diff options
Diffstat (limited to 'arch/m68k/kernel/head.S')
-rw-r--r-- | arch/m68k/kernel/head.S | 3855 |
1 files changed, 2984 insertions, 871 deletions
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index e98f39fa8..482c15f50 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -7,9 +7,12 @@ ** ** 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 @@ -18,6 +21,8 @@ ** 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 ** ** 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 @@ -34,69 +39,275 @@ * 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. - * Note that the kernel is located at virtual address 0x1000 == _start - * Enable cache memories - * Jump to kernel startup - * - * Register d6 contains the CPU flags and d4 the machine type - * from the boot_info information for most of this file. - * The upper word of d6 contains a bit for '040 or '060, since these two - * are quite similar for initial mm setup. Another bit in d6 allows - * distinction of the '060. The lower word of d6 contains the cache mode - * that should be applied to pages containing descriptors. This mode is - * non-cached/non-serialized for the '040 and cacheable/write-through for - * the '060. - * - * General register usage: - * a6 - start of unused memory - * new pages can be allocated from here - * a5 - mmu root table - * a4 - mmu pointer table - * a3 - mmu page tables - * a2 - points to the page table entry for a6 - * cache status can be changed (used for '0[46]0) - * you must increase a2 if alloc a new page - * d7 - used for debug output and some macros - * d6 - cpu type and cache mode - * d5 - physical start address of kernel - * d4 - machine type + * . 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/pgtable.h> +#include "m68k_defs.h" -.globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt) -.globl SYMBOL_NAME(availmem) -.globl SYMBOL_NAME(m68k_pgtable_cachemode) -.globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir) +#ifdef CONFIG_MAC -#if defined(CONFIG_MVME16x) -.globl SYMBOL_NAME(mvme_bdid_ptr) -#endif +#include <asm/machw.h> /* - * Added m68k_supervisor_cachemode for 68060 boards where some drivers - * need writethrough caching for supervisor accesses. Drivers known to - * be effected are 53c7xx.c and apricot.c (when used on VME boards). - * Richard Hirst. + * Macintosh console support */ -#ifdef CONFIG_060_WRITETHROUGH +#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) -#endif -D6B_0460 = 16 /* indicates 680[46]0 in d6 */ -D6B_060 = 17 /* indicates 68060 in d6 */ -D6F_040 = 1<<D6B_0460 -D6F_060 = (1<<D6B_0460)+(1<<D6B_060) +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 = 0x8000 @@ -144,6 +355,7 @@ CC3_ENABLE_I = 0x00000001 /* enable instruction cache (68030) */ /* Miscellaneous definitions */ PAGESIZE = 4096 +PAGESHIFT = 12 ROOT_TABLE_SIZE = 128 PTR_TABLE_SIZE = 128 @@ -152,32 +364,182 @@ ROOT_INDEX_SHIFT = 25 PTR_INDEX_SHIFT = 18 PAGE_INDEX_SHIFT = 12 -TABLENR_4MB = 16 /* # of page tables needed to page 4 MB */ -TABLENR_16MB = 64 /* same for 16 MB */ +#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 -#define putc(ch) moveq &ch,%d7; jbsr Lserial_putc -#define putr() putc(13); putc(10) -#define putn(nr) movel nr,%d7; jbsr Lserial_putnum +/* 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. + */ -#define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab -#define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab -#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab -#define is_not_bvme6000(lab) moveq &MACH_BVME6000,%d7; cmpl %d4,%d7; jne lab -#define is_not_hp300(lab) moveq &MACH_HP300,%d7 ; cmpl %d4,%d7; jne lab +/* 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=0 +L(\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 +.endm + +func_define mmu_map,4 +func_define mmu_map_tt,4 +func_define mmu_fixup_page_mmu_cache,1 +func_define mmu_temp_map,2 +func_define mmu_engage +func_define mmu_get_root_table_entry,1 +func_define mmu_get_ptr_table_entry,2 +func_define mmu_get_page_table_entry,2 +func_define mmu_print +func_define get_new_page +#ifdef CONFIG_HP300 +func_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 +.endm + +func_define serial_putc,1 +func_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 +.endm + +func_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_040_or_060(lab) btst &D6B_0460,%d6; jne lab -#define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab -#define is_060(lab) btst &D6B_060,%d6; jne lab -#define is_not_060(lab) btst &D6B_060,%d6; jeq lab + +#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_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_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab + +#define is_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jne lab +#define is_not_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jeq lab +#define is_040(lab) btst &CPUTYPE_040,%pc@(L(cputype)+3); jne lab +#define is_060(lab) btst &CPUTYPE_060,%pc@(L(cputype)+3); jne lab +#define is_not_060(lab) btst &CPUTYPE_060,%pc@(L(cputype)+3); jeq lab +#define is_020(lab) btst &CPUTYPE_020,%pc@(L(cputype)+3); jne lab +#define is_not_020(lab) btst &CPUTYPE_020,%pc@(L(cputype)+3); jeq lab /* On the HP300 we use the on-board LEDs for debug output before the console is running. Writing a 1 bit turns the corresponding LED _off_ - on the 340 bit 7 is towards the back panel of the machine. */ +.macro leds mask #ifdef CONFIG_HP300 -#define leds(x) is_not_hp300(42f) ; moveb #(x),%d7 ; jbsr Lset_leds; 42: -#else -#define leds(x) + is_not_hp300(.Lled\@) + pea \mask + func_call set_leds + addql #4,%sp +.Lled\@: #endif +.endm .text ENTRY(_stext) @@ -192,81 +554,193 @@ ENTRY(_stext) .long MACH_ATARI, ATARI_BOOTI_VERSION .long MACH_MVME16x, MVME16x_BOOTI_VERSION .long MACH_BVME6000, BVME6000_BOOTI_VERSION + .long MACH_MAC, MAC_BOOTI_VERSION .long 0 -1: jra SYMBOL_NAME(_start) +1: jra SYMBOL_NAME(__start) -.equ SYMBOL_NAME(kernel_pmd_table),SYMBOL_NAME(_stext) -.equ SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(kernel_pmd_table) -.equ SYMBOL_NAME(swapper_pg_dir),SYMBOL_NAME(kernel_pg_dir)+(ROOT_TABLE_SIZE<<2) -.equ Lavail_pmd_table,SYMBOL_NAME(swapper_pg_dir)+(ROOT_TABLE_SIZE<<2) +.equ SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(_stext) .equ .,SYMBOL_NAME(_stext)+PAGESIZE ENTRY(_start) + jra SYMBOL_NAME(__start) +__INIT +ENTRY(__start) /* * Setup initial stack pointer */ - lea %pc@(SYMBOL_NAME(_stext):w),%sp + lea %pc@(SYMBOL_NAME(_stext)),%sp /* * Record the CPU and machine type. */ - movew #BI_MACHTYPE,%d0 - jbsr Lget_bi_record - movel %a0@,%d4 - lea %pc@(SYMBOL_NAME(m68k_machtype)),%a0 - movel %d4,%a0@ - movew #BI_FPUTYPE,%d0 - jbsr Lget_bi_record - movel %a0@,%d0 - lea %pc@(SYMBOL_NAME(m68k_fputype)),%a0 - movel %d0,%a0@ - movew #BI_MMUTYPE,%d0 - jbsr Lget_bi_record - movel %a0@,%d0 - lea %pc@(SYMBOL_NAME(m68k_mmutype)),%a0 - movel %d0,%a0@ - movew #BI_CPUTYPE,%d0 - jbsr Lget_bi_record + get_bi_record BI_MACHTYPE + lea %pc@(SYMBOL_NAME(m68k_machtype)),%a1 + movel %a0@,%a1@ + + get_bi_record BI_FPUTYPE + lea %pc@(SYMBOL_NAME(m68k_fputype)),%a1 + movel %a0@,%a1@ + + get_bi_record BI_MMUTYPE + lea %pc@(SYMBOL_NAME(m68k_mmutype)),%a1 + movel %a0@,%a1@ + + get_bi_record BI_CPUTYPE + lea %pc@(SYMBOL_NAME(m68k_cputype)),%a1 + movel %a0@,%a1@ + +#ifdef CONFIG_MAC +/* + * For Macintosh, we need to determine the display parameters early (at least + * while debugging it). + */ + + is_not_mac(L(test_notmac)) + + get_bi_record BI_MAC_VADDR + lea %pc@(L(mac_videobase)),%a1 + movel %a0@,%a1@ + + get_bi_record BI_MAC_VDEPTH + lea %pc@(L(mac_videodepth)),%a1 + movel %a0@,%a1@ + + get_bi_record BI_MAC_VDIM + lea %pc@(L(mac_dimensions)),%a1 + movel %a0@,%a1@ + + get_bi_record BI_MAC_VROW + lea %pc@(L(mac_rowbytes)),%a1 + movel %a0@,%a1@ + +#ifdef MAC_SERIAL_DEBUG + get_bi_record BI_MAC_SCCBASE + lea %pc@(L(mac_sccbase)),%a1 + movel %a0@,%a1@ +#endif /* MAC_SERIAL_DEBUG */ + +#if 0 + /* + * Clear the screen + */ + lea %pc@(L(mac_videobase)),%a0 + movel %a0@,%a1 + lea %pc@(L(mac_dimensions)),%a0 + movel %a0@,%d1 + swap %d1 /* #rows is high bytes */ + andl #0xFFFF,%d1 /* rows */ + subl #10,%d1 + lea %pc@(L(mac_rowbytes)),%a0 +loopy2: movel %a0@,%d0 - lea %pc@(SYMBOL_NAME(m68k_cputype)),%a0 - movel %d0,%a0@ + subql #1,%d0 +loopx2: + moveb #0x55, %a1@+ + dbra %d0,loopx2 + dbra %d1,loopy2 +#endif + +L(test_notmac): +#endif /* CONFIG_MAC */ + +/* + * There are ultimately two pieces of information we want for all kinds of + * processors CpuType and CacheBits. The CPUTYPE was passed in from booter + * and is converted here from a booter type definition to a separate bit + * number which allows for the standard is_0x0 macro tests. + */ + movel %pc@(SYMBOL_NAME(m68k_cputype)),%d0 + /* + * Assume it's an 030 + */ + clrl %d1 + + /* + * Test the BootInfo cputype for 060 + */ btst #CPUB_68060,%d0 jeq 1f - /* '060: d6 := BIT0460|BIT060, cache mode 0x60 (no-cache/non-ser) */ - movel #D6F_060+_PAGE_CACHE040W,%d6 - jra 2f -1: btst #CPUB_68040,%d0 - jeq 1f - /* '040: d6 := BIT0460, cache mode 0x00 (write-through) */ - movel #D6F_040+_PAGE_CACHE040W,%d6 - jra 2f -1: /* '020 or '030: d6 := no CPU bit, cache mode unused */ - moveq #0,%d6 + bset #CPUTYPE_060,%d1 + bset #CPUTYPE_0460,%d1 + jra 3f +1: + /* + * Test the BootInfo cputype for 040 + */ + btst #CPUB_68040,%d0 + jeq 2f + bset #CPUTYPE_040,%d1 + bset #CPUTYPE_0460,%d1 + jra 3f +2: + /* + * Test the BootInfo cputype for 020 + */ + btst #CPUB_68020,%d0 + jeq 3f + bset #CPUTYPE_020,%d1 + jra 3f +3: + /* + * Record the cpu type + */ + lea %pc@(L(cputype)),%a0 + movel %d1,%a0@ -2: lea %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0 - moveq #0,%d0 - movew %d6,%d0 - movel %d0,%a0@ /* save cache mode for page tables */ + /* + * NOTE: + * + * Now the macros are valid: + * is_040_or_060 + * is_not_040_or_060 + * is_040 + * is_060 + * is_not_060 + */ + + /* + * Determine the cache mode for pages holding MMU tables + * and for supervisor mode, unused for '020 and '030 + */ + clrl %d0 + clrl %d1 + is_not_040_or_060(L(save_cachetype)) + + /* + * '040 or '060 + * d1 := cacheable write-through + * NOTE: The 68040 manual strongly recommends non-cached for MMU tables, + * but we have been using write-through since at least 2.0.29 so I + * guess it is OK. + */ +#ifdef CONFIG_060_WRITETHROUGH /* * If this is a 68060 board using drivers with cache coherency * problems, then supervisor memory accesses need to be write-through - * also; otherwise, we want copyback. + * also; otherwise, we want copyback. */ -#if defined(CONFIG_060_WRITETHROUGH) - is_not_060(Lset_norm) - jra 1f -Lset_norm: - move.w #_PAGE_CACHE040,%d0 + is_not_060(1f) + movel #_PAGE_CACHE040W,%d0 + jra L(save_cachetype) +#endif /* CONFIG_060_WRITETHROUGH */ 1: - lea %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0 + movew #_PAGE_CACHE040,%d0 + + movel #_PAGE_CACHE040W,%d1 + +L(save_cachetype): + /* Save cache mode for supervisor mode and page tables + */ + lea %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0 movel %d0,%a0@ -#endif + lea %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0 + movel %d1,%a0@ /* * raise interrupt level @@ -293,288 +767,120 @@ Lset_norm: */ #ifdef CONFIG_ATARI - is_not_atari(Lnotypetest) + is_not_atari(L(notypetest)) /* get special machine type (Medusa/Hades/AB40) */ moveq #0,%d3 /* default if tag doesn't exist */ - movew #BI_ATARI_MCH_TYPE,%d0 - jbsr Lget_bi_record + get_bi_record BI_ATARI_MCH_TYPE tstl %d0 jbmi 1f movel %a0@,%d3 -1: - /* %d3 is not clobbered until Atari page tables are set up, - * where it is used again. */ - + lea %pc@(SYMBOL_NAME(atari_mch_type)),%a0 + movel %d3,%a0@ +1: /* On the Hades, the iobase must be set up before opening the * serial port. There are no I/O regs at 0x00ffxxxx at all. */ moveq #0,%d0 cmpl #ATARI_MACH_HADES,%d3 jbne 1f movel #0xff000000,%d0 /* Hades I/O base addr: 0xff000000 */ -1: lea %pc@(Liobase),%a0 +1: lea %pc@(L(iobase)),%a0 movel %d0,%a0@ -Lnotypetest: + +L(notypetest): #endif /* * Initialize serial port */ - - jbsr Lserial_init - - putr() - putc('A') + jbsr L(serial_init) /* - * Get address at end of bootinfo and mask off at a page boundary. + * Initialize console */ - moveq #0,%d0 - jbsr Lget_bi_record - addw #PAGESIZE-1,%a0 - movel %a0,%d0 - andl #-PAGESIZE,%d0 - movel %d0,%a6 - - putc('B') +#ifdef CONFIG_MAC + is_not_mac(L(nocon)) +#ifdef CONSOLE + jbsr L(console_init) +#ifdef CONSOLE_PENGUIN + jbsr L(console_put_penguin) +#endif /* CONSOLE_PENGUIN */ + jbsr L(console_put_stats) +#endif /* CONSOLE */ +L(nocon): +#endif /* CONFIG_MAC */ + + + putc '\n' + putc 'A' + dputn %pc@(L(cputype)) + dputn %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)) + dputn %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)) + dputc '\n' /* * Save physical start address of kernel */ - lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0 - movel %a0,%d5 - -/* - * initialize the kernel root table. - */ - lea %pc@(SYMBOL_NAME(kernel_pg_dir):w),%a5 - movel %a5,%a0 - moveq #ROOT_TABLE_SIZE-1,%d1 -1: clrl %a0@+ - dbra %d1,1b - - /* - * Initialize root table descriptor pointing to the kernel pointer - * table. - */ - lea %pc@(Lavail_pmd_table:w),%a4 - moveq #_PAGE_TABLE,%d0 - addl %a4,%d0 - movel %d0,%a5@ - - putc('C') - -/* - * Initialize the pointer tables referred to above. They either point - * to page tables in the case of the 680[46]0 or contain early - * termination page descriptors in the case of the 68851 or 68030. - * - * Each pointer table entry points to a 64 entry page table. 16 of these - * page tables are grouped to form a single 1024 entry page table which - * fits in a single 4096 byte page. - * - * Some register usages: - * a0 -> pointer table descriptor address - * a1 -> pointer table descriptor - * d1 -> counter - * d2 -> pointer table descriptor increment (varies according to CPU) - */ - - /* clear the kernel pointer table */ - movel %a4,%a0 - moveq #PTR_TABLE_SIZE-1,%d1 -1: clrl %a0@+ - dbra %d1,1b + lea %pc@(L(phys_kernel_start)),%a0 + lea %pc@(SYMBOL_NAME(_stext)),%a1 + subl #SYMBOL_NAME(_stext),%a1 + movel %a1,%a0@ - movel %a4,%a0 - moveq #15,%d1 + putc 'B' - /* - * base value of pointer table descriptor is either - * the address of the first page table (680[46]0) - * or the base address of physical memory (68030). - */ - is_040_or_060(1f) - - /* 680[23]0 */ - movel %d5,%a1 /* base address */ - addql #_PAGE_PRESENT,%a1 /* descriptor type */ - movel #PAGE_TABLE_SIZE*PAGESIZE,%d2 /* increment */ - jra 2f - -1: /* 680[46]0 */ - movel %a6,%a3 /* base address */ - addw #PAGESIZE,%a6 /* allocate page for 16 page tables */ - lea %pc@(SYMBOL_NAME(kpt)),%a1 - movel %a3,%a1@ /* save address of page table */ - movel %a3,%a1 - addw #_PAGE_TABLE+_PAGE_ACCESSED,%a1 /* descriptor type */ - movel #PAGE_TABLE_SIZE<<2,%d2 /* increment */ - -2: movel %a1,%a0@+ - addl %d2,%a1 - dbra %d1,2b - - putc('D') + leds 0x4 /* - * If we are running on a 680[46]0, we have a kernel page table and - * must initialize it. Make the entries point to the first - * 4M of physical memory (the memory we are residing in). - * Set the cache mode bits to Cacheable, Copyback. Set the Global bits - * in the descriptors also. + * mmu_init + * + * This block of code does what's necessary to map in the various kinds + * of machines for execution of Linux. + * First map the first 4 MB of kernel code & data */ - is_not_040_or_060(Lnot040) - putc('F') - - movel %a3,%a0 - movel %d5,%a1 -#if defined(CONFIG_060_WRITETHROUGH) - addw #_PAGE_GLOBAL040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1 - addl m68k_supervisor_cachemode,%a1 -#else - addw #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1 -#endif - movew #(PAGE_TABLE_SIZE*TABLENR_4MB)-1,%d1 - movel #PAGESIZE,%d2 -1: movel %a1,%a0@+ - addl %d2,%a1 - dbra %d1,1b - - /* - * on the 68040, pages used to hold mmu tables should - * be initialized as noncachable; the '060 allows write-through. - * Do this for the root table page (which also contains - * all pointer tables utilized thus far) and the - * kernel page table. - */ - movel %a5,%d0 - subl %d5,%d0 - moveq #PAGE_INDEX_SHIFT,%d2 - lsrl %d2,%d0 - lea %a3@(%d0:l:4),%a2 - movel %a2@,%d1 - andw #_CACHEMASK040,%d1 - orw %d6,%d1 - movel %d1,%a2@ + mmu_map #0,%pc@(L(phys_kernel_start)),#4*1024*1024,\ + %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)) - movel %a3,%d0 - subl %d5,%d0 - lsrl %d2,%d0 - lea %a3@(%d0:l:4),%a2 - movel %a2@,%d1 - andw #_CACHEMASK040,%d1 - orw %d6,%d1 - movel %d1,%a2@+ - /* - * %a2 points now to the page table entry for available pages at %a6, - * hence caching modes for new pages can easily set unless increasing - * of %a2 are forgotten. - */ -Lnot040: + putc 'C' - leds(0x4) - -/* - * Do any machine specific page table initializations. - */ #ifdef CONFIG_AMIGA - is_not_amiga(Lnotami) +L(mmu_init_amiga): + + is_not_amiga(L(mmu_init_not_amiga)) /* - * Setup a mapping of the first 16M of physical address space at virtual - * address 0x80000000, using early termination page descriptors for the - * 68030, and proper page tables for the 680[46]0. Set this area as - * non-cacheable. + * mmu_init_amiga */ - putc('H') + putc 'D' - is_040_or_060(Lspami68040) + is_not_040_or_060(1f) /* - * for the 68030, just setup a translation to map in the first - * 32M of physical address space at virtual address 0x80000000 - * using an early termination page descriptor. + * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000 */ + mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S - putc('I') - - movel #_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0 - movel %d0,%a5@(0x40<<2) - - jra Lmapphys - -Lspami68040: - - /* - * for the 680[46]0, use another pointer table, and allocate 4 more - * page tables. Initialize the pointer table to point to the - * page tables. Then initialize the page tables to point to - * the first 16M of memory, with no caching (noncachable/serialized). - */ - - /* clear the amiga pointer table */ - lea %a4@(PTR_TABLE_SIZE<<2),%a4 - moveq #PTR_TABLE_SIZE-1,%d1 -1: clrl %a0@+ - dbra %d1,1b - - /* allocate 4 pages for 64 page tables */ - movel %a6,%a3 - addw #4*PAGESIZE,%a6 - - /* initialize the pointer table */ - movel %a4,%a0 - movel %a3,%a1 - addw #_PAGE_TABLE+_PAGE_ACCESSED,%a1 /* base descriptor */ - movel #PAGE_TABLE_SIZE<<2,%d2 /* increment */ - moveq #TABLENR_16MB-1,%d1 - -1: movel %a1,%a0@+ - addl %d2,%a1 - dbra %d1,1b - - /* ensure that the root table points to the pointer table */ - movel %a4,%a0 - addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0 - movel %a0,%a5@(0x40<<2) + jbra L(mmu_init_done) +1: /* - * initialize the page tables - * descriptor bits include noncachable/serialized and global bits. + * 030: Map the 32Meg range physical 0x0 upto logical 0x8000.0000 */ - movel %a3,%a0 - movew #_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT+_PAGE_ACCESSED,%a1 - movel #PAGESIZE,%d2 - movew #(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1 + mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030 -1: movel %a1,%a0@+ - addl %d2,%a1 - dbra %d1,1b + jbra L(mmu_init_done) - /* - * Finally, since we just allocated 4 page tables, make sure that - * the virtual mapping of the 4 page tables indicates - * noncachable/serialized. - */ - moveq #3,%d0 -1: movel %a2@,%d1 /* a2 already points to root table offset */ - andw #_CACHEMASK040,%d1 - orw %d6,%d1 - movel %d1,%a2@+ - dbra %d0,1b - - jra Lmapphys - -Lnotami: +L(mmu_init_not_amiga): #endif #ifdef CONFIG_ATARI - is_not_atari(Lnotatari) - move.w #PAGESIZE,%sp +L(mmu_init_atari): + + is_not_atari(L(mmu_init_not_atari)) + + putc 'E' /* On the Atari, we map the I/O region (phys. 0x00ffxxxx) by mapping the last 16 MB of virtual address space to the first 16 MB (i.e. @@ -591,103 +897,57 @@ Lnotami: /* I/O base addr for non-Medusa, non-Hades: 0x00000000 */ moveq #0,%d0 + movel %pc@(SYMBOL_NAME(atari_mch_type)),%d3 cmpl #ATARI_MACH_MEDUSA,%d3 jbeq 2f cmpl #ATARI_MACH_HADES,%d3 jbne 1f 2: movel #0xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */ 1: movel %d0,%d3 - - /* Let the root table point to the new pointer table */ - lea %a4@(PTR_TABLE_SIZE<<2),%a4 - movel %a4,%a0 - addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0 - movel %a0,%a5@(0x7f<<2) /* 0xFE000000 - 0xFFFFFFFF */ - - /* clear lower half of the pointer table (0xfexxxxxx) */ - movel %a4,%a0 - movel #(PTR_TABLE_SIZE/2)-1,%d2 -1: clrl %a0@+ - dbra %d2,1b - - is_040_or_060(Lspata68040) - -/* Mapping of the last 16M of virtual address space to the first 16M - for efficient addressing of hardware registers */ - movel #PAGE_TABLE_SIZE*PAGESIZE,%d1 - movel #(PTR_TABLE_SIZE/2)-1,%d2 - movel %d3,%d0 - orw #_PAGE_PRESENT+_PAGE_ACCESSED,%d0 -1: movel %d0,%a0@+ - addl %d1,%d0 - dbra %d2,1b - moveq #_PAGE_NOCACHE030,%d0 /* make non-cachable */ - addl %d0,%a4@(0x7f<<2) /* 0xFFFC0000-0xFFFFFFFF (I/O space) */ -/* GK: 0xFFF00000-0xFFF3FFFF (IDE-bus) has to be non-cachable too */ - addl %d0,%a4@(0x7c<<2) - - jra Lmapphys - -Lspata68040: - /* allocate 4 page tables */ - movel %a6,%a3 - addw #4*PAGESIZE,%a6 - - /* Initialize the upper half of the pointer table (a0 is still valid) */ - movel %a3,%a1 - addw #_PAGE_TABLE+_PAGE_ACCESSED,%a1 - movel #PAGE_TABLE_SIZE<<2,%d2 - moveq #TABLENR_16MB-1,%d1 -1: movel %a1,%a0@+ - addl %d2,%a1 - dbra %d1,1b - - /* Initialize the page tables as noncacheable/serialized! */ - movel %a3,%a0 - movel %d3,%a1 - addw #_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT+_PAGE_ACCESSED,%a1 - movel #PAGESIZE,%d2 - movew #(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1 -1: movel %a1,%a0@+ - addl %d2,%a1 - dbra %d1,1b - /* - * Finally, since we just allocated 4 page tables, make sure that - * the virtual mapping of the 4 page tables indicates - * noncachable or write-through. - */ - moveq #3,%d0 -1: movel %a2@,%d1 /* a2 already points to root table offset */ - andw #_CACHEMASK040,%d1 - orw %d6,%d1 - movel %d1,%a2@+ - dbra %d0,1b + is_040_or_060(L(spata68040)) + + /* Map everything non-cacheable, though not all parts really + * need to disable caches (crucial only for 0xff8000..0xffffff + * (standard I/O) and 0xf00000..0xf3ffff (IDE)). The remainder + * isn't really used, except for sometimes peeking into the + * ROMs (mirror at phys. 0x0), so caching isn't necessary for + * this. */ + mmu_map #0xff000000,%d3,#0x01000000,#_PAGE_NOCACHE030 + + jbra L(mmu_init_done) + +L(spata68040): + + mmu_map #0xff000000,%d3,#0x01000000,#_PAGE_NOCACHE_S + + jbra L(mmu_init_done) -Lnotatari: +L(mmu_init_not_atari): #endif #ifdef CONFIG_HP300 - is_not_hp300(Lnothp300) + is_not_hp300(L(nothp300)) /* On the HP300, we map the ROM, INTIO and DIO regions (phys. 0x00xxxxxx) - by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early - termination page descriptor. The ROM mapping is needed because the LEDs + by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early + termination page descriptor. The ROM mapping is needed because the LEDs are mapped there too. */ - movel #_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0 - movel %d0,%a5@(0x78<<2) + mmu_map #0xf0000000,#0,#0x02000000,#_PAGE_NOCACHE030 + +L(nothp300): -Lnothp300: - #endif -#if defined(CONFIG_MVME16x) - is_not_mvme16x(Lnot16x) +#ifdef CONFIG_MVME16x + + is_not_mvme16x(L(not16x)) /* Get pointer to board ID data */ movel %d2,%sp@- - .long 0x4e4f0070 /* trap 0x70 - .BRD_ID */ + trap #15 + .word 0x70 /* trap 0x70 - .BRD_ID */ movel %sp@+,%d2 lea %pc@(SYMBOL_NAME(mvme_bdid_ptr)),%a0 movel %d2,%a0@ @@ -696,392 +956,330 @@ Lnothp300: * On MVME16x we have already created kernel page tables for * 4MB of RAM at address 0, so now need to do a transparent * mapping of the top of memory space. Make it 0.5GByte for now. + * Supervisor only access, so transparent mapping doesn't + * clash with User code virtual address space. + * this covers IO devices, PROM and SRAM. The PROM and SRAM + * mapping is needed to allow 167Bug to run. + * IO is in the range 0xfff00000 to 0xfffeffff. + * PROM is 0xff800000->0xffbfffff and SRAM is + * 0xffe00000->0xffe1ffff. */ - movel #0xe01f0000,%d2 /* logical address base */ - orw #0xa040,%d2 /* add in magic bits */ - .long 0x4e7b2005 /* movec d2,ittr1 */ - .long 0x4e7b2007 /* movec d2,dttr1 */ + mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S -Lnot16x: -#endif + jbra L(mmu_init_done) + +L(not16x): +#endif /* CONFIG_MVME162 | CONFIG_MVME167 */ + +#ifdef CONFIG_BVME6000 -#if defined(CONFIG_BVME6000) - is_not_bvme6000(Lnotbvm) + is_not_bvme6000(L(not6000)) /* * On BVME6000 we have already created kernel page tables for * 4MB of RAM at address 0, so now need to do a transparent - * mapping of the top of memory space. Make it 0.5GByte for now. + * mapping of the top of memory space. Make it 0.5GByte for now, + * so we can access on-board i/o areas. + * Supervisor only access, so transparent mapping doesn't + * clash with User code virtual address space. */ - movel #0xe01f0000,%d2 /* logical address base */ - orw #0xa040,%d2 /* add in magic bits */ - .long 0x4e7b2005 /* movec d2,ittr1 */ - .long 0x4e7b2007 /* movec d2,dttr1 */ - .long 0x4e7b2004 /* movec d2,ittr0 */ - .long 0x4e7b2006 /* movec d2,dttr0 */ + mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S -Lnotbvm: -#endif + jbra L(mmu_init_done) + +L(not6000): +#endif /* CONFIG_BVME6000 */ /* - * Setup a transparent mapping of the physical memory we are executing in. + * mmu_init_mac + * + * The Macintosh mappings are less clear. * - * Only do this if the physical memory is not in the first 16M Meg, or not on - * an Amiga since the first 16M is already identity mapped on the Amiga. + * Even as of this writing, it is unclear how the + * Macintosh mappings will be done. However, as + * the first author of this code I'm proposing the + * following model: + * + * Map the kernel (that's already done), + * Map the I/O (on most machines that's the + * 0x5000.0000 ... 0x5200.0000 range, + * Map the video frame buffer using as few pages + * as absolutely (this requirement mostly stems from + * the fact that when the frame buffer is at + * 0x0000.0000 then we know there is valid RAM just + * above the screen that we don't want to waste!). + * + * By the way, if the frame buffer is at 0x0000.0000 + * then the Macintosh is known as an RBV based Mac. + * + * By the way 2, the code currently maps in a bunch of + * regions. But I'd like to cut that out. (And move most + * of the mappings up into the kernel proper ... or only + * map what's necessary.) */ -Lmapphys: - putc('J') - leds(0x8) -#ifdef CONFIG_AMIGA - is_not_amiga(Lmapphysnotamiga) +#ifdef CONFIG_MAC -/* - * The virtual address of the start of the kernel is 0x1000. We transparently - * translate the memory where we running in and can enable then the MMU. Hence - * we have now two locations of the kernel in memory and can jump to the final - * place. Except if the physical location is in the first 16MB, translation - * will overlap later virtual location, but as we already mapped the first - * 16MB to 0x80000000, we can jump there after translation and MMU is enabled - * and then we can switch off translation and go to the final place. - * On 020/030 we must emulate transparant translation, since 020 doesn't know - * it, but due to early termination pointer this is easy to do. - * When MMU is enabled, stack pointer and Lcustom will become again valid and - * stack points to the unused first page. - */ +L(mmu_init_mac): -/* - * Setup Supervisor Root Pointer register to point to page directory, - * setup translation register contents and enable translation. - */ - putc('K') + is_not_mac(L(mmu_init_not_mac)) - movew #PAGESIZE,%sp + putc 'F' - /* fixup the Amiga custom register location before printing */ - lea %pc@(Lcustom),%a0 - movel #0x80000000,%a0@ + lea %pc@(L(mac_videobase)),%a0 + lea %pc@(L(console_video_virtual)),%a1 + movel %a0@,%a1@ - is_040_or_060(Lamimmu68040) + is_not_040_or_060(1f) - moveq #ROOT_INDEX_SHIFT,%d2 - movel %d5,%d0 - lsrl %d2,%d0 - movel %d0,%d1 - lsll %d2,%d1 - orw #_PAGE_PRESENT+_PAGE_ACCESSED,%d1 - lsll #2,%d0 - movel %a5@(%d0:w),%d2 - movel %d1,%a5@(%d0:w) - lea %pc@(Lmmu),%a3 - /* no limit, 4byte descriptors */ - movel #0x80000002,%a3@ - movel %a5,%a3@(4) - pmove %a3@,%srp - pmove %a3@,%crp - pflusha + moveq #_PAGE_NOCACHE_S,%d3 + jbra 2f +1: + moveq #_PAGE_NOCACHE030,%d3 +2: /* - * enable,super root enable,4096 byte pages,7 bit root index, - * 7 bit pointer index, 6 bit page table index. + * Mac Note: screen address of logical 0xF000.0000 -> <screen physical> + * we simply map the 4MB that contains the videomem */ - movel #0x82c07760,%a3@ - pmove %a3@,%tc /* enable the MMU */ - tstl %d0 - jne 1f - jmp %pc@(2f+0x80000000) -1: jmp 2f:w -2: movel %d2,%a5@(%d0:w) - pflusha - jmp LdoneMMUenable:w -Lamimmu68040: + movel #VIDEOMEMMASK,%d0 + andl L(mac_videobase),%d0 - .chip 68040 - lea 2f:w,%a0 - movel %d5,%d0 - andl #0xff000000,%d0 - jne 1f - lea %pc@(2f+0x80000000),%a0 -1: orw #TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0 - movec %d0,%itt0 - movec %a5,%urp - movec %a5,%srp - pflusha - movel #TC_ENABLE+TC_PAGE4K,%d0 - /* - * this value is also ok for the 68060, we don`t use the cache - * mode/protection defaults - */ - movec %d0,%tc /* enable the MMU */ - jmp %a0@ -2: moveq #0,%d0 - movec %d0,%itt0 - jmp LdoneMMUenable:w - .chip 68k + mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3 + mmu_map_eq #0x40800000,#0x02000000,%d3 /* rom ? */ + mmu_map_eq #0x50000000,#0x02000000,%d3 + mmu_map_eq #0x60000000,#0x00400000,%d3 + mmu_map_eq #0x9c000000,#0x00400000,%d3 + mmu_map_tt 1,#0xf8000000,#0x08000000,%d3 -Lmapphysnotamiga: + jbra L(mmu_init_done) + +L(mmu_init_not_mac): #endif -#ifdef CONFIG_ATARI - is_not_atari(Lmapphysnotatari) +L(mmu_init_done): + + putc 'G' + leds 0x8 /* - * If the kernel physical address is different from its virtual address, we - * will temporarily set up an identity mapping of the 16MB chunk with - * transparent translation where the kernel is executing. + * mmu_fixup + * + * On the 040 class machines, all pages that are used for the + * mmu have to be fixed up. According to Motorola, pages holding mmu + * tables should be non-cacheable on a '040 and write-through on a + * '060. But analysis of the reasons for this, and practical + * experience, showed that write-through also works on a '040. + * + * Allocated memory so far goes from kernel_end to memory_start that + * is used for all kind of tables, for that the cache attributes + * are now fixed. */ - putc('L') - - /* fixup the Atari iobase register location before printing */ - lea %pc@(Liobase),%a0 - movel #0xff000000,%a0@ +L(mmu_fixup): - is_040_or_060(Latarimmu68040) + is_not_040_or_060(L(mmu_fixup_done)) - .chip 68030 - lea %pc@(Lmmu),%a3 - movel %d5,%d0 - jne 1f - lea LdoneMMUenable:w,%a0 - jra 3f -1: lea 4f:w,%a0 - andl #0xff000000,%d0 /* logical address base */ - jeq 2f - orw #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0 - movel %d0,%a3@ - pmove %a3@,%tt0 - jra 3f - /* tt0 doesn't work if physical and virtual address of kernel is in - * the same 16M area (Falcon with Magnum/FX, kernel in alternate ram) - * Transparent translation through kernel pointer table - * Requires that this code until after MMU enabling lies in - * the 256K page around %d5 - */ -2: movel %a5@,%d1 - andw #0xfff0,%d1 - movel %d1,%a1 - movel %d5,%d1 - moveq #PTR_INDEX_SHIFT,%d0 - lsrl %d0,%d1 - lea %a1@(%d1:l:4),%a1 - movel %d5,%d1 - orw #_PAGE_PRESENT+_PAGE_ACCESSED,%d1 - movel %a1@,%d2 - movel %d1,%a1@ - lea 5f:w,%a0 - /* no limit, 4byte descriptors */ -3: movel #0x80000002,%a3@ - movel %a5,%a3@(4) - pmove %a3@,%srp - pmove %a3@,%crp - pflusha - /* - * enable,super root enable,4096 byte pages,7 bit root index, - * 7 bit pointer index, 6 bit page table index. - */ - movel #0x82c07760,%a3@ - pmove %a3@,%tc /* enable the MMU */ - jmp %a0@ -4: clrl %a3@ - pmove %a3@,%tt0 - jra LdoneMMUenable -5: movel %d2,%a1@ - jra LdoneMMUenable - .chip 68k - -Latarimmu68040: - .chip 68040 - movel %d5,%d0 - jne 1f - lea LdoneMMUenable:w,%a0 - jra 2f -1: lea 3f:w,%a0 - andl #0xff000000,%d0 /* logical address base */ - orw #TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0 - movec %d0,%itt0 -2: nop - pflusha - movec %a5,%srp - movec %a5,%urp - movel #TC_ENABLE+TC_PAGE4K,%d0 - /* - * this value is also ok for the 68060, we don`t use the cache - * mode/protection defaults - */ - movec %d0,%tc /* enable the MMU */ - jmp %a0@ -3: moveq #0,%d0 - movec %d0,%itt0 - jra LdoneMMUenable - .chip 68k - -Lmapphysnotatari: +#ifdef MMU_NOCACHE_KERNEL + jbra L(mmu_fixup_done) #endif -#if defined(CONFIG_MVME16x) - is_not_mvme16x(Lmapphysnot16x) - /* - * save physaddr of phys mem in register a3 + /* first fix the page at the start of the kernel, that + * contains also kernel_pg_dir. */ - moveq #'L',%d7 - jbsr Lserial_putc - - .word 0xf4d8 /* CINVA I/D */ - .word 0xf518 /* pflusha */ - .long 0x4e7bd807 /* movec a5,srp */ - .long 0x4e7bd806 /* movec a5,urp */ - movel #(TC_ENABLE+TC_PAGE4K),%d0 - .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */ - jra LdoneMMUenable /* branch to continuation of startup */ + movel %pc@(L(phys_kernel_start)),%d0 + lea %pc@(SYMBOL_NAME(_stext)),%a0 + subl %d0,%a0 + mmu_fixup_page_mmu_cache %a0 + + movel %pc@(L(kernel_end)),%a0 + subl %d0,%a0 + movel %pc@(L(memory_start)),%a1 + subl %d0,%a1 + bra 2f +1: + mmu_fixup_page_mmu_cache %a0 + addw #PAGESIZE,%a0 +2: + cmpl %a0,%a1 + jgt 1b -Lmapphysnot16x: +L(mmu_fixup_done): +#ifdef MMU_PRINT + mmu_print #endif -#if defined(CONFIG_HP300) - is_not_hp300(Lmapphysnothp300) - /* - * Physical RAM is at 0xff000000. We want to map the kernel at 0x00000000. - * In order to avoid disaster when we enable the MMU we need to make a - * transparent mapping of the RAM we're executing out of as well. + * mmu_engage + * + * This chunk of code performs the gruesome task of engaging the MMU. + * The reason its gruesome is because when the MMU becomes engaged it + * maps logical addresses to physical addresses. The Program Counter + * register is then passed through the MMU before the next instruction + * is fetched (the instruction following the engage MMU instruction). + * This may mean one of two things: + * 1. The Program Counter falls within the logical address space of + * the kernel of which there are two sub-possibilities: + * A. The PC maps to the correct instruction (logical PC == physical + * code location), or + * B. The PC does not map through and the processor will read some + * data (or instruction) which is not the logically next instr. + * As you can imagine, A is good and B is bad. + * Alternatively, + * 2. The Program Counter does not map through the MMU. The processor + * will take a Bus Error. + * Clearly, 2 is bad. + * It doesn't take a wiz kid to figure you want 1.A. + * This code creates that possibility. + * There are two possible 1.A. states (we now ignore the other above states): + * A. The kernel is located at physical memory addressed the same as + * the logical memory for the kernel, i.e., 0x01000. + * B. The kernel is located some where else. e.g., 0x0400.0000 + * + * Under some conditions the Macintosh can look like A or B. + * [A friend and I once noted that Apple hardware engineers should be + * wacked twice each day: once when they show up at work (as in, Whack!, + * "This is for the screwy hardware we know you're going to design today."), + * and also at the end of the day (as in, Whack! "I don't know what + * you designed today, but I'm sure it wasn't good."). -- rst] + * + * This code works on the following premise: + * If the kernel start (%d5) is within the first 16 Meg of RAM, + * then create a mapping for the kernel at logical 0x8000.0000 to + * the physical location of the pc. And, create a transparent + * translation register for the first 16 Meg. Then, after the MMU + * is engaged, the PC can be moved up into the 0x8000.0000 range + * and then the transparent translation can be turned off and then + * the PC can jump to the correct logical location and it will be + * home (finally). This is essentially the code that the Amiga used + * to use. Now, it's generalized for all processors. Which means + * that a fresh (but temporary) mapping has to be created. The mapping + * is made in page 0 (an as of yet unused location -- except for the + * stack!). This temporary mapping will only require 1 pointer table + * and a single page table (it can map 256K). + * + * OK, alternatively, imagine that the Program Counter is not within + * the first 16 Meg. Then, just use Transparent Translation registers + * to do the right thing. + * + * Last, if _start is already at 0x01000, then there's nothing special + * to do (in other words, in a degenerate case of the first case above, + * do nothing). + * + * Let's do it. + * + * */ - /* - * save physaddr of phys mem in register a3 - */ - .chip 68030 - lea %pc@(Lmmu),%a3 - movel %d5,%d0 - andl #0xff000000,%d0 /* logical address base */ - orw #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0 - movel %d0,%a3@ - pmove %a3@,%tt0 - /* no limit, 4byte descriptors */ - movel #0x80000002,%a3@ - movel %a5,%a3@(4) - pmove %a3@,%srp - pmove %a3@,%crp - pflusha - /* - * enable,super root enable,4096 byte pages,7 bit root index, - * 7 bit pointer index, 6 bit page table index. - */ - movel #0x82c07760,%a3@ - pmove %a3@,%tc /* enable the MMU */ - jmp 1f -1: - .chip 68k + putc 'H' - /* - * Fix up the custom register to point to the new location of the LEDs. - */ - lea %pc@(Lcustom),%a1 - movel #0xf0000000,%a1@ + mmu_engage - /* - * Energise the FPU and caches. - */ - orl #0x64, 0xf05f400c - -Lmapphysnothp300: +#ifdef CONFIG_AMIGA + is_not_amiga(1f) + /* fixup the Amiga custom register location before printing */ + clrl L(custom) +1: +#endif + +#ifdef CONFIG_ATARI + is_not_atari(1f) + /* fixup the Atari iobase register location before printing */ + movel #0xff000000,L(iobase) +1: +#endif +#ifdef CONFIG_MAC + is_not_mac(1f) + movel #~VIDEOMEMMASK,%d0 + andl L(mac_videobase),%d0 + addl #VIDEOMEMBASE,%d0 + movel %d0,L(mac_videobase) +1: #endif -#if defined(CONFIG_BVME6000) - is_not_bvme6000(Lmapphysnotbvm) +#ifdef CONFIG_HP300 + is_not_hp300(1f) /* - * save physaddr of phys mem in register a3 + * Fix up the custom register to point to the new location of the LEDs. */ - moveq #'L',%d7 - jbsr Lserial_putc + movel #0xf0000000,L(custom) - .word 0xf4d8 /* CINVA I/D */ - .word 0xf518 /* pflusha */ - .long 0x4e7bd807 /* movec a5,srp */ - .long 0x4e7bd806 /* movec a5,urp */ - movel #(TC_ENABLE+TC_PAGE4K),%d0 /* - * this value is also ok for the 68060, we don`t use the cache - * mode/protection defaults + * Energise the FPU and caches. */ - .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */ - jra LdoneMMUenable /* branch to continuation of startup */ - -Lmapphysnotbvm: - + movel #0x60,0xf05f400c +1: #endif -LdoneMMUenable: - /* * Fixup the addresses for the kernel pointer table and availmem. * Convert them from physical addresses to virtual addresses. */ - putc('M') - leds(0x10) - - /* - * d5 contains physaddr of kernel start - */ - subl %d5,SYMBOL_NAME(kpt) + putc 'I' + leds 0x10 - /* - * do the same conversion on the first available memory + /* do the same conversion on the first available memory * address (in a6). */ - subl %d5,%a6 - movel %a6,SYMBOL_NAME(availmem) /* first available memory address */ - - putc('N') + movel L(memory_start),%d0 + movel %d0,SYMBOL_NAME(availmem) /* * Enable caches */ - is_040_or_060(Lcache680460) - movel #CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0 - movec %d0,%cacr - jra 1f + is_not_040_or_060(L(cache_not_680460)) -Lcache680460: +L(cache680460): .chip 68040 + nop cpusha %bc - .chip 68k + nop - is_060(Lcache68060) + is_060(L(cache68060)) movel #CC6_ENABLE_D+CC6_ENABLE_I,%d0 /* MMU stuff works in copyback mode now, so enable the cache */ movec %d0,%cacr - jra 1f + jra L(cache_done) -Lcache68060: - .chip 68060 +L(cache68060): movel #CC6_ENABLE_D+CC6_ENABLE_I+CC6_ENABLE_SB+CC6_PUSH_DPI+CC6_ENABLE_B+CC6_CLRA_B,%d0 /* MMU stuff works in copyback mode now, so enable the cache */ movec %d0,%cacr /* enable superscalar dispatch in PCR */ moveq #1,%d0 + .chip 68060 movec %d0,%pcr + + jbra L(cache_done) +L(cache_not_680460): +L(cache68030): + .chip 68030 + movel #CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0 + movec %d0,%cacr + + jra L(cache_done) .chip 68k -1: +L(cache_done): + + putc 'J' /* * Setup initial stack pointer - * We need to get current loaded up with our first task... */ lea SYMBOL_NAME(init_task_union),%a2 - lea 8192(%a2),%sp + lea 0x2000(%a2),%sp /* jump to the kernel start */ - putr() - leds(0x55) + putc '\n' + leds 0x55 - subl %a6,%a6 /* clear a6 for gdb */ + subl %a6,%a6 /* clear a6 for gdb */ jbsr SYMBOL_NAME(start_kernel) /* @@ -1090,33 +1288,1260 @@ Lcache68060: * Returns: d0: size (-1 if not found) * a0: data pointer (end-of-records if not found) */ -Lget_bi_record: +func_start get_bi_record,%d1 + + movel ARG1,%d0 lea %pc@(SYMBOL_NAME(_end)),%a0 -1: tstw %a0@(BIR_tag) +1: tstw %a0@(BIR_TAG) jeq 3f - cmpw %a0@(BIR_tag),%d0 + cmpw %a0@(BIR_TAG),%d0 jeq 2f - addw %a0@(BIR_size),%a0 + addw %a0@(BIR_SIZE),%a0 jra 1b 2: moveq #0,%d0 - movew %a0@(BIR_size),%d0 - lea %a0@(BIR_data),%a0 - rts + movew %a0@(BIR_SIZE),%d0 + lea %a0@(BIR_DATA),%a0 + jra 4f 3: moveq #-1,%d0 - lea %a0@(BIR_size),%a0 + lea %a0@(BIR_SIZE),%a0 +4: +func_return get_bi_record + + +/* + * MMU Initialization Begins Here + * + * The structure of the MMU tables on the 68k machines + * is thus: + * Root Table + * Logical addresses are translated through + * a hierarchical translation mechanism where the high-order + * seven bits of the logical address (LA) are used as an + * index into the "root table." Each entry in the root + * table has a bit which specifies if it's a valid pointer to a + * pointer table. Each entry defines a 32KMeg range of memory. + * If an entry is invalid then that logical range of 32M is + * invalid and references to that range of memory (when the MMU + * is enabled) will fault. If the entry is valid, then it does + * one of two things. On 040/060 class machines, it points to + * a pointer table which then describes more finely the memory + * within that 32M range. On 020/030 class machines, a technique + * called "early terminating descriptors" are used. This technique + * allows an entire 32Meg to be described by a single entry in the + * root table. Thus, this entry in the root table, contains the + * physical address of the memory or I/O at the logical address + * which the entry represents and it also contains the necessary + * cache bits for this region. + * + * Pointer Tables + * Per the Root Table, there will be one or more + * pointer tables. Each pointer table defines a 32M range. + * Not all of the 32M range need be defined. Again, the next + * seven bits of the logical address are used an index into + * the pointer table to point to page tables (if the pointer + * is valid). There will undoubtedly be more than one + * pointer table for the kernel because each pointer table + * defines a range of only 32M. Valid pointer table entries + * point to page tables, or are early terminating entries + * themselves. + * + * Page Tables + * Per the Pointer Tables, each page table entry points + * to the physical page in memory that supports the logical + * address that translates to the particular index. + * + * In short, the Logical Address gets translated as follows: + * bits 31..26 - index into the Root Table + * bits 25..18 - index into the Pointer Table + * bits 17..12 - index into the Page Table + * bits 11..0 - offset into a particular 4K page + * + * The algorithms which follows do one thing: they abstract + * the MMU hardware. For example, there are three kinds of + * cache settings that are relevant. Either, memory is + * being mapped in which case it is either Kernel Code (or + * the RamDisk) or it is MMU data. On the 030, the MMU data + * option also describes the kernel. Or, I/O is being mapped + * in which case it has its own kind of cache bits. There + * are constants which abstract these notions from the code that + * actually makes the call to map some range of memory. + * + * + * + */ + +#ifdef MMU_PRINT +/* + * mmu_print + * + * This algorithm will print out the current MMU mappings. + * + * Input: + * %a5 points to the root table. Everything else is calculated + * from this. + */ + +#define mmu_next_valid 0 +#define mmu_start_logical 4 +#define mmu_next_logical 8 +#define mmu_start_physical 12 +#define mmu_next_physical 16 + +#define MMU_PRINT_INVALID -1 +#define MMU_PRINT_VALID 1 +#define MMU_PRINT_UNINITED 0 + +#define putZc(z,n) jbne 1f; putc z; jbra 2f; 1: putc n; 2: + +func_start mmu_print,%a0-%a6/%d0-%d7 + + movel %pc@(L(kernel_pgdir_ptr)),%a5 + lea %pc@(L(mmu_print_data)),%a0 + movel #MMU_PRINT_UNINITED,%a0@(mmu_next_valid) + + is_not_040_or_060(mmu_030_print) + +mmu_040_print: + puts "\nMMU040\n" + puts "rp:" + putn %a5 + putc '\n' +#if 0 + /* + * The following #if/#endif block is a tight algorithm for dumping the 040 + * MMU Map in gory detail. It really isn't that practical unless the + * MMU Map algorithm appears to go awry and you need to debug it at the + * entry per entry level. + */ + movel #ROOT_TABLE_SIZE,%d5 +#if 0 + movel %a5@+,%d7 | Burn an entry to skip the kernel mappings, + subql #1,%d5 | they (might) work +#endif +1: tstl %d5 + jbeq mmu_print_done + subq #1,%d5 + movel %a5@+,%d7 + btst #1,%d7 + jbeq 1b + +2: putn %d7 + andil #0xFFFFFE00,%d7 + movel %d7,%a4 + movel #PTR_TABLE_SIZE,%d4 + putc ' ' +3: tstl %d4 + jbeq 11f + subq #1,%d4 + movel %a4@+,%d7 + btst #1,%d7 + jbeq 3b + +4: putn %d7 + andil #0xFFFFFF00,%d7 + movel %d7,%a3 + movel #PAGE_TABLE_SIZE,%d3 +5: movel #8,%d2 +6: tstl %d3 + jbeq 31f + subq #1,%d3 + movel %a3@+,%d6 + btst #0,%d6 + jbeq 6b +7: tstl %d2 + jbeq 8f + subq #1,%d2 + putc ' ' + jbra 91f +8: putc '\n' + movel #8+1+8+1+1,%d2 +9: putc ' ' + dbra %d2,9b + movel #7,%d2 +91: putn %d6 + jbra 6b + +31: putc '\n' + movel #8+1,%d2 +32: putc ' ' + dbra %d2,32b + jbra 3b + +11: putc '\n' + jbra 1b +#endif /* MMU 040 Dumping code that's gory and detailed */ + + lea %pc@(SYMBOL_NAME(kernel_pg_dir)),%a5 + movel %a5,%a0 /* a0 has the address of the root table ptr */ + movel #0x00000000,%a4 /* logical address */ + moveql #0,%d0 +40: + /* Increment the logical address and preserve in d5 */ + movel %a4,%d5 + addil #PAGESIZE<<13,%d5 + movel %a0@+,%d6 + btst #1,%d6 + jbne 41f + jbsr mmu_print_tuple_invalidate + jbra 48f +41: + movel #0,%d1 + andil #0xfffffe00,%d6 + movel %d6,%a1 +42: + movel %a4,%d5 + addil #PAGESIZE<<6,%d5 + movel %a1@+,%d6 + btst #1,%d6 + jbne 43f + jbsr mmu_print_tuple_invalidate + jbra 47f +43: + movel #0,%d2 + andil #0xffffff00,%d6 + movel %d6,%a2 +44: + movel %a4,%d5 + addil #PAGESIZE,%d5 + movel %a2@+,%d6 + btst #0,%d6 + jbne 45f + jbsr mmu_print_tuple_invalidate + jbra 46f +45: + moveml %d0-%d1,%sp@- + movel %a4,%d0 + movel %d6,%d1 + andil #0xfffff4e0,%d1 + lea %pc@(mmu_040_print_flags),%a6 + jbsr mmu_print_tuple + moveml %sp@+,%d0-%d1 +46: + movel %d5,%a4 + addq #1,%d2 + cmpib #64,%d2 + jbne 44b +47: + movel %d5,%a4 + addq #1,%d1 + cmpib #128,%d1 + jbne 42b +48: + movel %d5,%a4 /* move to the next logical address */ + addq #1,%d0 + cmpib #128,%d0 + jbne 40b + + .chip 68040 + movec %dtt1,%d0 + movel %d0,%d1 + andiw #0x8000,%d1 /* is it valid ? */ + jbeq 1f /* No, bail out */ + + movel %d0,%d1 + andil #0xff000000,%d1 /* Get the address */ + putn %d1 + puts "==" + putn %d1 + + movel %d0,%d6 + jbsr mmu_040_print_flags_tt +1: + movec %dtt0,%d0 + movel %d0,%d1 + andiw #0x8000,%d1 /* is it valid ? */ + jbeq 1f /* No, bail out */ + + movel %d0,%d1 + andil #0xff000000,%d1 /* Get the address */ + putn %d1 + puts "==" + putn %d1 + + movel %d0,%d6 + jbsr mmu_040_print_flags_tt +1: + .chip 68k + + jbra mmu_print_done + +mmu_040_print_flags: + btstl #10,%d6 + putZc(' ','G') /* global bit */ + btstl #7,%d6 + putZc(' ','S') /* supervisor bit */ +mmu_040_print_flags_tt: + btstl #6,%d6 + jbne 3f + putc 'C' + btstl #5,%d6 + putZc('w','c') /* write through or copy-back */ + jbra 4f +3: + putc 'N' + btstl #5,%d6 + putZc('s',' ') /* serialized non-cacheable, or non-cacheable */ +4: + rts + +mmu_030_print_flags: + btstl #6,%d6 + putZc('C','I') /* write through or copy-back */ + rts + +mmu_030_print: + puts "\nMMU030\n" + puts "\nrp:" + putn %a5 + putc '\n' + movel %a5,%d0 + andil #0xfffffff0,%d0 + movel %d0,%a0 + movel #0x00000000,%a4 /* logical address */ + movel #0,%d0 +30: + movel %a4,%d5 + addil #PAGESIZE<<13,%d5 + movel %a0@+,%d6 + btst #1,%d6 /* is it a ptr? */ + jbne 31f /* yes */ + btst #0,%d6 /* is it early terminating? */ + jbeq 1f /* no */ + jbsr mmu_030_print_helper + jbra 38f +1: + jbsr mmu_print_tuple_invalidate + jbra 38f +31: + movel #0,%d1 + andil #0xfffffff0,%d6 + movel %d6,%a1 +32: + movel %a4,%d5 + addil #PAGESIZE<<6,%d5 + movel %a1@+,%d6 + btst #1,%d6 + jbne 33f + btst #0,%d6 + jbeq 1f /* no */ + jbsr mmu_030_print_helper + jbra 37f +1: + jbsr mmu_print_tuple_invalidate + jbra 37f +33: + movel #0,%d2 + andil #0xfffffff0,%d6 + movel %d6,%a2 +34: + movel %a4,%d5 + addil #PAGESIZE,%d5 + movel %a2@+,%d6 + btst #0,%d6 + jbne 35f + jbsr mmu_print_tuple_invalidate + jbra 36f +35: + jbsr mmu_030_print_helper +36: + movel %d5,%a4 + addq #1,%d2 + cmpib #64,%d2 + jbne 34b +37: + movel %d5,%a4 + addq #1,%d1 + cmpib #128,%d1 + jbne 32b +38: + movel %d5,%a4 /* move to the next logical address */ + addq #1,%d0 + cmpib #128,%d0 + jbne 30b + +mmu_print_done: + puts "\n\n" + +func_return mmu_print + + +mmu_030_print_helper: + moveml %d0-%d1,%sp@- + movel %a4,%d0 + movel %d6,%d1 + lea %pc@(mmu_030_print_flags),%a6 + jbsr mmu_print_tuple + moveml %sp@+,%d0-%d1 + rts + +mmu_print_tuple_invalidate: + moveml %a0/%d7,%sp@- + + lea %pc@(L(mmu_print_data)),%a0 + tstl %a0@(mmu_next_valid) + jbmi mmu_print_tuple_invalidate_exit + + movel #MMU_PRINT_INVALID,%a0@(mmu_next_valid) + + putn %a4 + + puts "##\n" + +mmu_print_tuple_invalidate_exit: + moveml %sp@+,%a0/%d7 + rts + + +mmu_print_tuple: + moveml %d0-%d7/%a0,%sp@- + + lea %pc@(L(mmu_print_data)),%a0 + + tstl %a0@(mmu_next_valid) + jble mmu_print_tuple_print + + cmpl %a0@(mmu_next_physical),%d1 + jbeq mmu_print_tuple_increment + +mmu_print_tuple_print: + putn %d0 + puts "->" + putn %d1 + + movel %d1,%d6 + jbsr %a6@ + +mmu_print_tuple_record: + movel #MMU_PRINT_VALID,%a0@(mmu_next_valid) + + movel %d1,%a0@(mmu_next_physical) + +mmu_print_tuple_increment: + movel %d5,%d7 + subl %a4,%d7 + addl %d7,%a0@(mmu_next_physical) + +mmu_print_tuple_exit: + moveml %sp@+,%d0-%d7/%a0 rts +mmu_print_machine_cpu_types: + puts "machine: " + + is_not_amiga(1f) + puts "amiga" + jbra 9f +1: + is_not_atari(2f) + puts "atari" + jbra 9f +2: + is_not_mac(3f) + puts "macintosh" + jbra 9f +3: puts "unknown" +9: putc '\n' + + puts "cputype: 0" + is_not_060(1f) + putc '6' + jbra 9f +1: + is_not_040_or_060(2f) + putc '4' + jbra 9f +2: putc '3' +9: putc '0' + putc '\n' + + rts +#endif /* MMU_PRINT */ + +/* + * mmu_map_tt + * + * This is a specific function which works on all 680x0 machines. + * On 030, 040 & 060 it will attempt to use Transparent Translation + * registers (tt1). + * On 020 it will call the standard mmu_map which will use early + * terminating descriptors. + */ +func_start mmu_map_tt,%d0/%d1/%a0,4 + + dputs "mmu_map_tt:" + dputn ARG1 + dputn ARG2 + dputn ARG3 + dputn ARG4 + dputc '\n' + + is_020(L(do_map)) + + /* Extract the highest bit set + */ + bfffo ARG3{#0,#32},%d1 + cmpw #8,%d0 + jcc L(do_map) + + /* And get the mask + */ + moveq #-1,%d0 + lsrl %d1,%d0 + lsrl #1,%d0 + + /* Mask the address + */ + movel %d0,%d1 + notl %d1 + andl ARG2,%d1 + + /* Generate the upper 16bit of the tt register + */ + lsrl #8,%d0 + orl %d0,%d1 + clrw %d1 + + is_040_or_060(L(mmu_map_tt_040)) + + /* set 030 specific bits (read/write access for supervisor mode + * (highest function code set, lower two bits masked)) + */ + orw #TTR_ENABLE+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d1 + movel ARG4,%d0 + btst #6,%d0 + jeq 1f + orw #TTR_CI,%d1 + +1: lea STACK,%a0 + dputn %d1 + movel %d1,%a0@ + .chip 68030 + tstl ARG1 + jne 1f + pmove %a0@,%tt0 + jra 2f +1: pmove %a0@,%tt1 +2: .chip 68k + jra L(mmu_map_tt_done) + + /* set 040 specific bits + */ +L(mmu_map_tt_040): + orw #TTR_ENABLE+TTR_KERNELMODE,%d1 + orl ARG4,%d1 + dputn %d1 + + .chip 68040 + tstl ARG1 + jne 1f + movec %d1,%itt0 + movec %d1,%dtt0 + jra 2f +1: movec %d1,%itt1 + movec %d1,%dtt1 +2: .chip 68k + + jra L(mmu_map_tt_done) + +L(do_map): + mmu_map_eq ARG2,ARG3,ARG4 + +L(mmu_map_tt_done): + +func_return mmu_map_tt + +/* + * mmu_map + * + * This routine will map a range of memory using a pointer + * table and allocating the pages on the fly from the kernel. + * The pointer table does not have to be already linked into + * the root table, this routine will do that if necessary. + * + * NOTE + * This routine will assert failure and use the serial_putc + * routines in the case of a run-time error. For example, + * if the address is already mapped. + * + * NOTE-2 + * This routine will use early terminating descriptors + * where possible for the 68020+68851 and 68030 type + * processors. + */ +func_start mmu_map,%d0-%d4/%a0-%a4 + + dputs "\nmmu_map:" + dputn ARG1 + dputn ARG2 + dputn ARG3 + dputn ARG4 + dputc '\n' + + /* Get logical address and round it down to 256KB + */ + movel ARG1,%d0 + andl #-(PAGESIZE*PAGE_TABLE_SIZE),%d0 + movel %d0,%a3 + + /* Get the end address + */ + movel ARG1,%a4 + addl ARG3,%a4 + subql #1,%a4 + + /* Get physical address and round it down to 256KB + */ + movel ARG2,%d0 + andl #-(PAGESIZE*PAGE_TABLE_SIZE),%d0 + movel %d0,%a2 + + /* Add page attributes to the physical address + */ + movel ARG4,%d0 + orw #_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY,%d0 + addw %d0,%a2 + + dputn %a2 + dputn %a3 + dputn %a4 + + is_not_040_or_060(L(mmu_map_030)) + + addw #_PAGE_GLOBAL040,%a2 +/* + * MMU 040 & 060 Support + * + * The MMU usage for the 040 and 060 is different enough from + * the 030 and 68851 that there is separate code. This comment + * block describes the data structures and algorithms built by + * this code. + * + * The 040 does not support early terminating descriptors, as + * the 030 does. Therefore, a third level of table is needed + * for the 040, and that would be the page table. In Linux, + * page tables are allocated directly from the memory above the + * kernel. + * + */ + +L(mmu_map_040): + /* Calculate the offset into the root table + */ + movel %a3,%d0 + moveq #ROOT_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + mmu_get_root_table_entry %d0 + + /* Calculate the offset into the pointer table + */ + movel %a3,%d0 + moveq #PTR_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + andl #PTR_TABLE_SIZE-1,%d0 + mmu_get_ptr_table_entry %a0,%d0 + + /* Calculate the offset into the page table + */ + movel %a3,%d0 + moveq #PAGE_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + andl #PAGE_TABLE_SIZE-1,%d0 + mmu_get_page_table_entry %a0,%d0 + + /* The page table entry must not no be busy + */ + tstl %a0@ + jne L(mmu_map_error) + + /* Do the mapping and advance the pointers + */ + movel %a2,%a0@ +2: + addw #PAGESIZE,%a2 + addw #PAGESIZE,%a3 + + /* Ready with mapping? + */ + lea %a3@(-1),%a0 + cmpl %a0,%a4 + jhi L(mmu_map_040) + jra L(mmu_map_done) + +L(mmu_map_030): + /* Calculate the offset into the root table + */ + movel %a3,%d0 + moveq #ROOT_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + mmu_get_root_table_entry %d0 + + /* Check if logical address 32MB aligned, + * so we can try to map it once + */ + movel %a3,%d0 + andl #(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE-1)&(-ROOT_TABLE_SIZE),%d0 + jne 1f + + /* Is there enough to map for 32MB at once + */ + lea %a3@(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE-1),%a1 + cmpl %a1,%a4 + jcs 1f + + addql #1,%a1 + + /* The root table entry must not no be busy + */ + tstl %a0@ + jne L(mmu_map_error) + + /* Do the mapping and advance the pointers + */ + dputs "early term1" + dputn %a2 + dputn %a3 + dputn %a1 + dputc '\n' + movel %a2,%a0@ + + movel %a1,%a3 + lea %a2@(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE),%a2 + jra L(mmu_mapnext_030) +1: + /* Calculate the offset into the pointer table + */ + movel %a3,%d0 + moveq #PTR_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + andl #PTR_TABLE_SIZE-1,%d0 + mmu_get_ptr_table_entry %a0,%d0 + + /* The pointer table entry must not no be busy + */ + tstl %a0@ + jne L(mmu_map_error) + + /* Do the mapping and advance the pointers + */ + dputs "early term2" + dputn %a2 + dputn %a3 + dputc '\n' + movel %a2,%a0@ + + addl #PAGE_TABLE_SIZE*PAGESIZE,%a2 + addl #PAGE_TABLE_SIZE*PAGESIZE,%a3 + +L(mmu_mapnext_030): + /* Ready with mapping? + */ + lea %a3@(-1),%a0 + cmpl %a0,%a4 + jhi L(mmu_map_030) + jra L(mmu_map_done) + +L(mmu_map_error): + + dputs "mmu_map error:" + dputn %a2 + dputn %a3 + dputc '\n' + +L(mmu_map_done): + +func_return mmu_map + +/* + * mmu_fixup + * + * On the 040 class machines, all pages that are used for the + * mmu have to be fixed up. + */ + +func_start mmu_fixup_page_mmu_cache,%d0/%a0 + + dputs "mmu_fixup_page_mmu_cache" + dputn ARG1 + + /* Calculate the offset into the root table + */ + movel ARG1,%d0 + moveq #ROOT_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + mmu_get_root_table_entry %d0 + + /* Calculate the offset into the pointer table + */ + movel ARG1,%d0 + moveq #PTR_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + andl #PTR_TABLE_SIZE-1,%d0 + mmu_get_ptr_table_entry %a0,%d0 + + /* Calculate the offset into the page table + */ + movel ARG1,%d0 + moveq #PAGE_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + andl #PAGE_TABLE_SIZE-1,%d0 + mmu_get_page_table_entry %a0,%d0 + + movel %a0@,%d0 + andil #_CACHEMASK040,%d0 + orl %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%d0 + movel %d0,%a0@ + + dputc '\n' + +func_return mmu_fixup_page_mmu_cache + +/* + * mmu_temp_map + * + * create a temporary mapping to enable the mmu, + * this we don't need any transparation translation tricks. + */ + +func_start mmu_temp_map,%d0/%d1/%a0/%a1 + + dputs "mmu_temp_map" + dputn ARG1 + dputn ARG2 + dputc '\n' + + lea %pc@(L(temp_mmap_mem)),%a1 + + /* Calculate the offset in the root table + */ + movel ARG2,%d0 + moveq #ROOT_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + mmu_get_root_table_entry %d0 + + /* Check if the table is temporary allocated, so we have to reuse it + */ + movel %a0@,%d0 + cmpl %pc@(L(memory_start)),%d0 + jcc 1f + + /* Temporary allocate a ptr table and insert it into the root table + */ + movel %a1@,%d0 + addl #PTR_TABLE_SIZE*4,%a1@ + orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0 + movel %d0,%a0@ + dputs " (new)" +1: + dputn %d0 + /* Mask the root table entry for the ptr table + */ + andw #-ROOT_TABLE_SIZE,%d0 + movel %d0,%a0 + + /* Calculate the offset into the pointer table + */ + movel ARG2,%d0 + moveq #PTR_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + andl #PTR_TABLE_SIZE-1,%d0 + lea %a0@(%d0*4),%a0 + dputn %a0 + + /* Check if a temporary page table is already allocated + */ + movel %a0@,%d0 + jne 1f + + /* Temporary allocate a page table and insert it into the ptr table + */ + movel %a1@,%d0 + addl #PTR_TABLE_SIZE*4,%a1@ + orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0 + movel %d0,%a0@ + dputs " (new)" +1: + dputn %d0 + /* Mask the ptr table entry for the page table + */ + andw #-PTR_TABLE_SIZE,%d0 + movel %d0,%a0 + + /* Calculate the offset into the page table + */ + movel ARG2,%d0 + moveq #PAGE_INDEX_SHIFT,%d1 + lsrl %d1,%d0 + andl #PAGE_TABLE_SIZE-1,%d0 + lea %a0@(%d0*4),%a0 + dputn %a0 + + /* Insert the address into the page table + */ + movel ARG1,%d0 + andw #-PAGESIZE,%d0 + orw #_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY,%d0 + movel %d0,%a0@ + dputn %d0 + + dputc '\n' + +func_return mmu_temp_map + +func_start mmu_engage,%d0-%d2/%a0-%a3 + + moveq #ROOT_TABLE_SIZE-1,%d0 + /* Temporarily use a different root table. */ + lea %pc@(L(kernel_pgdir_ptr)),%a0 + movel %a0@,%a2 + movel %pc@(L(memory_start)),%a1 + movel %a1,%a0@ + movel %a2,%a0 +1: + movel %a0@+,%a1@+ + dbra %d0,1b + + lea %pc@(L(temp_mmap_mem)),%a0 + movel %a1,%a0@ + + movew #PAGESIZE-1,%d0 +1: + clrl %a1@+ + dbra %d0,1b + + lea %pc@(1b),%a0 + movel #1b,%a1 + /* Skip temp mappings if phys == virt */ + cmpl %a0,%a1 + jeq 1f + + mmu_temp_map %a0,%a0 + mmu_temp_map %a0,%a1 + + addw #PAGESIZE,%a0 + addw #PAGESIZE,%a1 + mmu_temp_map %a0,%a0 + mmu_temp_map %a0,%a1 +1: + movel %pc@(L(memory_start)),%a3 + movel %pc@(L(phys_kernel_start)),%d2 + + is_not_040_or_060(L(mmu_engage_030)) + +L(mmu_engage_040): + .chip 68040 + nop + cinva %bc + nop + pflusha + nop + movec %a3,%srp + movel #TC_ENABLE+TC_PAGE4K,%d0 + movec %d0,%tc /* enable the MMU */ + jmp 1f:l +1: nop + movec %a2,%srp + nop + cinva %bc + nop + pflusha + .chip 68k + jra L(mmu_engage_cleanup) + +L(mmu_engage_030_temp): + .space 12 +L(mmu_engage_030): + .chip 68030 + lea %pc@(L(mmu_engage_030_temp)),%a0 + movel #0x80000002,%a0@ + movel %a3,%a0@(4) + movel #0x0808,%d0 + movec %d0,%cacr + pmove %a0@,%srp + pflusha + /* + * enable,super root enable,4096 byte pages,7 bit root index, + * 7 bit pointer index, 6 bit page table index. + */ + movel #0x82c07760,%a0@(8) + pmove %a0@(8),%tc /* enable the MMU */ + jmp 1f:l +1: movel %a2,%a0@(4) + movel #0x0808,%d0 + movec %d0,%cacr + pmove %a0@,%srp + pflusha + .chip 68k + +L(mmu_engage_cleanup): + subl %d2,%a2 + movel %a2,L(kernel_pgdir_ptr) + subl %d2,%fp + subl %d2,%sp + subl %d2,ARG0 + subl %d2,L(memory_start) + +func_return mmu_engage + +func_start mmu_get_root_table_entry,%d0/%a1 + +#if 0 + dputs "mmu_get_root_table_entry:" + dputn ARG1 + dputs " =" +#endif + + movel %pc@(L(kernel_pgdir_ptr)),%a0 + tstl %a0 + jne 2f + + dputs "\nmmu_init:" + + /* Find the start of free memory, get_bi_record does this for us, + * as the bootinfo structure is located directly behind the kernel + * and and we simply search for the last entry. + */ + get_bi_record BI_LAST + addw #PAGESIZE-1,%a0 + movel %a0,%d0 + andw #-PAGESIZE,%d0 + + dputn %d0 + + lea %pc@(L(memory_start)),%a0 + movel %d0,%a0@ + lea %pc@(L(kernel_end)),%a0 + movel %d0,%a0@ + + /* we have to return the first page at _stext since the init code + * in mm/init.c simply expects kernel_pg_dir there, the rest of + * page is used for further ptr tables in get_ptr_table. + */ + lea %pc@(SYMBOL_NAME(_stext)),%a0 + lea %pc@(L(mmu_cached_pointer_tables)),%a1 + movel %a0,%a1@ + addl #ROOT_TABLE_SIZE*4,%a1@ + + lea %pc@(L(mmu_num_pointer_tables)),%a1 + addql #1,%a1@ + + /* clear the page + */ + movel %a0,%a1 + movew #PAGESIZE/4-1,%d0 +1: + clrl %a1@+ + dbra %d0,1b + + lea %pc@(L(kernel_pgdir_ptr)),%a1 + movel %a0,%a1@ + + dputn %a0 + dputc '\n' +2: + movel ARG1,%d0 + lea %a0@(%d0*4),%a0 + +#if 0 + dputn %a0 + dputc '\n' +#endif + +func_return mmu_get_root_table_entry + + + +func_start mmu_get_ptr_table_entry,%d0/%a1 + +#if 0 + dputs "mmu_get_ptr_table_entry:" + dputn ARG1 + dputn ARG2 + dputs " =" +#endif + + movel ARG1,%a0 + movel %a0@,%d0 + jne 2f + + /* Keep track of the number of pointer tables we use + */ + dputs "\nmmu_get_new_ptr_table:" + lea %pc@(L(mmu_num_pointer_tables)),%a0 + movel %a0@,%d0 + addql #1,%a0@ + + /* See if there is a free pointer table in our cache of pointer tables + */ + lea %pc@(L(mmu_cached_pointer_tables)),%a1 + andw #7,%d0 + jne 1f + + /* Get a new pointer table page from above the kernel memory + */ + get_new_page + movel %a0,%a1@ +1: + /* There is an unused pointer table in our cache... use it + */ + movel %a1@,%d0 + addl #PTR_TABLE_SIZE*4,%a1@ + + dputn %d0 + dputc '\n' + + /* Insert the new pointer table into the root table + */ + movel ARG1,%a0 + orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0 + movel %d0,%a0@ +2: + /* Extract the pointer table entry + */ + andw #-PTR_TABLE_SIZE,%d0 + movel %d0,%a0 + movel ARG2,%d0 + lea %a0@(%d0*4),%a0 + +#if 0 + dputn %a0 + dputc '\n' +#endif + +func_return mmu_get_ptr_table_entry + + +func_start mmu_get_page_table_entry,%d0/%a1 + +#if 0 + dputs "mmu_get_page_table_entry:" + dputn ARG1 + dputn ARG2 + dputs " =" +#endif + + movel ARG1,%a0 + movel %a0@,%d0 + jne 2f + + /* If the page table entry doesn't exist, we allocate a complete new + * page and use it as one continues big page table which can cover + * 4MB of memory, nearly almost all mappings have that alignment. + */ + get_new_page + addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0 + + /* align pointer table entry for a page of page tables + */ + movel ARG1,%d0 + andw #-(PAGESIZE/PAGE_TABLE_SIZE),%d0 + movel %d0,%a1 + + /* Insert the page tables into the pointer entries + */ + moveq #PAGESIZE/PAGE_TABLE_SIZE/4-1,%d0 +1: + movel %a0,%a1@+ + lea %a0@(PAGE_TABLE_SIZE*4),%a0 + dbra %d0,1b + + /* Now we can get the initialized pointer table entry + */ + movel ARG1,%a0 + movel %a0@,%d0 +2: + /* Extract the page table entry + */ + andw #-PAGE_TABLE_SIZE,%d0 + movel %d0,%a0 + movel ARG2,%d0 + lea %a0@(%d0*4),%a0 + +#if 0 + dputn %a0 + dputc '\n' +#endif + +func_return mmu_get_page_table_entry + +/* + * get_new_page + * + * Return a new page from the memory start and clear it. + */ +func_start get_new_page,%d0/%a1 + + dputs "\nget_new_page:" + + /* allocate the page and adjust memory_start + */ + lea %pc@(L(memory_start)),%a0 + movel %a0@,%a1 + addl #PAGESIZE,%a0@ + + /* clear the new page + */ + movel %a1,%a0 + movew #PAGESIZE/4-1,%d0 +1: + clrl %a1@+ + dbra %d0,1b + + dputn %a0 + dputc '\n' + +func_return get_new_page + + + /* * Debug output support * Atarians have a choice between the parallel port, the serial port * from the MFP or a serial port of the SCC */ +#ifdef CONFIG_MAC + +L(scc_initable_mac): + .byte 9,12 /* Reset */ + .byte 4,0x44 /* x16, 1 stopbit, no parity */ + .byte 3,0xc0 /* receiver: 8 bpc */ + .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */ + .byte 9,0 /* no interrupts */ + .byte 10,0 /* NRZ */ + .byte 11,0x50 /* use baud rate generator */ + .byte 12,10,13,0 /* 9600 baud */ + .byte 14,1 /* Baud rate generator enable */ + .byte 3,0xc1 /* enable receiver */ + .byte 5,0xea /* enable transmitter */ + .byte -1 + .even +#endif + #ifdef CONFIG_ATARI /* #define USE_PRINTER */ -/* #define USE_SCC */ +/* #define USE_SCC_B */ +/* #define USE_SCC_A */ #define USE_MFP +#if defined(USE_SCC_A) || defined(USE_SCC_B) +#define USE_SCC +/* Initialisation table for SCC */ +L(scc_initable): + .byte 9,12 /* Reset */ + .byte 4,0x44 /* x16, 1 stopbit, no parity */ + .byte 3,0xc0 /* receiver: 8 bpc */ + .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */ + .byte 9,0 /* no interrupts */ + .byte 10,0 /* NRZ */ + .byte 11,0x50 /* use baud rate generator */ + .byte 12,24,13,0 /* 9600 baud */ + .byte 14,2,14,3 /* use master clock for BRG, enable */ + .byte 3,0xc1 /* enable receiver */ + .byte 5,0xea /* enable transmitter */ + .byte -1 + .even +#endif + #ifdef USE_PRINTER LPSG_SELECT = 0xff8800 @@ -1129,13 +2554,18 @@ LSTMFP_GPIP = 0xfffa01 LSTMFP_DDR = 0xfffa05 LSTMFP_IERB = 0xfffa09 -#elif defined(USE_SCC) - -LSCC_CTRL_B = 0xff8c85 -LSCC_DATA_B = 0xff8c87 +#elif defined(USE_SCC_B) + +LSCC_CTRL = 0xff8c85 +LSCC_DATA = 0xff8c87 + +#elif defined(USE_SCC_A) + +LSCC_CTRL = 0xff8c81 +LSCC_DATA = 0xff8c83 /* Initialisation table for SCC */ -scc_initable: +L(scc_initable): .byte 9,12 /* Reset */ .byte 4,0x44 /* x16, 1 stopbit, no parity */ .byte 3,0xc0 /* receiver: 8 bpc */ @@ -1159,45 +2589,48 @@ LMFP_TSR = 0xfffa2d LMFP_UDR = 0xfffa2f #endif -#endif - -#if defined (CONFIG_BVME6000) -BVME_SCC_CTRL_A = 0xffb0000b -BVME_SCC_DATA_A = 0xffb0000f -#endif +#endif /* CONFIG_ATARI */ /* * Serial port output support. */ -LSERPER = 0xdff032 -LSERDAT = 0xdff030 -LSERDATR = 0xdff018 -LSERIAL_CNTRL = 0xbfd000 -LSERIAL_DTR = 7 /* * Initialize serial port hardware for 9600/8/1 - * a0 thrashed - * Amiga d0 trashed - * Atari d0 trashed (a1 in case of SCC) */ - .even -Lserial_init: +func_start serial_init,%d0/%d1/%a0/%a1 + /* + * Some of the register usage that follows + * CONFIG_AMIGA + * a0 = pointer to boot info record + * d0 = boot info offset + * CONFIG_ATARI + * a0 = address of SCC + * a1 = Liobase address/address of scc_initable + * d0 = init data for serial port + * CONFIG_MAC + * a0 = address of SCC + * a1 = address of scc_initable_mac + * d0 = init data for serial port + */ + #ifdef CONFIG_AMIGA - cmpil #MACH_AMIGA,%d4 - jne 1f - bclr #LSERIAL_DTR,LSERIAL_CNTRL - movew #BI_AMIGA_SERPER,%d0 - jbsr Lget_bi_record - movew %a0@,LSERPER - jra 9f +#define SERIAL_DTR 7 +#define SERIAL_CNTRL CIABBASE+C_PRA + + is_not_amiga(1f) + lea %pc@(L(custom)),%a0 + movel #-ZTWOBASE,%a0@ + bclr #SERIAL_DTR,SERIAL_CNTRL-ZTWOBASE + get_bi_record BI_AMIGA_SERPER + movew %a0@,CUSTOMBASE+C_SERPER-ZTWOBASE +| movew #61,CUSTOMBASE+C_SERPER-ZTWOBASE 1: #endif #ifdef CONFIG_ATARI - cmpil #MACH_ATARI,%d4 - jne 4f - movel %pc@(Liobase),%a1 -#ifdef USE_PRINTER + is_not_atari(4f) + movel %pc@(L(iobase)),%a1 +#if defined(USE_PRINTER) bclr #0,%a1@(LSTMFP_IERB) bclr #0,%a1@(LSTMFP_DDR) moveb #LPSG_CONTROL,%a1@(LPSG_SELECT) @@ -1209,8 +2642,8 @@ Lserial_init: bset #5,%d0 moveb %d0,%a1@(LPSG_WRITE) #elif defined(USE_SCC) - lea %a1@(LSCC_CTRL_B),%a0 - lea %pc@(scc_initable:w),%a1 + lea %a1@(LSCC_CTRL),%a0 + lea %pc@(L(scc_initable)),%a1 2: moveb %a1@+,%d0 jmi 3f moveb %d0,%a0@ @@ -1225,174 +2658,854 @@ Lserial_init: orb #1,%a1@(LMFP_TDCDR) bset #1,%a1@(LMFP_TSR) #endif + jra L(serial_init_done) 4: #endif -9: - rts - -#ifdef CONFIG_HP300 -/* Set LEDs to %d7 */ - .even -Lset_leds: - moveml %a0/%a1,%sp@- - movel %pc@(Lcustom),%a1 - moveb %d7,%a1@(0x1ffff) - moveml %sp@+,%a0/%a1 - rts +#ifdef CONFIG_MAC + is_not_mac(L(serial_init_not_mac)) +#ifdef MAC_SERIAL_DEBUG +#if !defined(MAC_USE_SCC_A) && !defined(MAC_USE_SCC_B) +#define MAC_USE_SCC_B #endif - +#define mac_scc_cha_b_ctrl_offset 0x0 +#define mac_scc_cha_a_ctrl_offset 0x2 +#define mac_scc_cha_b_data_offset 0x4 +#define mac_scc_cha_a_data_offset 0x6 + +#ifdef MAC_USE_SCC_A + /* Initialize channel A */ + movel %pc@(L(mac_sccbase)),%a0 + lea %pc@(L(scc_initable_mac)),%a1 +5: moveb %a1@+,%d0 + jmi 6f + moveb %d0,%a0@(mac_scc_cha_a_ctrl_offset) + moveb %a1@+,%a0@(mac_scc_cha_a_ctrl_offset) + jra 5b +6: +#endif /* MAC_USE_SCC_A */ + +#ifdef MAC_USE_SCC_B + /* Initialize channel B */ +#ifndef MAC_USE_SCC_A /* Load mac_sccbase only if needed */ + movel %pc@(L(mac_sccbase)),%a0 +#endif /* MAC_USE_SCC_A */ + lea %pc@(L(scc_initable_mac)),%a1 +7: moveb %a1@+,%d0 + jmi 8f + moveb %d0,%a0@(mac_scc_cha_b_ctrl_offset) + moveb %a1@+,%a0@(mac_scc_cha_b_ctrl_offset) + jra 7b +8: +#endif /* MAC_USE_SCC_B */ +#endif /* MAC_SERIAL_DEBUG */ + + jra L(serial_init_done) +L(serial_init_not_mac): +#endif /* CONFIG_MAC */ + +L(serial_init_done): +func_return serial_init + /* - * Output character in d7 on serial port. - * d7 thrashed. + * Output character on serial port. */ -Lserial_putc: - moveml %a0/%a1,%sp@- -#if defined(CONFIG_MVME16x) - cmpil #MACH_MVME16x,%d4 - jne 2f - moveb %d7,%sp@- - .long 0x4e4f0020 - jra 9f -2: -#endif -#ifdef CONFIG_BVME6000 - cmpil #MACH_BVME6000,%d4 - jne 2f -1: btst #2,BVME_SCC_CTRL_A - jeq 1b - moveb %d7,BVME_SCC_DATA_A - jra 9f -2: -#endif +func_start serial_putc,%d0/%d1/%a0/%a1 + + movel ARG1,%d0 + cmpib #'\n',%d0 + jbne 1f + + /* A little safe recursion is good for the soul */ + serial_putc #'\r' +1: + #ifdef CONFIG_AMIGA - cmpil #MACH_AMIGA,%d4 - jne 2f - andw #0x00ff,%d7 - oriw #0x0100,%d7 - movel %pc@(Lcustom),%a1 - movew %d7,%a1@(LSERDAT) -1: movew %a1@(LSERDATR),%d7 - andw #0x2000,%d7 + is_not_amiga(2f) + andw #0x00ff,%d0 + oriw #0x0100,%d0 + movel %pc@(L(custom)),%a0 + movew %d0,%a0@(CUSTOMBASE+C_SERDAT) +1: movew %a0@(CUSTOMBASE+C_SERDATR),%d0 + andw #0x2000,%d0 jeq 1b - jra 9f + jra L(serial_putc_done) 2: #endif + +#ifdef CONFIG_MAC + is_not_mac(5f) + +#ifdef CONSOLE + console_putc %d0 +#endif /* CONSOLE */ + +#ifdef MAC_SERIAL_DEBUG + +#ifdef MAC_USE_SCC_A + movel %pc@(L(mac_sccbase)),%a1 +3: btst #2,%a1@(mac_scc_cha_a_ctrl_offset) + jeq 3b + moveb %d0,%a1@(mac_scc_cha_a_data_offset) +#endif /* MAC_USE_SCC_A */ + +#ifdef MAC_USE_SCC_B +#ifndef MAC_USE_SCC_A /* Load mac_sccbase only if needed */ + movel %pc@(L(mac_sccbase)),%a1 +#endif /* MAC_USE_SCC_A */ +4: btst #2,%a1@(mac_scc_cha_b_ctrl_offset) + jeq 4b + moveb %d0,%a1@(mac_scc_cha_b_data_offset) +#endif /* MAC_USE_SCC_B */ + +#endif /* MAC_SERIAL_DEBUG */ + + jra L(serial_putc_done) +5: +#endif /* CONFIG_MAC */ + #ifdef CONFIG_ATARI - cmpil #MACH_ATARI,%d4 - jne 4f - movel %pc@(Liobase),%a1 -#ifdef USE_PRINTER + is_not_atari(4f) + movel %pc@(L(iobase)),%a1 +#if defined(USE_PRINTER) 3: btst #0,%a1@(LSTMFP_GPIP) jne 3b moveb #LPSG_IO_B,%a1@(LPSG_SELECT) - moveb %d7,%a1@(LPSG_WRITE) + moveb %d0,%a1@(LPSG_WRITE) moveb #LPSG_IO_A,%a1@(LPSG_SELECT) - moveb %a1@(LPSG_READ),%d7 - bclr #5,%d7 - moveb %d7,%a1@(LPSG_WRITE) + moveb %a1@(LPSG_READ),%d0 + bclr #5,%d0 + moveb %d0,%a1@(LPSG_WRITE) nop nop - bset #5,%d7 - moveb %d7,%a1@(LPSG_WRITE) + bset #5,%d0 + moveb %d0,%a1@(LPSG_WRITE) #elif defined(USE_SCC) -3: btst #2,%a1@(LSCC_CTRL_B) +3: btst #2,%a1@(LSCC_CTRL) jeq 3b - moveb %d7,%a1@(LSCC_DATA_B) + moveb %d0,%a1@(LSCC_DATA) #elif defined(USE_MFP) 3: btst #7,%a1@(LMFP_TSR) jeq 3b - moveb %d7,%a1@(LMFP_UDR) + moveb %d0,%a1@(LMFP_UDR) #endif + jra L(serial_putc_done) 4: +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_MVME16x + is_not_mvme16x(2f) + /* + * The VME 16x class has PROM support for serial output + * of some kind; the TRAP table is still valid. + */ + moveml %d0-%d7/%a2-%a6,%sp@- + moveb %d0,%sp@- + trap #15 + .word 0x0020 /* TRAP 0x020 */ + moveml %sp@+,%d0-%d7/%a2-%a6 + jbra L(serial_putc_done) +2: +#endif CONFIG_MVME162 | CONFIG_MVME167 + +#ifdef CONFIG_BVME6000 + is_not_bvme6000(2f) + /* + * The BVME6000 machine has a serial port ... + */ +1: btst #2,BVME_SCC_CTRL_A + jeq 1b + moveb %d0,BVME_SCC_DATA_A + jbra L(serial_putc_done) +2: +#endif + +L(serial_putc_done): +func_return serial_putc + +/* + * Output a string. + */ +func_start puts,%d0/%a0 + + movel ARG1,%a0 + jra 2f +1: +#ifdef CONSOLE + console_putc %d0 +#endif +#ifdef SERIAL_DEBUG + serial_putc %d0 +#endif +2: moveb %a0@+,%d0 + jne 1b + +func_return puts + +/* + * Output number in hex notation. + */ + +func_start putn,%d0-%d2 + + putc ' ' + + movel ARG1,%d0 + moveq #7,%d1 +1: roll #4,%d0 + move %d0,%d2 + andb #0x0f,%d2 + addb #'0',%d2 + cmpb #'9',%d2 + jls 2f + addb #'A'-('9'+1),%d2 +2: +#ifdef CONSOLE + console_putc %d2 +#endif +#ifdef SERIAL_DEBUG + serial_putc %d2 #endif -9: - moveml %sp@+,%a0/%a1 + dbra %d1,1b + +func_return putn + +#ifdef CONFIG_MAC +/* + * mac_serial_print + * + * This routine takes its parameters on the stack. It then + * turns around and calls the internal routine. This routine + * is used until the Linux console driver initializes itself. + * + * The calling parameters are: + * void mac_serial_print(const char *str); + * + * This routine does NOT understand variable arguments only + * simple strings! + */ +ENTRY(mac_serial_print) + moveml %d0/%a0,%sp@- +#if 1 + move %sr,%sp@- + ori #0x0700,%sr +#endif + movel %sp@(10),%a0 /* fetch parameter */ + jra 2f +1: serial_putc %d0 +2: moveb %a0@+,%d0 + jne 1b +#if 1 + move %sp@+,%sr +#endif + moveml %sp@+,%d0/%a0 rts +#endif /* CONFIG_MAC */ + +#ifdef CONFIG_HP300 +func_start set_leds,%d0/%a0 + movel ARG1,%d0 + movel %pc@(Lcustom),%a0 + moveb %d0,%a0@(0x1ffff) +func_return set_leds +#endif +#ifdef CONSOLE /* - * Output string pointed to by a0 to serial port. - * a0 trashed. + * For continuity, see the data alignment + * to which this structure is tied. */ -Lserial_puts: - movel %d7,%sp@- -1: moveb %a0@+,%d7 - jeq 2f - jbsr Lserial_putc - jra 1b -2: movel %sp@+,%d7 +#define Lconsole_struct_cur_column 0 +#define Lconsole_struct_cur_row 4 +#define Lconsole_struct_num_columns 8 +#define Lconsole_struct_num_rows 12 +#define Lconsole_struct_left_edge 16 +#define Lconsole_struct_penguin_putc 20 + +L(console_init): + /* + * Some of the register usage that follows + * a0 = pointer to boot_info + * a1 = pointer to screen + * a2 = pointer to Lconsole_globals + * d3 = pixel width of screen + * d4 = pixel height of screen + * (d3,d4) ~= (x,y) of a point just below + * and to the right of the screen + * NOT on the screen! + * d5 = number of bytes per scan line + * d6 = number of bytes on the entire screen + */ + moveml %a0-%a4/%d0-%d7,%sp@- + + lea %pc@(L(console_globals)),%a2 + lea %pc@(L(mac_videobase)),%a0 + movel %a0@,%a1 + lea %pc@(L(mac_rowbytes)),%a0 + movel %a0@,%d5 + lea %pc@(L(mac_dimensions)),%a0 + movel %a0@,%d3 /* -> low byte */ + movel %d3,%d4 + swap %d4 /* -> high byte */ + andl #0xffff,%d3 /* d3 = screen width in pixels */ + andl #0xffff,%d4 /* d4 = screen height in pixels */ + + movel %d5,%d6 + subl #20,%d6 + mulul %d4,%d6 /* scan line bytes x num scan lines */ + divul #8,%d6 /* we'll clear 8 bytes at a time */ + subq #1,%d6 + +console_clear_loop: + movel #0xffffffff,%a1@+ /* Mac_black */ + movel #0xffffffff,%a1@+ /* Mac_black */ + dbra %d6,console_clear_loop + + /* Calculate font size */ + +#if defined(FONT_8x8) + lea %pc@(SYMBOL_NAME(font_vga_8x8)), %a0 +#elif defined(FONT_8x16) + lea %pc@(SYMBOL_NAME(font_vga_8x16)),%a0 +#elif defined(FONT_6x11) + lea %pc@(SYMBOL_NAME(font_vga_6x11)),%a0 +#else /* (FONT_8x8) default */ + lea %pc@(SYMBOL_NAME(font_vga_8x8)), %a0 +#endif + + /* + * At this point we make a shift in register usage + * a1 = address of Lconsole_font pointer + */ + lea %pc@(L(console_font)),%a1 + movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in Lconsole_font */ + + /* + * Calculate global maxs + * Note - we can use either an + * 8 x 16 or 8 x 8 character font + * 6 x 11 also supported + */ + /* ASSERT: a0 = contents of Lconsole_font */ + movel %d3,%d0 /* screen width in pixels */ + divul %a0@(FBCON_FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */ + + movel %d4,%d1 /* screen height in pixels */ + divul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */ + + movel %d0,%a2@(Lconsole_struct_num_columns) + movel %d1,%a2@(Lconsole_struct_num_rows) + + /* + * Clear the current row and column + */ + clrl %a2@(Lconsole_struct_cur_column) + clrl %a2@(Lconsole_struct_cur_row) + clrl %a2@(Lconsole_struct_left_edge) + + /* + * Initialization is complete + */ + moveml %sp@+,%a0-%a4/%d0-%d7 + rts + +L(console_put_stats): + /* + * Some of the register usage that follows + * a0 = pointer to boot_info + * d7 = value of boot_info fields + */ + moveml %a0/%d7,%sp@- + + puts "\nMacLinux\n\n" + +#ifdef SERIAL_DEBUG + puts " vidaddr:" + putn %pc@(L(mac_videobase)) /* video addr. */ + + puts "\n _stext:" + lea %pc@(SYMBOL_NAME(_stext)),%a0 + putn %a0 + + puts "\nbootinfo:" + lea %pc@(SYMBOL_NAME(_end)),%a0 + putn %a0 + + puts "\ncpuid:" + putn %pc@(L(cputype)) + putc '\n' + +# if defined(MMU_PRINT) + jbsr mmu_print_machine_cpu_types +# endif /* MMU_PRINT */ +#endif /* SERIAL_DEBUG */ + + moveml %sp@+,%a0/%d7 + rts + +#ifdef CONSOLE_PENGUIN +L(console_put_penguin): + /* + * Get 'that_penguin' onto the screen in the upper right corner + * penguin is 64 x 74 pixels, align against right edge of screen + */ + moveml %a0-%a1/%d0-%d7,%sp@- + + lea %pc@(L(mac_dimensions)),%a0 + movel %a0@,%d0 + andil #0xffff,%d0 + subil #64,%d0 /* snug up against the right edge */ + clrl %d1 /* start at the top */ + movel #73,%d7 + lea %pc@(SYMBOL_NAME(that_penguin)),%a1 +console_penguin_row: + movel #31,%d6 +console_penguin_pixel_pair: + moveb %a1@,%d2 + lsrb #4,%d2 + jbsr console_plot_pixel + addq #1,%d0 + moveb %a1@+,%d2 + jbsr console_plot_pixel + addq #1,%d0 + dbra %d6,console_penguin_pixel_pair + + subil #64,%d0 + addq #1,%d1 + dbra %d7,console_penguin_row + + moveml %sp@+,%a0-%a1/%d0-%d7 + rts +#endif + +console_scroll: + moveml %a0-%a4/%d0-%d7,%sp@- + + /* + * Calculate source and destination addresses + * output a1 = dest + * a2 = source + */ + lea %pc@(L(mac_videobase)),%a0 + movel %a0@,%a1 + movel %a1,%a2 + lea %pc@(L(mac_rowbytes)),%a0 + movel %a0@,%d5 + movel %pc@(L(console_font)),%a0 + mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d5 /* account for # scan lines per character */ + addal %d5,%a2 + + /* + * Get dimensions + */ + lea %pc@(L(mac_dimensions)),%a0 + movel %a0@,%d3 + movel %d3,%d4 + swap %d4 + andl #0xffff,%d3 /* d3 = screen width in pixels */ + andl #0xffff,%d4 /* d4 = screen height in pixels */ + + /* + * Calculate number of bytes to move + */ + lea %pc@(L(mac_rowbytes)),%a0 + movel %a0@,%d6 + movel %pc@(L(console_font)),%a0 + subl %a0@(FBCON_FONT_DESC_HEIGHT),%d4 /* we're not scrolling the top row! */ + mulul %d4,%d6 /* scan line bytes x num scan lines */ + divul #32,%d6 /* we'll move 8 longs at a time */ + subq #1,%d6 + +console_scroll_loop: + movel %a2@+,%a1@+ + movel %a2@+,%a1@+ + movel %a2@+,%a1@+ + movel %a2@+,%a1@+ + movel %a2@+,%a1@+ + movel %a2@+,%a1@+ + movel %a2@+,%a1@+ + movel %a2@+,%a1@+ + dbra %d6,console_scroll_loop + + lea %pc@(L(mac_rowbytes)),%a0 + movel %a0@,%d6 + movel %pc@(L(console_font)),%a0 + mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d6 /* scan line bytes x font height */ + divul #32,%d6 /* we'll move 8 words at a time */ + subq #1,%d6 + + moveq #-1,%d0 +console_scroll_clear_loop: + movel %d0,%a1@+ + movel %d0,%a1@+ + movel %d0,%a1@+ + movel %d0,%a1@+ + movel %d0,%a1@+ + movel %d0,%a1@+ + movel %d0,%a1@+ + movel %d0,%a1@+ + dbra %d6,console_scroll_clear_loop + + moveml %sp@+,%a0-%a4/%d0-%d7 rts + +func_start console_putc,%a0/%a1/%d0-%d7 + + is_not_mac(console_exit) + + /* Output character in d7 on console. + */ + movel ARG1,%d7 + cmpib #'\n',%d7 + jbne 1f + + /* A little safe recursion is good for the soul */ + console_putc #'\r' +1: + lea %pc@(L(console_globals)),%a0 + + cmpib #10,%d7 + jne console_not_lf + movel %a0@(Lconsole_struct_cur_row),%d0 + addil #1,%d0 + movel %d0,%a0@(Lconsole_struct_cur_row) + movel %a0@(Lconsole_struct_num_rows),%d1 + cmpl %d1,%d0 + jcs 1f + subil #1,%d0 + movel %d0,%a0@(Lconsole_struct_cur_row) + jbsr console_scroll +1: + jra console_exit + +console_not_lf: + cmpib #13,%d7 + jne console_not_cr + clrl %a0@(Lconsole_struct_cur_column) + jra console_exit + +console_not_cr: + cmpib #1,%d7 + jne console_not_home + clrl %a0@(Lconsole_struct_cur_row) + clrl %a0@(Lconsole_struct_cur_column) + jra console_exit + /* - * Output number in d7 in hex notation on serial port. + * At this point we know that the %d7 character is going to be + * rendered on the screen. Register usage is - + * a0 = pointer to console globals + * a1 = font data + * d0 = cursor column + * d1 = cursor row to draw the character + * d7 = character number */ +console_not_home: + movel %a0@(Lconsole_struct_cur_column),%d0 + addil #1,%a0@(Lconsole_struct_cur_column) + movel %a0@(Lconsole_struct_num_columns),%d1 + cmpl %d1,%d0 + jcs 1f + putc '\n' /* recursion is OK! */ +1: + movel %a0@(Lconsole_struct_cur_row),%d1 -Lserial_putnum: - moveml %d0-%d2/%d7,%sp@- - movel %d7,%d1 - moveq #4,%d0 - moveq #7,%d2 -L1: roll %d0,%d1 - moveb %d1,%d7 - andb #0x0f,%d7 - cmpb #0x0a,%d7 - jcc 1f - addb #'0',%d7 - jra 2f -1: addb #'A'-10,%d7 -2: jbsr Lserial_putc - dbra %d2,L1 - moveq #32,%d7 - jbsr Lserial_putc - moveml %sp@+,%d0-%d2/%d7 + /* + * At this point we make a shift in register usage + * a0 = address of pointer to font data (fbcon_font_desc) + */ + movel %pc@(L(console_font)),%a0 + movel %a0@(FBCON_FONT_DESC_DATA),%a1 /* Load fbcon_font_desc.data into a1 */ + andl #0x000000ff,%d7 + /* ASSERT: a0 = contents of Lconsole_font */ + mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */ + addl %d7,%a1 /* a1 = points to char image */ + + /* + * At this point we make a shift in register usage + * d0 = pixel coordinate, x + * d1 = pixel coordinate, y + * d2 = (bit 0) 1/0 for white/black (!) pixel on screen + * d3 = font scan line data (8 pixels) + * d6 = count down for the font's pixel width (8) + * d7 = count down for the font's pixel count in height + */ + /* ASSERT: a0 = contents of Lconsole_font */ + mulul %a0@(FBCON_FONT_DESC_WIDTH),%d0 + mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 + movel %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* Load fbcon_font_desc.height into d7 */ + subq #1,%d7 +console_read_char_scanline: + moveb %a1@+,%d3 + + /* ASSERT: a0 = contents of Lconsole_font */ + movel %a0@(FBCON_FONT_DESC_WIDTH),%d6 /* Load fbcon_font_desc.width into d6 */ + subql #1,%d6 + +console_do_font_scanline: + lslb #1,%d3 + scsb %d2 /* convert 1 bit into a byte */ + jbsr console_plot_pixel + addq #1,%d0 + dbra %d6,console_do_font_scanline + + /* ASSERT: a0 = contents of Lconsole_font */ + subl %a0@(FBCON_FONT_DESC_WIDTH),%d0 + addq #1,%d1 + dbra %d7,console_read_char_scanline + +console_exit: + +func_return console_putc + +console_plot_pixel: + /* + * Input: + * d0 = x coordinate + * d1 = y coordinate + * d2 = (bit 0) 1/0 for white/black (!) + * All registers are preserved + */ + moveml %a0-%a1/%d0-%d4,%sp@- + + lea %pc@(L(mac_videobase)),%a0 + movel %a0@,%a1 + lea %pc@(L(mac_videodepth)),%a0 + movel %a0@,%d3 + lea %pc@(L(mac_rowbytes)),%a0 + mulul %a0@,%d1 + + /* + * Register usage: + * d0 = x coord becomes byte offset into frame buffer + * d1 = y coord + * d2 = black or white (0/1) + * d3 = video depth + * d4 = temp of x (d0) for many bit depths + * d5 = unused + * d6 = unused + * d7 = unused + */ +test_1bit: + cmpb #1,%d3 + jbne test_2bit + movel %d0,%d4 /* we need the low order 3 bits! */ + divul #8,%d0 + addal %d0,%a1 + addal %d1,%a1 + andb #7,%d4 + eorb #7,%d4 /* reverse the x-coordinate w/ screen-bit # */ + andb #1,%d2 + jbne white_1 + bsetb %d4,%a1@ + jbra console_plot_pixel_exit +white_1: + bclrb %d4,%a1@ + jbra console_plot_pixel_exit + +test_2bit: + cmpb #2,%d3 + jbne test_4bit + movel %d0,%d4 /* we need the low order 2 bits! */ + divul #4,%d0 + addal %d0,%a1 + addal %d1,%a1 + andb #3,%d4 + eorb #3,%d4 /* reverse the x-coordinate w/ screen-bit # */ + lsll #1,%d4 /* ! */ + andb #1,%d2 + jbne white_2 + bsetb %d4,%a1@ + addq #1,%d4 + bsetb %d4,%a1@ + jbra console_plot_pixel_exit +white_2: + bclrb %d4,%a1@ + addq #1,%d4 + bclrb %d4,%a1@ + jbra console_plot_pixel_exit + +test_4bit: + cmpb #4,%d3 + jbne test_8bit + movel %d0,%d4 /* we need the low order bit! */ + divul #2,%d0 + addal %d0,%a1 + addal %d1,%a1 + andb #1,%d4 + eorb #1,%d4 + lsll #2,%d4 /* ! */ + andb #1,%d2 + jbne white_4 + bsetb %d4,%a1@ + addq #1,%d4 + bsetb %d4,%a1@ + addq #1,%d4 + bsetb %d4,%a1@ + addq #1,%d4 + bsetb %d4,%a1@ + jbra console_plot_pixel_exit +white_4: + bclrb %d4,%a1@ + addq #1,%d4 + bclrb %d4,%a1@ + addq #1,%d4 + bclrb %d4,%a1@ + addq #1,%d4 + bclrb %d4,%a1@ + jbra console_plot_pixel_exit + +test_8bit: + cmpb #8,%d3 + jbne test_16bit + addal %d0,%a1 + addal %d1,%a1 + andb #1,%d2 + jbne white_8 + moveb #0xff,%a1@ + jbra console_plot_pixel_exit +white_8: + clrb %a1@ + jbra console_plot_pixel_exit + +test_16bit: + cmpb #16,%d3 + jbne console_plot_pixel_exit + addal %d0,%a1 + addal %d0,%a1 + addal %d1,%a1 + andb #1,%d2 + jbne white_16 + clrw %a1@ + jbra console_plot_pixel_exit +white_16: + movew #0x0fff,%a1@ + jbra console_plot_pixel_exit + +console_plot_pixel_exit: + moveml %sp@+,%a0-%a1/%d0-%d4 rts +#endif /* CONSOLE */ #if 0 -Lshowtest: +/* + * This is some old code lying around. I don't believe + * it's used or important anymore. My guess is it contributed + * to getting to this point, but it's done for now. + * It was still in the 2.1.77 head.S, so it's still here. + * (And still not used!) + */ +L(showtest): moveml %a0/%d7,%sp@- - putc('A') - putc('=') - putn(%a1) + puts "A=" + putn %a1 - ptestr #5,%a1@,#7,%a0 + .long 0xf0119f15 | ptestr #5,%a1@,#7,%a0 - putc('D') - putc('A') - putc('=') - putn(%a0) + puts "DA=" + putn %a0 - putc('D') - putc('=') - putn(%a0@) + puts "D=" + putn %a0@ - putc('S') - putc('=') - lea %pc@(Lmmu),%a0 - pmove %psr,%a0@ + puts "S=" + lea %pc@(L(mmu)),%a0 + .long 0xf0106200 | pmove %psr,%a0@ clrl %d7 movew %a0@,%d7 - jbsr Lserial_putnum + putn %d7 - putr() + putc '\n' moveml %sp@+,%a0/%d7 rts +#endif /* 0 */ + +__INITDATA + .align 4 + +#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA) || defined(CONFIG_HP300) +L(custom): +L(iobase): + .long 0 +#endif + +#ifdef CONFIG_MAC +L(console_video_virtual): + .long 0 +#endif /* CONFIG_MAC */ + +#if defined(CONSOLE) +L(console_globals): + .long 0 /* cursor column */ + .long 0 /* cursor row */ + .long 0 /* max num columns */ + .long 0 /* max num rows */ + .long 0 /* left edge */ + .long 0 /* mac putc */ +L(console_font): + .long 0 /* pointer to console font (struct fbcon_font_desc) */ +#endif /* CONSOLE */ + +#if defined(MMU_PRINT) +L(mmu_print_data): + .long 0 /* valid flag */ + .long 0 /* start logical */ + .long 0 /* next logical */ + .long 0 /* start physical */ + .long 0 /* next physical */ +#endif /* MMU_PRINT */ + +L(cputype): + .long 0 +L(mmu_cached_pointer_tables): + .long 0 +L(mmu_num_pointer_tables): + .long 0 +L(phys_kernel_start): + .long 0 +L(kernel_end): + .long 0 +L(memory_start): + .long 0 +L(kernel_pgdir_ptr): + .long 0 +L(temp_mmap_mem): + .long 0 + + +#if defined (CONFIG_BVME6000) +BVME_SCC_CTRL_A = 0xffb0000b +BVME_SCC_DATA_A = 0xffb0000f +#endif + +#if defined(CONFIG_MAC) +L(mac_booter_data): + .long 0 +L(mac_videobase): + .long 0 +L(mac_videodepth): + .long 0 +L(mac_dimensions): + .long 0 +L(mac_rowbytes): + .long 0 +#ifdef MAC_SERIAL_DEBUG +L(mac_sccbase): + .long 0 +#endif /* MAC_SERIAL_DEBUG */ #endif + +__FINIT .data - .even -Lcustom: -Liobase: - .long 0 -Lmmu: .quad 0 -SYMBOL_NAME_LABEL(kpt) - .long 0 + .align 4 + SYMBOL_NAME_LABEL(availmem) - .long 0 + .long 0 SYMBOL_NAME_LABEL(m68k_pgtable_cachemode) - .long 0 -#ifdef CONFIG_060_WRITETHROUGH + .long 0 SYMBOL_NAME_LABEL(m68k_supervisor_cachemode) - .long 0 -#endif + .long 0 #if defined(CONFIG_MVME16x) SYMBOL_NAME_LABEL(mvme_bdid_ptr) - .long 0 + .long 0 #endif |