/* SPDX-License-Identifier: GPL-2.0-or-later
* * - * - mode : asm - * -
* *
* * head . S - - This file contains the initial boot code for the
* * Linux / 68 k kernel .
* *
* * Copyright 1993 by Hamish Macdonald
* *
* * 68040 fixes by Michael Rausch
* * 68060 fixes by Roman Hodek
* * MMU cleanup by Randy Thelen
* * Final MMU cleanup by Roman Zippel
* *
* * Atari support by Andreas Schwab , using ideas of Robert de Vries
* * and Bjoern Brauel
* * VME Support by Richard Hirst
* *
* * 94 / 11 / 14 Andreas Schwab : put kernel at PAGESIZE
* * 94 / 11 / 18 Andreas Schwab : remove identity mapping of STRAM for Atari
* * + + Bjoern & Roman : ATARI - 68040 support for the Medusa
* * 95 / 11 / 18 Richard Hirst : Added MVME166 support
* * 96 / 04 / 26 Guenther Kelleter : fixed identity mapping for Falcon with
* * Magnum - and FX - alternate ram
* * 98 / 04 / 25 Phil Blundell : added HP300 support
* * 1998 / 08 / 30 David Kilzer : Added support for font_desc structures
* * for linux - 2 . 1 . 115
* * 1999 / 02 / 11 Richard Zidlicky : added Q40 support ( initial version 99 / 01 / 01 )
* * 2004 / 05 / 13 Kars de Jong : Finalised HP300 support
*/
/*
* Linux startup code .
*
* At this point , the boot loader has :
* Disabled interrupts
* Disabled caches
* Put us in supervisor state .
*
* The kernel setup code takes the following steps :
* . Raise interrupt level
* . Set up initial kernel memory mapping .
* . This sets up a mapping of the 4 M 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 exhaustive
* 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 propagate 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 4 MB 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 quite 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
* position 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 / # 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 8 x8 font or an 8 x16 ( widthxheight ) . I prefer the 8 x8 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 available 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 autoconf . h .
*
* CONSOLE_DEBUG : Only supports a Mac frame buffer but could easily be
* extended 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 .
*
* 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 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_USE_SCC_A : Use SCC port A ( modem ) for serial debug .
* MAC_USE_SCC_B : Use SCC port B ( printer ) for serial debug .
*/
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/pgtable.h>
#include <asm/bootinfo.h>
#include <asm/bootinfo-amiga.h>
#include <asm/bootinfo-atari.h>
#include <asm/bootinfo-hp300.h>
#include <asm/bootinfo-mac.h>
#include <asm/bootinfo-q40.h>
#include <asm/bootinfo-virt.h>
#include <asm/bootinfo-vme.h>
#include <asm/setup.h>
#include <asm/entry.h>
#include <asm/page.h>
#include <asm/asm-offsets.h>
#ifdef CONFIG_MAC
# include <asm/machw.h>
#endif
#ifdef CONFIG_EARLY_PRINTK
# define SERIAL_DEBUG
# if defined(CONFIG_MAC) && defined(CONFIG_FONT_SUPPORT)
# define CONSOLE_DEBUG
# endif
#endif
#undef MMU_PRINT
#undef MMU_NOCACHE_KERNEL
#undef DEBUG
/*
* For the head . S console , there are three supported fonts , 6 x11 , 8 x16 and 8 x8 .
* The 8 x8 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 kernel_pg_dir
.globl availmem
.globl m68k_init_mapped_size
.globl m68k_pgtable_cachemode
.globl m68k_supervisor_cachemode
#ifdef CONFIG_MVME16x
.globl mvme_bdid
#endif
#ifdef CONFIG_Q40
.globl q40_mem_cptr
#endif
CPUTYPE_040 = 1 /* indicates an 040 */
CPUTYPE_060 = 2 /* indicates an 060 */
CPUTYPE_0460 = 3 /* if either above are set, this is set */
CPUTYPE_020 = 4 /* indicates an 020 */
/* Translation control register */
TC_ENABLE = 0 x8000
TC_PAGE8K = 0 x4000
TC_PAGE4K = 0 x0000
/* Transparent translation registers */
TTR_ENABLE = 0 x8000 /* enable transparent translation */
TTR_ANYMODE = 0 x4000 /* user and kernel mode access */
TTR_KERNELMODE = 0 x2000 /* only kernel mode access */
TTR_USERMODE = 0 x0000 /* only user mode access */
TTR_CI = 0 x0400 /* inhibit cache */
TTR_RW = 0 x0200 /* read/write mode */
TTR_RWM = 0 x0100 /* read/write mask */
TTR_FCB2 = 0 x0040 /* function code base bit 2 */
TTR_FCB1 = 0 x0020 /* function code base bit 1 */
TTR_FCB0 = 0 x0010 /* function code base bit 0 */
TTR_FCM2 = 0 x0004 /* function code mask bit 2 */
TTR_FCM1 = 0 x0002 /* function code mask bit 1 */
TTR_FCM0 = 0 x0001 /* function code mask bit 0 */
/* Cache Control registers */
CC6_ENABLE_D = 0 x80000000 /* enable data cache (680[46]0) */
CC6_FREEZE_D = 0 x40000000 /* freeze data cache (68060) */
CC6_ENABLE_SB = 0 x20000000 /* enable store buffer (68060) */
CC6_PUSH_DPI = 0 x10000000 /* disable CPUSH invalidation (68060) */
CC6_HALF_D = 0 x08000000 /* half-cache mode for data cache (68060) */
CC6_ENABLE_B = 0 x00800000 /* enable branch cache (68060) */
CC6_CLRA_B = 0 x00400000 /* clear all entries in branch cache (68060) */
CC6_CLRU_B = 0 x00200000 /* clear user entries in branch cache (68060) */
CC6_ENABLE_I = 0 x00008000 /* enable instruction cache (680[46]0) */
CC6_FREEZE_I = 0 x00004000 /* freeze instruction cache (68060) */
CC6_HALF_I = 0 x00002000 /* half-cache mode for instruction cache (68060) */
CC3_ALLOC_WRITE = 0 x00002000 /* write allocate mode(68030) */
CC3_ENABLE_DB = 0 x00001000 /* enable data burst (68030) */
CC3_CLR_D = 0 x00000800 /* clear data cache (68030) */
CC3_CLRE_D = 0 x00000400 /* clear entry in data cache (68030) */
CC3_FREEZE_D = 0 x00000200 /* freeze data cache (68030) */
CC3_ENABLE_D = 0 x00000100 /* enable data cache (68030) */
CC3_ENABLE_IB = 0 x00000010 /* enable instruction burst (68030) */
CC3_CLR_I = 0 x00000008 /* clear instruction cache (68030) */
CC3_CLRE_I = 0 x00000004 /* clear entry in instruction cache (68030) */
CC3_FREEZE_I = 0 x00000002 /* freeze instruction cache (68030) */
CC3_ENABLE_I = 0 x00000001 /* enable instruction cache (68030) */
/* Miscellaneous definitions */
PAGESIZE = 4096
PAGESHIFT = 12
ROOT_TABLE_SIZE = 128
PTR_TABLE_SIZE = 128
PAGE_TABLE_SIZE = 64
ROOT_INDEX_SHIFT = 25
PTR_INDEX_SHIFT = 18
PAGE_INDEX_SHIFT = 12
#ifdef DEBUG
/* When debugging use readable names for labels */
#ifdef __STDC__
#define L(name) .head.S.##name
#else
#define L(name) .head.S./**/name
#endif
#else
#ifdef __STDC__
#define L(name) .L##name
#else
#define L(name) .L/**/name
#endif
#endif
/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */
#ifndef __INITDATA
#define __INITDATA .data
#define __FINIT .previous
#endif
/* Several macros to make the writing of subroutines easier:
* - func_start marks the beginning of the routine which setups the frame
* register and saves the registers , it also defines another macro
* to automatically restore the registers again .
* - func_return marks the end of the routine and simply calls the prepared
* macro to restore registers and jump back to the caller .
* - func_define generates another macro to automatically put arguments
* onto the stack call the subroutine and cleanup the stack again .
*/
/* Within subroutines these macros can be used to access the arguments
* on the stack . With STACK some allocated memory on the stack can be
* accessed and ARG0 points to the return address ( used by mmu_engage ) .
*/
#define STACK %a6@(stackstart)
#define ARG0 %a6@(4 )
#define ARG1 %a6@(8 )
#define ARG2 %a6@(12 )
#define ARG3 %a6@(16 )
#define ARG4 %a6@(20 )
.macro func_start name,saveregs,stack=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
#if defined(CONFIG_HP300) || defined(CONFIG_APOLLO)
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
func_define console_init
func_define console_put_penguin
func_define console_plot_pixel,3
func_define console_scroll
.macro putc ch
#if defined(CONSOLE_DEBUG) || defined(SERIAL_DEBUG)
pea \ch
#endif
#ifdef CONSOLE_DEBUG
func_call console_putc
#endif
#ifdef SERIAL_DEBUG
func_call serial_putc
#endif
#if defined(CONSOLE_DEBUG) || 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_DEBUG) || defined(SERIAL_DEBUG)
__INITDATA
.Lstr\@:
.string "\string"
__FINIT
pea %pc@(.Lstr\@)
func_call puts
addql #4 ,%sp
#endif
.endm
.macro dputs string
#ifdef DEBUG
puts "\string"
#endif
.endm
#define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab
#define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab
#define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab
#define is_not_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jne lab
#define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab
#define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab
#define is_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jeq lab
#define is_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jeq lab
#define is_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jeq lab
#define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab
#define is_not_apollo(lab) cmpl &MACH_APOLLO,%pc@(m68k_machtype); jne lab
#define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab
#define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab
#define is_not_virt(lab) cmpl &MACH_VIRT,%pc@(m68k_machtype); jne lab
#define hasnt_leds(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); \
jeq 42 f; \
cmpl &MACH_APOLLO,%pc@(m68k_machtype); \
jne lab ;\
42 :\
#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
#if defined(CONFIG_HP300) || defined(CONFIG_APOLLO)
hasnt_leds(.Lled\@)
pea \mask
func_call set_leds
addql #4 ,%sp
.Lled\@:
#endif
.endm
__HEAD
ENTRY(_stext)
/*
* Version numbers of the bootinfo interface
* The area from _ stext to _ start will later be used as kernel pointer table
*/
bras 1 f /* Jump over bootinfo version numbers */
.long BOOTINFOV_MAGIC
.long MACH_AMIGA, AMIGA_BOOTI_VERSION
.long MACH_ATARI, ATARI_BOOTI_VERSION
.long MACH_MVME147, MVME147_BOOTI_VERSION
.long MACH_MVME16x, MVME16x_BOOTI_VERSION
.long MACH_BVME6000, BVME6000_BOOTI_VERSION
.long MACH_MAC, MAC_BOOTI_VERSION
.long MACH_Q40, Q40_BOOTI_VERSION
.long MACH_HP300, HP300_BOOTI_VERSION
.long 0
1 : jra __start
.equ kernel_pg_dir,_stext
.equ .,_stext+PAGESIZE
ENTRY(_start)
jra __start
__INIT
ENTRY(__start)
/*
* Setup initial stack pointer
*/
lea %pc@(_stext),%sp
/*
* Record the CPU and machine type .
*/
get_bi_record BI_MACHTYPE
lea %pc@(m68k_machtype),%a1
movel %a0@,%a1@
get_bi_record BI_FPUTYPE
lea %pc@(m68k_fputype),%a1
movel %a0@,%a1@
get_bi_record BI_MMUTYPE
lea %pc@(m68k_mmutype),%a1
movel %a0@,%a1@
get_bi_record BI_CPUTYPE
lea %pc@(m68k_cputype),%a1
movel %a0@,%a1@
leds 0 x1
#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@
get_bi_record BI_MAC_SCCBASE
lea %pc@(L(mac_sccbase)),%a1
movel %a0@,%a1@
L(test_notmac):
#endif /* CONFIG_MAC */
#ifdef CONFIG_VIRT
is_not_virt(L(test_notvirt))
get_bi_record BI_VIRT_GF_TTY_BASE
lea %pc@(L(virt_gf_tty_base)),%a1
movel %a0@,%a1@
L(test_notvirt):
#endif /* CONFIG_VIRT */
/*
* 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@(m68k_cputype),%d0
/*
* Assume it ' s an 030
*/
clrl %d1
/*
* Test the BootInfo cputype for 060
*/
btst #CPUB_68060,%d0
jeq 1 f
bset #CPUTYPE_060,%d1
bset #CPUTYPE_0460,%d1
jra 3 f
1 :
/*
* Test the BootInfo cputype for 040
*/
btst #CPUB_68040,%d0
jeq 2 f
bset #CPUTYPE_040,%d1
bset #CPUTYPE_0460,%d1
jra 3 f
2 :
/*
* Test the BootInfo cputype for 020
*/
btst #CPUB_68020,%d0
jeq 3 f
bset #CPUTYPE_020,%d1
jra 3 f
3 :
/*
* Record the cpu type
*/
lea %pc@(L(cputype)),%a0
movel %d1,%a0@
/*
* 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 .
*/
is_not_060(1 f)
movel #_PAGE_CACHE040W,%d0
jra L(save_cachetype)
#endif /* CONFIG_060_WRITETHROUGH */
1 :
movew #_PAGE_CACHE040,%d0
movel #_PAGE_CACHE040W,%d1
L(save_cachetype):
/* Save cache mode for supervisor mode and page tables
*/
lea %pc@(m68k_supervisor_cachemode),%a0
movel %d0,%a0@
lea %pc@(m68k_pgtable_cachemode),%a0
movel %d1,%a0@
/*
* raise interrupt level
*/
movew #0 x2700,%sr
/*
If running on an Atari , determine the I / O base of the
serial port and test if we are running on a Medusa or Hades .
This test is necessary here , because on the Hades the serial
port is only accessible in the high I / O memory area .
The test whether it is a Medusa is done by writing to the byte at
phys . 0 x0 . This should result in a bus error on all other machines .
. . . should , but doesn ' t . The Afterburner040 for the Falcon has the
same behaviour ( 0 x0 . . 0 x7 are no ROM shadow ) . So we have to do
another test to distinguish Medusa and AB040 . This is a
read attempt for 0 x00ff82fe phys . that should bus error on a Falcon
( + AB040 ) , but is in the range where the Medusa always asserts DTACK .
The test for the Hades is done by reading address 0 xb0000000 . This
should give a bus error on the Medusa .
*/
#ifdef CONFIG_ATARI
is_not_atari(L(notypetest))
/* get special machine type (Medusa/Hades/AB40) */
moveq #0 ,%d3 /* default if tag doesn't exist */
get_bi_record BI_ATARI_MCH_TYPE
tstl %d0
jbmi 1 f
movel %a0@,%d3
lea %pc@(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 1 f
movel #0 xff000000,%d0 /* Hades I/O base addr: 0xff000000 */
1 : lea %pc@(L(iobase)),%a0
movel %d0,%a0@
L(notypetest):
#endif
#ifdef CONFIG_VME
is_mvme147(L(getvmetype))
is_bvme6000(L(getvmetype))
is_not_mvme16x(L(gvtdone))
/* See if the loader has specified the BI_VME_TYPE tag. Recent
* versions of VMELILO and TFTPLILO do this . We have to do this
* early so we know how to handle console output . If the tag
* doesn ' t exist then we use the Bug for output on MVME16x .
*/
L(getvmetype):
get_bi_record BI_VME_TYPE
tstl %d0
jbmi 1 f
movel %a0@,%d3
lea %pc@(vme_brdtype),%a0
movel %d3,%a0@
1 :
#ifdef CONFIG_MVME16x
is_not_mvme16x(L(gvtdone))
/* Need to get the BRD_ID info to differentiate between 162, 167,
* etc . This is available as a BI_VME_BRDINFO tag with later
* versions of VMELILO and TFTPLILO , otherwise we call the Bug .
*/
get_bi_record BI_VME_BRDINFO
tstl %d0
jpl 1 f
/* Get pointer to board ID data from Bug */
movel %d2,%sp@-
trap #15
.word 0 x70 /* trap 0x70 - .BRD_ID */
movel %sp@+,%a0
1 :
lea %pc@(mvme_bdid),%a1
/* Structure is 32 bytes long */
movel %a0@+,%a1@+
movel %a0@+,%a1@+
movel %a0@+,%a1@+
movel %a0@+,%a1@+
movel %a0@+,%a1@+
movel %a0@+,%a1@+
movel %a0@+,%a1@+
movel %a0@+,%a1@+
#endif
L(gvtdone):
#endif
#ifdef CONFIG_HP300
is_not_hp300(L(nothp))
/* Get the address of the UART for serial debugging */
get_bi_record BI_HP300_UART_ADDR
tstl %d0
jbmi 1 f
movel %a0@,%d3
lea %pc@(L(uartbase)),%a0
movel %d3,%a0@
get_bi_record BI_HP300_UART_SCODE
tstl %d0
jbmi 1 f
movel %a0@,%d3
lea %pc@(L(uart_scode)),%a0
movel %d3,%a0@
1 :
L(nothp):
#endif
/*
* Initialize serial port
*/
jbsr L(serial_init)
/*
* Initialize console
*/
#ifdef CONFIG_MAC
is_not_mac(L(nocon))
# ifdef CONSOLE_DEBUG
console_init
# ifdef CONFIG_LOGO
console_put_penguin
# endif /* CONFIG_LOGO */
# endif /* CONSOLE_DEBUG */
L(nocon):
#endif /* CONFIG_MAC */
putc '\n'
putc 'A'
leds 0 x2
dputn %pc@(L(cputype))
dputn %pc@(m68k_supervisor_cachemode)
dputn %pc@(m68k_pgtable_cachemode)
dputc '\n'
/*
* Save physical start address of kernel
*/
lea %pc@(L(phys_kernel_start)),%a0
lea %pc@(_stext),%a1
subl #_stext,%a1
addl #PAGE_OFFSET,%a1
movel %a1,%a0@
putc 'B'
leds 0 x4
/*
* 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 , 8 , or 16 MB of kernel code & data
*/
get_bi_record BI_MEMCHUNK
movel %a0@(4 ),%d0
movel #16 *1024 *1024 ,%d1
cmpl %d0,%d1
jls 1 f
lsrl #1 ,%d1
cmpl %d0,%d1
jls 1 f
lsrl #1 ,%d1
1 :
lea %pc@(m68k_init_mapped_size),%a0
movel %d1,%a0@
mmu_map #PAGE_OFFSET,%pc@(L(phys_kernel_start)),%d1,\
%pc@(m68k_supervisor_cachemode)
putc 'C'
#ifdef CONFIG_AMIGA
L(mmu_init_amiga):
is_not_amiga(L(mmu_init_not_amiga))
/*
* mmu_init_amiga
*/
putc 'D'
is_not_040_or_060(1 f)
/*
* 040 : Map the 16 Meg range physical 0 x0 up to logical 0 x8000 . 0000
*/
mmu_map #0 x80000000,#0 ,#0 x01000000,#_PAGE_NOCACHE_S
/*
* Map the Zorro III I / O space with transparent translation
* for frame buffer memory etc .
*/
mmu_map_tt #1 ,#0 x40000000,#0 x20000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
1 :
/*
* 030 : Map the 32 Meg range physical 0 x0 up to logical 0 x8000 . 0000
*/
mmu_map #0 x80000000,#0 ,#0 x02000000,#_PAGE_NOCACHE030
mmu_map_tt #1 ,#0 x40000000,#0 x20000000,#_PAGE_NOCACHE030
jbra L(mmu_init_done)
L(mmu_init_not_amiga):
#endif
#ifdef CONFIG_ATARI
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 .
0 xffxxxxxx - > 0 x00xxxxxx ) . For this , an additional pointer table is
needed . I / O ranges are marked non - cachable .
For the Medusa it is better to map the I / O region transparently
( i . e . 0 xffxxxxxx - > 0 xffxxxxxx ) , because some I / O registers are
accessible only in the high area .
On the Hades all I / O registers are only accessible in the high
area .
*/
/* I/O base addr for non-Medusa, non-Hades: 0x00000000 */
moveq #0 ,%d0
movel %pc@(atari_mch_type),%d3
cmpl #ATARI_MACH_MEDUSA,%d3
jbeq 2 f
cmpl #ATARI_MACH_HADES,%d3
jbne 1 f
2 : movel #0 xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */
1 : movel %d0,%d3
is_040_or_060(L(spata68040))
/* Map everything non-cacheable, though not all parts really
* need to disable caches ( crucial only for 0 xff8000 . . 0 xffffff
* ( standard I / O ) and 0 xf00000 . . 0 xf3ffff ( IDE ) ) . The remainder
* isn ' t really used , except for sometimes peeking into the
* ROMs ( mirror at phys . 0 x0 ) , so caching isn ' t necessary for
* this. */
mmu_map #0 xff000000,%d3,#0 x01000000,#_PAGE_NOCACHE030
jbra L(mmu_init_done)
L(spata68040):
mmu_map #0 xff000000,%d3,#0 x01000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
L(mmu_init_not_atari):
#endif
#ifdef CONFIG_Q40
is_not_q40(L(notq40))
/*
* add transparent mapping for 0 xff00 0000 - 0 xffff ffff
* non - cached serialized etc . .
* this includes master chip , DAC , RTC and ISA ports
* 0 xfe000000 - 0 xfeffffff is for screen and ROM
*/
putc 'Q'
mmu_map_tt #0 ,#0 xfe000000,#0 x01000000,#_PAGE_CACHE040W
mmu_map_tt #1 ,#0 xff000000,#0 x01000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
L(notq40):
#endif
#ifdef CONFIG_HP300
is_not_hp300(L(nothp300))
/* On the HP300, we map the ROM, INTIO and DIO regions (phys. 0x00xxxxxx)
* by mapping 32 MB ( on 020 / 030 ) or 16 MB ( on 040 ) from 0 xf0xxxxxx - > 0 x00xxxxxx ) .
* The ROM mapping is needed because the LEDs are mapped there too .
*/
is_040(1 f)
/*
* 030 : Map the 32 Meg range physical 0 x0 up to logical 0 xf000 . 0000
*/
mmu_map #0 xf0000000,#0 ,#0 x02000000,#_PAGE_NOCACHE030
jbra L(mmu_init_done)
1 :
/*
* 040 : Map the 16 Meg range physical 0 x0 up to logical 0 xf000 . 0000
*/
mmu_map #0 xf0000000,#0 ,#0 x01000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
L(nothp300):
#endif /* CONFIG_HP300 */
#ifdef CONFIG_MVME147
is_not_mvme147(L(not147))
/*
* On MVME147 we have already created kernel page tables for
* 4 MB of RAM at address 0 , so now need to do a transparent
* mapping of the top of memory space . Make it 0 . 5 GByte for now ,
* so we can access on - board i / o areas .
*/
mmu_map_tt #1 ,#0 xe0000000,#0 x20000000,#_PAGE_NOCACHE030
jbra L(mmu_init_done)
L(not147):
#endif /* CONFIG_MVME147 */
#ifdef CONFIG_MVME16x
is_not_mvme16x(L(not16x))
/*
* On MVME16x we have already created kernel page tables for
* 4 MB of RAM at address 0 , so now need to do a transparent
* mapping of the top of memory space . Make it 0 . 5 GByte 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 167 Bug to run .
* IO is in the range 0 xfff00000 to 0 xfffeffff .
* PROM is 0 xff800000 - > 0 xffbfffff and SRAM is
* 0 xffe00000 - > 0 xffe1ffff .
*/
mmu_map_tt #1 ,#0 xe0000000,#0 x20000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
L(not16x):
#endif /* CONFIG_MVME162 | CONFIG_MVME167 */
#ifdef CONFIG_BVME6000
is_not_bvme6000(L(not6000))
/*
* On BVME6000 we have already created kernel page tables for
* 4 MB of RAM at address 0 , so now need to do a transparent
* mapping of the top of memory space . Make it 0 . 5 GByte 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 .
*/
mmu_map_tt #1 ,#0 xe0000000,#0 x20000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
L(not6000):
#endif /* CONFIG_BVME6000 */
/*
* mmu_init_mac
*
* The Macintosh mappings are less clear .
*
* 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
* 0 x5000 . 0000 . . . 0 x5300 . 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
* 0 x0000 . 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 0 x0000 . 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 . )
*/
#ifdef CONFIG_MAC
L(mmu_init_mac):
is_not_mac(L(mmu_init_not_mac))
putc 'F'
is_not_040_or_060(1 f)
moveq #_PAGE_NOCACHE_S,%d3
jbra 2 f
1 :
moveq #_PAGE_NOCACHE030,%d3
2 :
/*
* Mac Note : screen address of logical 0 xF000 . 0000 - > < screen physical >
* we simply map the 4 MB that contains the videomem
*/
movel #VIDEOMEMMASK,%d0
andl %pc@(L(mac_videobase)),%d0
mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3
/* ROM from 4000 0000 to 4200 0000 (only for mac_reset()) */
mmu_map_eq #0 x40000000,#0 x02000000,%d3
/* IO devices (incl. serial port) from 5000 0000 to 5300 0000 */
mmu_map_eq #0 x50000000,#0 x03000000,%d3
/* Nubus slot space (video at 0xF0000000, rom at 0xF0F80000) */
mmu_map_tt #1 ,#0 xf8000000,#0 x08000000,%d3
jbra L(mmu_init_done)
L(mmu_init_not_mac):
#endif
#ifdef CONFIG_SUN3X
is_not_sun3x(L(notsun3x))
/* oh, the pain.. We're gonna want the prom code after
* starting the MMU , so we copy the mappings , translating
* from 8 k - > 4 k pages as we go .
*/
/* copy maps from 0xfee00000 to 0xff000000 */
movel #0 xfee00000, %d0
moveq #ROOT_INDEX_SHIFT, %d1
lsrl %d1,%d0
mmu_get_root_table_entry %d0
movel #0 xfee00000, %d0
moveq #PTR_INDEX_SHIFT, %d1
lsrl %d1,%d0
andl #PTR_TABLE_SIZE-1 , %d0
mmu_get_ptr_table_entry %a0,%d0
movel #0 xfee00000, %d0
moveq #PAGE_INDEX_SHIFT, %d1
lsrl %d1,%d0
andl #PAGE_TABLE_SIZE-1 , %d0
mmu_get_page_table_entry %a0,%d0
/* this is where the prom page table lives */
movel 0 xfefe00d4, %a1
movel %a1@, %a1
movel #((0 x200000 >> 13 )-1 ), %d1
1 :
movel %a1@+, %d3
movel %d3,%a0@+
addl #0 x1000,%d3
movel %d3,%a0@+
dbra %d1,1 b
/* setup tt1 for I/O */
mmu_map_tt #1 ,#0 x40000000,#0 x40000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
L(notsun3x):
#endif
#ifdef CONFIG_VIRT
is_not_virt(L(novirt))
mmu_map_tt #1 ,#0 xFF000000,#0 x01000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
L(novirt):
#endif
#ifdef CONFIG_APOLLO
is_not_apollo(L(notapollo))
putc 'P'
mmu_map #0 x80000000,#0 ,#0 x02000000,#_PAGE_NOCACHE030
L(notapollo):
jbra L(mmu_init_done)
#endif
L(mmu_init_done):
putc 'G'
leds 0 x8
/*
* 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 .
*/
L(mmu_fixup):
is_not_040_or_060(L(mmu_fixup_done))
#ifdef MMU_NOCACHE_KERNEL
jbra L(mmu_fixup_done)
#endif
/* first fix the page at the start of the kernel, that
* contains also kernel_pg_dir .
*/
movel %pc@(L(phys_kernel_start)),%d0
subl #PAGE_OFFSET,%d0
lea %pc@(_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 2 f
1 :
mmu_fixup_page_mmu_cache %a0
addw #PAGESIZE,%a0
2 :
cmpl %a0,%a1
jgt 1 b
L(mmu_fixup_done):
#ifdef MMU_PRINT
mmu_print
#endif
/*
* mmu_engage
*
* This chunk of code performs the gruesome task of engaging the MMU .
* The reason it ' s 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 . , 0 x01000 .
* B . The kernel is located some where else . e . g . , 0 x0400 . 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 0 x8000 . 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 0 x8000 . 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 256 K ) .
*
* 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 0 x01000 , 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 .
*
*
*/
putc 'H'
mmu_engage
/*
* After this point no new memory is allocated and
* the start of available memory is stored in availmem .
* ( The bootmem allocator requires now the physical address . )
*/
movel L(memory_start),availmem
#ifdef CONFIG_AMIGA
is_not_amiga(1 f)
/* fixup the Amiga custom register location before printing */
clrl L(custom)
1 :
#endif
#ifdef CONFIG_ATARI
is_not_atari(1 f)
/* fixup the Atari iobase register location before printing */
movel #0 xff000000,L(iobase)
1 :
#endif
#ifdef CONFIG_MAC
is_not_mac(1 f)
movel #~VIDEOMEMMASK,%d0
andl L(mac_videobase),%d0
addl #VIDEOMEMBASE,%d0
movel %d0,L(mac_videobase)
#ifdef CONSOLE_DEBUG
movel %pc@(L(phys_kernel_start)),%d0
subl #PAGE_OFFSET,%d0
subl %d0,L(console_font)
subl %d0,L(console_font_data)
#endif
orl #0 x50000000,L(mac_sccbase)
1 :
#endif
#ifdef CONFIG_HP300
is_not_hp300(2 f)
/*
* Fix up the iobase register to point to the new location of the LEDs .
*/
movel #0 xf0000000,L(iobase)
/*
* Energise the FPU and caches .
*/
is_040(1 f)
movel #0 x60,0 xf05f400c
jbra 2 f
/*
* 040 : slightly different , apparently .
*/
1 : movew #0 ,0 xf05f400e
movew #0 x64,0 xf05f400e
2 :
#endif
#ifdef CONFIG_SUN3X
is_not_sun3x(1 f)
/* enable copro */
oriw #0 x4000,0 x61000000
1 :
#endif
#ifdef CONFIG_APOLLO
is_not_apollo(1 f)
/*
* Fix up the iobase before printing
*/
movel #0 x80000000,L(iobase)
1 :
#endif
putc 'I'
leds 0 x10
/*
* Enable caches
*/
is_not_040_or_060(L(cache_not_680460))
L(cache680460):
.chip 68040
nop
cpusha %bc
nop
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 L(cache_done)
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 68 k
L(cache_done):
putc 'J'
/*
* Setup initial stack pointer
*/
lea init_task,%curptr
lea init_thread_union+THREAD_SIZE,%sp
putc 'K'
subl %a6,%a6 /* clear a6 for gdb */
/*
* The new 64 bit printf support requires an early exception initialization .
*/
jbsr base_trap_init
/* jump to the kernel start */
putc '\n'
leds 0 x55
jbsr start_kernel
/*
* Find a tag record in the bootinfo structure
* The bootinfo structure is located right after the kernel
* Returns : d0 : size ( - 1 if not found )
* a0 : data pointer ( end - of - records if not found )
*/
func_start get_bi_record,%d1
movel ARG1,%d0
lea %pc@(_end),%a0
1 : tstw %a0@(BIR_TAG)
jeq 3 f
cmpw %a0@(BIR_TAG),%d0
jeq 2 f
addw %a0@(BIR_SIZE),%a0
jra 1 b
2 : moveq #0 ,%d0
movew %a0@(BIR_SIZE),%d0
lea %a0@(BIR_DATA),%a0
jra 4 f
3 : moveq #-1 ,%d0
lea %a0@(BIR_SIZE),%a0
4 :
func_return get_bi_record
/*
* MMU Initialization Begins Here
*
* The structure of the MMU tables on the 68 k 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 32 Meg range of memory .
* If an entry is invalid then that logical range of 32 M 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 32 M range . On 020 / 030 class machines , a technique
* called " early terminating descriptors " are used . This technique
* allows an entire 32 Meg 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 32 M range .
* Not all of the 32 M 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 32 M . 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 4 K page
*
* The algorithms which follow 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 1 f; putc z; jbra 2 f; 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 1 b
2 : putn %d7
andil #0 xFFFFFE00,%d7
movel %d7,%a4
movel #PTR_TABLE_SIZE,%d4
putc ' '
3 : tstl %d4
jbeq 11 f
subq #1 ,%d4
movel %a4@+,%d7
btst #1 ,%d7
jbeq 3 b
4 : putn %d7
andil #0 xFFFFFF00,%d7
movel %d7,%a3
movel #PAGE_TABLE_SIZE,%d3
5 : movel #8 ,%d2
6 : tstl %d3
jbeq 31 f
subq #1 ,%d3
movel %a3@+,%d6
btst #0 ,%d6
jbeq 6 b
7 : tstl %d2
jbeq 8 f
subq #1 ,%d2
putc ' '
jbra 91 f
8 : putc '\n'
movel #8 +1 +8 +1 +1 ,%d2
9 : putc ' '
dbra %d2,9 b
movel #7 ,%d2
91 : putn %d6
jbra 6 b
31 : putc '\n'
movel #8 +1 ,%d2
32 : putc ' '
dbra %d2,32 b
jbra 3 b
11 : putc '\n'
jbra 1 b
#endif /* MMU 040 Dumping code that's gory and detailed */
lea %pc@(kernel_pg_dir),%a5
movel %a5,%a0 /* a0 has the address of the root table ptr */
movel #0 x00000000,%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 41 f
jbsr mmu_print_tuple_invalidate
jbra 48 f
41 :
movel #0 ,%d1
andil #0 xfffffe00,%d6
movel %d6,%a1
42 :
movel %a4,%d5
addil #PAGESIZE<<6 ,%d5
movel %a1@+,%d6
btst #1 ,%d6
jbne 43 f
jbsr mmu_print_tuple_invalidate
jbra 47 f
43 :
movel #0 ,%d2
andil #0 xffffff00,%d6
movel %d6,%a2
44 :
movel %a4,%d5
addil #PAGESIZE,%d5
movel %a2@+,%d6
btst #0 ,%d6
jbne 45 f
jbsr mmu_print_tuple_invalidate
jbra 46 f
45 :
moveml %d0-%d1,%sp@-
movel %a4,%d0
movel %d6,%d1
andil #0 xfffff4e0,%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 44 b
47 :
movel %d5,%a4
addq #1 ,%d1
cmpib #128 ,%d1
jbne 42 b
48 :
movel %d5,%a4 /* move to the next logical address */
addq #1 ,%d0
cmpib #128 ,%d0
jbne 40 b
.chip 68040
movec %dtt1,%d0
movel %d0,%d1
andiw #0 x8000,%d1 /* is it valid ? */
jbeq 1 f /* No, bail out */
movel %d0,%d1
andil #0 xff000000,%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 #0 x8000,%d1 /* is it valid ? */
jbeq 1 f /* No, bail out */
movel %d0,%d1
andil #0 xff000000,%d1 /* Get the address */
putn %d1
puts "=="
putn %d1
movel %d0,%d6
jbsr mmu_040_print_flags_tt
1 :
.chip 68 k
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 3 f
putc 'C'
btstl #5 ,%d6
putZc('w' ,'c' ) /* write through or copy-back */
jbra 4 f
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 #0 xfffffff0,%d0
movel %d0,%a0
movel #0 x00000000,%a4 /* logical address */
movel #0 ,%d0
30 :
movel %a4,%d5
addil #PAGESIZE<<13 ,%d5
movel %a0@+,%d6
btst #1 ,%d6 /* is it a table ptr? */
jbne 31 f /* yes */
btst #0 ,%d6 /* is it early terminating? */
jbeq 1 f /* no */
jbsr mmu_030_print_helper
jbra 38 f
1 :
jbsr mmu_print_tuple_invalidate
jbra 38 f
31 :
movel #0 ,%d1
andil #0 xfffffff0,%d6
movel %d6,%a1
32 :
movel %a4,%d5
addil #PAGESIZE<<6 ,%d5
movel %a1@+,%d6
btst #1 ,%d6 /* is it a table ptr? */
jbne 33 f /* yes */
btst #0 ,%d6 /* is it a page descriptor? */
jbeq 1 f /* no */
jbsr mmu_030_print_helper
jbra 37 f
1 :
jbsr mmu_print_tuple_invalidate
jbra 37 f
33 :
movel #0 ,%d2
andil #0 xfffffff0,%d6
movel %d6,%a2
34 :
movel %a4,%d5
addil #PAGESIZE,%d5
movel %a2@+,%d6
btst #0 ,%d6
jbne 35 f
jbsr mmu_print_tuple_invalidate
jbra 36 f
35 :
jbsr mmu_030_print_helper
36 :
movel %d5,%a4
addq #1 ,%d2
cmpib #64 ,%d2
jbne 34 b
37 :
movel %d5,%a4
addq #1 ,%d1
cmpib #128 ,%d1
jbne 32 b
38 :
movel %d5,%a4 /* move to the next logical address */
addq #1 ,%d0
cmpib #128 ,%d0
jbne 30 b
mmu_print_done:
puts "\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(1 f)
puts "amiga"
jbra 9 f
1 :
is_not_atari(2 f)
puts "atari"
jbra 9 f
2 :
is_not_mac(3 f)
puts "macintosh"
jbra 9 f
3 : puts "unknown"
9 : putc '\n'
puts "cputype: 0"
is_not_060(1 f)
putc '6'
jbra 9 f
1 :
is_not_040_or_060(2 f)
putc '4'
jbra 9 f
2 : putc '3'
9 : putc '0'
putc '\n'
rts
#endif /* MMU_PRINT */
/*
* mmu_map_tt
*
* This is a specific function which works on all 680 x0 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 ,%d1
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 1 f
orw #TTR_CI,%d1
1 : lea STACK,%a0
dputn %d1
movel %d1,%a0@
.chip 68030
tstl ARG1
jne 1 f
pmove %a0@,%tt0
jra 2 f
1 : pmove %a0@,%tt1
2 : .chip 68 k
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 1 f
movec %d1,%itt0
movec %d1,%dtt0
jra 2 f
1 : movec %d1,%itt1
movec %d1,%dtt1
2 : .chip 68 k
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 allocate 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 1 f
/* Is there enough to map for 32MB at once
*/
lea %a3@(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE-1 ),%a1
cmpl %a1,%a4
jcs 1 f
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@(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 1 f
/* 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 1 f
/* Temporary allocate a page table and insert it into the ptr table
*/
movel %a1@,%d0
/* The 512 should be PAGE_TABLE_SIZE*4, but that violates the
alignment restriction for pointer tables on the '0[46]0. */
addl #512 ,%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,1 b
lea %pc@(L(temp_mmap_mem)),%a0
movel %a1,%a0@
movew #PAGESIZE-1 ,%d0
1 :
clrl %a1@+
dbra %d0,1 b
lea %pc@(1 b),%a0
movel #1 b,%a1
/* Skip temp mappings if phys == virt */
cmpl %a0,%a1
jeq 1 f
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 1 f:l
1 : nop
movec %a2,%srp
nop
cinva %bc
nop
pflusha
.chip 68 k
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 #0 x80000002,%a0@
movel %a3,%a0@(4 )
movel #0 x0808,%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 #0 x82c07760,%a0@(8 )
pmove %a0@(8 ),%tc /* enable the MMU */
jmp 1 f:l
1 : movel %a2,%a0@(4 )
movel #0 x0808,%d0
movec %d0,%cacr
pmove %a0@,%srp
pflusha
.chip 68 k
L(mmu_engage_cleanup):
subl #PAGE_OFFSET,%d2
subl %d2,%a2
movel %a2,L(kernel_pgdir_ptr)
subl %d2,%fp
subl %d2,%sp
subl %d2,ARG0
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 2 f
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
* 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@(_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,1 b
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 2 f
/* 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 1 f
/* 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 2 f
/* If the page table entry doesn't exist, we allocate a complete new
* page and use it as one continuous big page table which can cover
* 4 MB 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,1 b
/* 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,1 b
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
/* You may define either or both of these. */
#define MAC_USE_SCC_A /* Modem port */
#define MAC_USE_SCC_B /* Printer port */
#if defined(MAC_USE_SCC_A) || defined(MAC_USE_SCC_B)
/* Initialisation table for SCC with 3.6864 MHz PCLK */
L(scc_initable_mac):
.byte 4 ,0 x44 /* x16, 1 stopbit, no parity */
.byte 3 ,0 xc0 /* receiver: 8 bpc */
.byte 5 ,0 xe2 /* transmitter: 8 bpc, assert dtr/rts */
.byte 10 ,0 /* NRZ */
.byte 11 ,0 x50 /* use baud rate generator */
.byte 12 ,1 ,13 ,0 /* 38400 baud */
.byte 14 ,1 /* Baud rate generator enable */
.byte 3 ,0 xc1 /* enable receiver */
.byte 5 ,0 xea /* enable transmitter */
.byte -1
.even
#endif
#endif /* CONFIG_MAC */
#ifdef CONFIG_ATARI
/* #define USE_PRINTER */
/* #define USE_SCC_B */
/* #define USE_SCC_A */
#define USE_MFP
#if defined(USE_SCC_A) || defined(USE_SCC_B)
/* Initialisation table for SCC with 7.9872 MHz PCLK */
/* PCLK == 8.0539 gives baud == 9680.1 */
L(scc_initable_atari):
.byte 4 ,0 x44 /* x16, 1 stopbit, no parity */
.byte 3 ,0 xc0 /* receiver: 8 bpc */
.byte 5 ,0 xe2 /* transmitter: 8 bpc, assert dtr/rts */
.byte 10 ,0 /* NRZ */
.byte 11 ,0 x50 /* use baud rate generator */
.byte 12 ,24 ,13 ,0 /* 9600 baud */
.byte 14 ,2 ,14 ,3 /* use master clock for BRG, enable */
.byte 3 ,0 xc1 /* enable receiver */
.byte 5 ,0 xea /* enable transmitter */
.byte -1
.even
#endif
#ifdef USE_PRINTER
LPSG_SELECT = 0 xff8800
LPSG_READ = 0 xff8800
LPSG_WRITE = 0 xff8802
LPSG_IO_A = 14
LPSG_IO_B = 15
LPSG_CONTROL = 7
LSTMFP_GPIP = 0 xfffa01
LSTMFP_DDR = 0 xfffa05
LSTMFP_IERB = 0 xfffa09
#elif defined(USE_SCC_B)
LSCC_CTRL = 0 xff8c85
LSCC_DATA = 0 xff8c87
#elif defined(USE_SCC_A)
LSCC_CTRL = 0 xff8c81
LSCC_DATA = 0 xff8c83
#elif defined(USE_MFP)
LMFP_UCR = 0 xfffa29
LMFP_TDCDR = 0 xfffa1d
LMFP_TDDR = 0 xfffa25
LMFP_TSR = 0 xfffa2d
LMFP_UDR = 0 xfffa2f
#endif
#endif /* CONFIG_ATARI */
/*
* Serial port output support .
*/
/*
* Initialize serial port hardware
*/
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_atari
* 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
#define SERIAL_DTR 7
#define SERIAL_CNTRL CIABBASE+C_PRA
is_not_amiga(1 f)
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
is_not_atari(4 f)
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)
moveb #0 xff,%a1@(LPSG_WRITE)
moveb #LPSG_IO_B,%a1@(LPSG_SELECT)
clrb %a1@(LPSG_WRITE)
moveb #LPSG_IO_A,%a1@(LPSG_SELECT)
moveb %a1@(LPSG_READ),%d0
bset #5 ,%d0
moveb %d0,%a1@(LPSG_WRITE)
#elif defined(USE_SCC_A) || defined(USE_SCC_B)
lea %a1@(LSCC_CTRL),%a0
/* Reset SCC register pointer */
moveb %a0@,%d0
/* Reset SCC device: write register pointer then register value */
moveb #9 ,%a0@
moveb #0 xc0,%a0@
/* Wait for 5 PCLK cycles, which is about 63 CPU cycles */
/* 5 / 7.9872 MHz = approx. 0.63 us = 63 / 100 MHz */
movel #32 ,%d0
2 :
subq #1 ,%d0
jne 2 b
/* Initialize channel */
lea %pc@(L(scc_initable_atari)),%a1
2 : moveb %a1@+,%d0
jmi 3 f
moveb %d0,%a0@
moveb %a1@+,%a0@
jra 2 b
3 : clrb %a0@
#elif defined(USE_MFP)
bclr #1 ,%a1@(LMFP_TSR)
moveb #0 x88,%a1@(LMFP_UCR)
andb #0 x70,%a1@(LMFP_TDCDR)
moveb #2 ,%a1@(LMFP_TDDR)
orb #1 ,%a1@(LMFP_TDCDR)
bset #1 ,%a1@(LMFP_TSR)
#endif
jra L(serial_init_done)
4 :
#endif
#ifdef CONFIG_MAC
is_not_mac(L(serial_init_not_mac))
#if defined(MAC_USE_SCC_A) || defined(MAC_USE_SCC_B)
#define mac_scc_cha_b_ctrl_offset 0 x0
#define mac_scc_cha_a_ctrl_offset 0 x2
#define mac_scc_cha_b_data_offset 0 x4
#define mac_scc_cha_a_data_offset 0 x6
movel %pc@(L(mac_sccbase)),%a0
/* Reset SCC register pointer */
moveb %a0@(mac_scc_cha_a_ctrl_offset),%d0
/* Reset SCC device: write register pointer then register value */
moveb #9 ,%a0@(mac_scc_cha_a_ctrl_offset)
moveb #0 xc0,%a0@(mac_scc_cha_a_ctrl_offset)
/* Wait for 5 PCLK cycles, which is about 68 CPU cycles */
/* 5 / 3.6864 MHz = approx. 1.36 us = 68 / 50 MHz */
movel #35 ,%d0
5 :
subq #1 ,%d0
jne 5 b
#endif
#ifdef MAC_USE_SCC_A
/* Initialize channel A */
lea %pc@(L(scc_initable_mac)),%a1
5 : moveb %a1@+,%d0
jmi 6 f
moveb %d0,%a0@(mac_scc_cha_a_ctrl_offset)
moveb %a1@+,%a0@(mac_scc_cha_a_ctrl_offset)
jra 5 b
6 :
#endif /* MAC_USE_SCC_A */
#ifdef MAC_USE_SCC_B
/* Initialize channel B */
lea %pc@(L(scc_initable_mac)),%a1
7 : moveb %a1@+,%d0
jmi 8 f
moveb %d0,%a0@(mac_scc_cha_b_ctrl_offset)
moveb %a1@+,%a0@(mac_scc_cha_b_ctrl_offset)
jra 7 b
8 :
#endif /* MAC_USE_SCC_B */
jra L(serial_init_done)
L(serial_init_not_mac):
#endif /* CONFIG_MAC */
#ifdef CONFIG_Q40
is_not_q40(2 f)
/* debug output goes into SRAM, so we don't do it unless requested
- check for '%LX$' signature in SRAM */
lea %pc@(q40_mem_cptr),%a1
move.l #0 xff020010,%a1@ /* must be inited - also used by debug=mem */
move.l #0 xff020000,%a1
cmp.b #'%' ,%a1@
bne 2 f /*nodbg*/
addq.w #4 ,%a1
cmp.b #'L' ,%a1@
bne 2 f /*nodbg*/
addq.w #4 ,%a1
cmp.b #'X' ,%a1@
bne 2 f /*nodbg*/
addq.w #4 ,%a1
cmp.b #'$' ,%a1@
bne 2 f /*nodbg*/
/* signature OK */
lea %pc@(L(q40_do_debug)),%a1
tas %a1@
/*nodbg: q40_do_debug is 0 by default*/
2 :
#endif
#ifdef CONFIG_MVME16x
is_not_mvme16x(L(serial_init_not_mvme16x))
moveb #0 x10,M167_PCSCCMICR
moveb #0 x10,M167_PCSCCTICR
moveb #0 x10,M167_PCSCCRICR
jra L(serial_init_done)
L(serial_init_not_mvme16x):
#endif
#ifdef CONFIG_APOLLO
/* We count on the PROM initializing SIO1 */
#endif
#ifdef CONFIG_HP300
/* We count on the boot loader initialising the UART */
#endif
L(serial_init_done):
func_return serial_init
/*
* Output character on serial port .
*/
func_start serial_putc,%d0/%d1/%a0/%a1
movel ARG1,%d0
cmpib #'\n' ,%d0
jbne 1 f
/* A little safe recursion is good for the soul */
serial_putc #'\r'
1 :
#ifdef CONFIG_AMIGA
is_not_amiga(2 f)
andw #0 x00ff,%d0
oriw #0 x0100,%d0
movel %pc@(L(custom)),%a0
movew %d0,%a0@(CUSTOMBASE+C_SERDAT)
1 : movew %a0@(CUSTOMBASE+C_SERDATR),%d0
andw #0 x2000,%d0
jeq 1 b
jra L(serial_putc_done)
2 :
#endif
#ifdef CONFIG_MAC
is_not_mac(5 f)
#if defined(MAC_USE_SCC_A) || defined(MAC_USE_SCC_B)
movel %pc@(L(mac_sccbase)),%a1
#endif
#ifdef MAC_USE_SCC_A
3 : btst #2 ,%a1@(mac_scc_cha_a_ctrl_offset)
jeq 3 b
moveb %d0,%a1@(mac_scc_cha_a_data_offset)
#endif /* MAC_USE_SCC_A */
#ifdef MAC_USE_SCC_B
4 : btst #2 ,%a1@(mac_scc_cha_b_ctrl_offset)
jeq 4 b
moveb %d0,%a1@(mac_scc_cha_b_data_offset)
#endif /* MAC_USE_SCC_B */
jra L(serial_putc_done)
5 :
#endif /* CONFIG_MAC */
#ifdef CONFIG_ATARI
is_not_atari(4 f)
movel %pc@(L(iobase)),%a1
#if defined(USE_PRINTER)
3 : btst #0 ,%a1@(LSTMFP_GPIP)
jne 3 b
moveb #LPSG_IO_B,%a1@(LPSG_SELECT)
moveb %d0,%a1@(LPSG_WRITE)
moveb #LPSG_IO_A,%a1@(LPSG_SELECT)
moveb %a1@(LPSG_READ),%d0
bclr #5 ,%d0
moveb %d0,%a1@(LPSG_WRITE)
nop
nop
bset #5 ,%d0
moveb %d0,%a1@(LPSG_WRITE)
#elif defined(USE_SCC_A) || defined(USE_SCC_B)
3 : btst #2 ,%a1@(LSCC_CTRL)
jeq 3 b
moveb %d0,%a1@(LSCC_DATA)
#elif defined(USE_MFP)
3 : btst #7 ,%a1@(LMFP_TSR)
jeq 3 b
moveb %d0,%a1@(LMFP_UDR)
#endif
jra L(serial_putc_done)
4 :
#endif /* CONFIG_ATARI */
#ifdef CONFIG_MVME147
is_not_mvme147(2 f)
1 : btst #2 ,M147_SCC_CTRL_A
jeq 1 b
moveb %d0,M147_SCC_DATA_A
jbra L(serial_putc_done)
2 :
#endif
#ifdef CONFIG_MVME16x
is_not_mvme16x(2 f)
/*
* If the loader gave us a board type then we can use that to
* select an appropriate output routine ; otherwise we just use
* the Bug code . If we have to use the Bug that means the Bug
* workspace has to be valid , which means the Bug has to use
* the SRAM , which is non - standard .
*/
moveml %d0-%d7/%a2-%a6,%sp@-
movel vme_brdtype,%d1
jeq 1 f | No tag - use the Bug
cmpi #VME_TYPE_MVME162,%d1
jeq 6 f
cmpi #VME_TYPE_MVME172,%d1
jne 5 f
/* 162/172; it's an SCC */
6 : btst #2 ,M162_SCC_CTRL_A
nop
nop
nop
jeq 6 b
moveb #8 ,M162_SCC_CTRL_A
nop
nop
nop
moveb %d0,M162_SCC_CTRL_A
jra 3 f
5 :
/* 166/167/177; it's a CD2401 */
moveb #0 ,M167_CYCAR
moveb M167_CYIER,%d2
moveb #0 x02,M167_CYIER
7 :
btst #5 ,M167_PCSCCTICR
jeq 7 b
moveb M167_PCTPIACKR,%d1
moveb M167_CYLICR,%d1
jeq 8 f
moveb #0 x08,M167_CYTEOIR
jra 7 b
8 :
moveb %d0,M167_CYTDR
moveb #0 ,M167_CYTEOIR
moveb %d2,M167_CYIER
jra 3 f
1 :
moveb %d0,%sp@-
trap #15
.word 0 x0020 /* TRAP 0x020 */
3 :
moveml %sp@+,%d0-%d7/%a2-%a6
jbra L(serial_putc_done)
2 :
#endif /* CONFIG_MVME16x */
#ifdef CONFIG_BVME6000
is_not_bvme6000(2 f)
/*
* The BVME6000 machine has a serial port . . .
*/
1 : btst #2 ,BVME_SCC_CTRL_A
jeq 1 b
moveb %d0,BVME_SCC_DATA_A
jbra L(serial_putc_done)
2 :
#endif
#ifdef CONFIG_SUN3X
is_not_sun3x(2 f)
movel %d0,-(%sp)
movel 0 xFEFE0018,%a1
jbsr (%a1)
addq #4 ,%sp
jbra L(serial_putc_done)
2 :
#endif
#ifdef CONFIG_Q40
is_not_q40(2 f)
tst.l %pc@(L(q40_do_debug)) /* only debug if requested */
beq 2 f
lea %pc@(q40_mem_cptr),%a1
move.l %a1@,%a0
move.b %d0,%a0@
addq.l #4 ,%a0
move.l %a0,%a1@
jbra L(serial_putc_done)
2 :
#endif
#ifdef CONFIG_APOLLO
is_not_apollo(2 f)
movl %pc@(L(iobase)),%a1
moveb %d0,%a1@(LTHRB0)
1 : moveb %a1@(LSRB0),%d0
andb #0 x4,%d0
beq 1 b
jbra L(serial_putc_done)
2 :
#endif
#ifdef CONFIG_HP300
is_not_hp300(3 f)
movl %pc@(L(iobase)),%a1
addl %pc@(L(uartbase)),%a1
movel %pc@(L(uart_scode)),%d1 /* Check the scode */
jmi 3 f /* Unset? Exit */
cmpi #256 ,%d1 /* APCI scode? */
jeq 2 f
1 : moveb %a1@(DCALSR),%d1 /* Output to DCA */
andb #0 x20,%d1
beq 1 b
moveb %d0,%a1@(DCADATA)
jbra L(serial_putc_done)
2 : moveb %a1@(APCILSR),%d1 /* Output to APCI */
andb #0 x20,%d1
beq 2 b
moveb %d0,%a1@(APCIDATA)
jbra L(serial_putc_done)
3 :
#endif
#ifdef CONFIG_VIRT
is_not_virt(1 f)
movel L(virt_gf_tty_base),%a1
movel %d0,%a1@(GF_PUT_CHAR)
1 :
#endif
L(serial_putc_done):
func_return serial_putc
/*
* Output a string .
*/
func_start puts,%d0/%a0
movel ARG1,%a0
jra 2 f
1 :
#ifdef CONSOLE_DEBUG
console_putc %d0
#endif
#ifdef SERIAL_DEBUG
serial_putc %d0
#endif
2 : moveb %a0@+,%d0
jne 1 b
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 #0 x0f,%d2
addb #'0' ,%d2
cmpb #'9' ,%d2
jls 2 f
addb #'A' -('9' +1 ),%d2
2 :
#ifdef CONSOLE_DEBUG
console_putc %d2
#endif
#ifdef SERIAL_DEBUG
serial_putc %d2
#endif
dbra %d1,1 b
func_return putn
#ifdef CONFIG_EARLY_PRINTK
/*
* This routine takes its parameters on the stack . It then
* turns around and calls the internal routines . This routine
* is used by the boot console .
*
* The function signature is -
* void debug_cons_nputs ( struct console * c , const char * s , unsigned int n )
*
* This routine does NOT understand variable arguments only
* simple strings !
*/
ENTRY(debug_cons_nputs)
moveml %d0/%d1/%a0,%sp@-
movew %sr,%sp@-
ori #0 x0700,%sr
movel %sp@(22 ),%a0 /* char *s */
movel %sp@(26 ),%d1 /* unsigned int n */
jra 2 f
1 :
#ifdef CONSOLE_DEBUG
console_putc %d0
#endif
#ifdef SERIAL_DEBUG
serial_putc %d0
#endif
subq #1 ,%d1
2 : jeq 3 f
moveb %a0@+,%d0
jne 1 b
3 :
movew %sp@+,%sr
moveml %sp@+,%d0/%d1/%a0
rts
#endif /* CONFIG_EARLY_PRINTK */
#if defined(CONFIG_HP300) || defined(CONFIG_APOLLO)
func_start set_leds,%d0/%a0
movel ARG1,%d0
#ifdef CONFIG_HP300
is_not_hp300(1 f)
movel %pc@(L(iobase)),%a0
moveb %d0,%a0@(0 x1ffff)
jra 2 f
#endif
1 :
#ifdef CONFIG_APOLLO
movel %pc@(L(iobase)),%a0
lsll #8 ,%d0
eorw #0 xff00,%d0
moveb %d0,%a0@(LCPUCTRL)
#endif
2 :
func_return set_leds
#endif
#ifdef CONSOLE_DEBUG
/*
* For continuity , see the data alignment
* to which this structure is tied .
*/
#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
func_start console_init,%a0-%a4/%d0-%d7
/*
* Some of the register usage that follows
* a0 = pointer to boot_info
* a1 = pointer to screen
* a2 = pointer to console_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
*/
lea %pc@(L(console_globals)),%a2
movel %pc@(L(mac_videobase)),%a1
movel %pc@(L(mac_rowbytes)),%d5
movel %pc@(L(mac_dimensions)),%d3 /* -> low byte */
movel %d3,%d4
swap %d4 /* -> high byte */
andl #0 xffff,%d3 /* d3 = screen width in pixels */
andl #0 xffff,%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 */
moveq #-1 ,%d0 /* Mac_black */
subq #1 ,%d6
L(console_clear_loop):
movel %d0,%a1@+
movel %d0,%a1@+
dbra %d6,L(console_clear_loop)
/* Calculate font size */
#if defined(FONT_8x8) && defined(CONFIG_FONT_8x8)
lea %pc@(font_vga_8x8),%a0
#elif defined(FONT_8x16) && defined(CONFIG_FONT_8x16)
lea %pc@(font_vga_8x16),%a0
#elif defined(FONT_6x11) && defined(CONFIG_FONT_6x11)
lea %pc@(font_vga_6x11),%a0
#elif defined(CONFIG_FONT_8x8) /* default */
lea %pc@(font_vga_8x8),%a0
#else /* no compiled-in font */
lea 0 ,%a0
#endif
/*
* At this point we make a shift in register usage
* a1 = address of console_font pointer
*/
lea %pc@(L(console_font)),%a1
movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in console_font */
tstl %a0
jeq 1 f
lea %pc@(L(console_font_data)),%a4
movel %a0@(FONT_DESC_DATA),%d0
subl #L(console_font),%a1
addl %a1,%d0
movel %d0,%a4@
/*
* 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@(FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */
movel %d4,%d1 /* screen height in pixels */
divul %a0@(FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */
subql #1 ,%d1 /* row range is 0 to num - 1 */
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
*/
1 :
func_return console_init
#ifdef CONFIG_LOGO
func_start console_put_penguin,%a0-%a1/%d0-%d7
/*
* Get ' that_penguin ' onto the screen in the upper right corner
* penguin is 64 x 74 pixels , align against right edge of screen
*/
lea %pc@(L(mac_dimensions)),%a0
movel %a0@,%d0
andil #0 xffff,%d0
subil #64 ,%d0 /* snug up against the right edge */
clrl %d1 /* start at the top */
movel #73 ,%d7
lea %pc@(L(that_penguin)),%a1
L(console_penguin_row):
movel #31 ,%d6
L(console_penguin_pixel_pair):
moveb %a1@,%d2
lsrb #4 ,%d2
console_plot_pixel %d0,%d1,%d2
addq #1 ,%d0
moveb %a1@+,%d2
console_plot_pixel %d0,%d1,%d2
addq #1 ,%d0
dbra %d6,L(console_penguin_pixel_pair)
subil #64 ,%d0
addq #1 ,%d1
dbra %d7,L(console_penguin_row)
func_return console_put_penguin
/* include penguin bitmap */
L(that_penguin):
#include "../mac/mac_penguin.S"
#endif
/*
* Calculate source and destination addresses
* output a1 = dest
* a2 = source
*/
func_start console_scroll,%a0-%a4/%d0-%d7
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
tstl %a0
jeq 1 f
mulul %a0@(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 #0 xffff,%d3 /* d3 = screen width in pixels */
andl #0 xffff,%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@(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
L(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,L(console_scroll_loop)
lea %pc@(L(mac_rowbytes)),%a0
movel %a0@,%d6
movel %pc@(L(console_font)),%a0
mulul %a0@(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
L(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,L(console_scroll_clear_loop)
1 :
func_return console_scroll
func_start console_putc,%a0/%a1/%d0-%d7
is_not_mac(L(console_exit))
tstl %pc@(L(console_font))
jeq L(console_exit)
lea %pc@(L(console_globals)),%a0
/* Output character in d7 on console.
*/
movel ARG1,%d7
cmpib #'\n' ,%d7
jne L(console_not_lf)
clrl %a0@(Lconsole_struct_cur_column) /* implicit \r */
movel %a0@(Lconsole_struct_cur_row),%d0
movel %a0@(Lconsole_struct_num_rows),%d1
cmpl %d1,%d0
jcs 1 f
console_scroll
jra L(console_exit)
1 :
addql #1 ,%d0
movel %d0,%a0@(Lconsole_struct_cur_row)
jra L(console_exit)
L(console_not_lf):
cmpib #'\r' ,%d7
jne L(console_not_lf_not_cr)
clrl %a0@(Lconsole_struct_cur_column)
jra L(console_exit)
/*
* 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
*/
L(console_not_lf_not_cr):
movel %a0@(Lconsole_struct_cur_column),%d0
movel %a0@(Lconsole_struct_cur_row),%d1
/*
* 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 %pc@(L(console_font_data)),%a1 /* Load fbcon_font_desc.data into a1 */
andl #0 x000000ff,%d7
/* ASSERT: a0 = contents of Lconsole_font */
mulul %a0@(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@(FONT_DESC_WIDTH),%d0
mulul %a0@(FONT_DESC_HEIGHT),%d1
movel %a0@(FONT_DESC_HEIGHT),%d7 /* Load fbcon_font_desc.height into d7 */
subq #1 ,%d7
L(console_read_char_scanline):
moveb %a1@+,%d3
/* ASSERT: a0 = contents of Lconsole_font */
movel %a0@(FONT_DESC_WIDTH),%d6 /* Load fbcon_font_desc.width into d6 */
subql #1 ,%d6
L(console_do_font_scanline):
lslb #1 ,%d3
scsb %d2 /* convert 1 bit into a byte */
console_plot_pixel %d0,%d1,%d2
addq #1 ,%d0
dbra %d6,L(console_do_font_scanline)
/* ASSERT: a0 = contents of Lconsole_font */
subl %a0@(FONT_DESC_WIDTH),%d0
addq #1 ,%d1
dbra %d7,L(console_read_char_scanline)
/*
* Register usage in the code below :
* a0 = pointer to console globals
* d0 = cursor column
* d1 = cursor column limit
*/
lea %pc@(L(console_globals)),%a0
movel %a0@(Lconsole_struct_cur_column),%d0
addql #1 ,%d0
movel %d0,%a0@(Lconsole_struct_cur_column) /* Update cursor pos */
movel %a0@(Lconsole_struct_num_columns),%d1
cmpl %d1,%d0
jcs L(console_exit)
console_putc #'\n' /* Line wrap using tail recursion */
L(console_exit):
func_return console_putc
/*
* Input :
* d0 = x coordinate
* d1 = y coordinate
* d2 = ( bit 0 ) 1 / 0 for white / black ( !)
* All registers are preserved
*/
func_start console_plot_pixel,%a0-%a1/%d0-%d4
movel %pc@(L(mac_videobase)),%a1
movel %pc@(L(mac_videodepth)),%d3
movel ARG1,%d0
movel ARG2,%d1
mulul %pc@(L(mac_rowbytes)),%d1
movel ARG3,%d2
/*
* 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
*/
L(test_1bit):
cmpb #1 ,%d3
jbne L(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 L(white_1)
bsetb %d4,%a1@
jbra L(console_plot_pixel_exit)
L(white_1):
bclrb %d4,%a1@
jbra L(console_plot_pixel_exit)
L(test_2bit):
cmpb #2 ,%d3
jbne L(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 L(white_2)
bsetb %d4,%a1@
addq #1 ,%d4
bsetb %d4,%a1@
jbra L(console_plot_pixel_exit)
L(white_2):
bclrb %d4,%a1@
addq #1 ,%d4
bclrb %d4,%a1@
jbra L(console_plot_pixel_exit)
L(test_4bit):
cmpb #4 ,%d3
jbne L(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 L(white_4)
bsetb %d4,%a1@
addq #1 ,%d4
bsetb %d4,%a1@
addq #1 ,%d4
bsetb %d4,%a1@
addq #1 ,%d4
bsetb %d4,%a1@
jbra L(console_plot_pixel_exit)
L(white_4):
bclrb %d4,%a1@
addq #1 ,%d4
bclrb %d4,%a1@
addq #1 ,%d4
bclrb %d4,%a1@
addq #1 ,%d4
bclrb %d4,%a1@
jbra L(console_plot_pixel_exit)
L(test_8bit):
cmpb #8 ,%d3
jbne L(test_16bit)
addal %d0,%a1
addal %d1,%a1
andb #1 ,%d2
jbne L(white_8)
moveb #0 xff,%a1@
jbra L(console_plot_pixel_exit)
L(white_8):
clrb %a1@
jbra L(console_plot_pixel_exit)
L(test_16bit):
cmpb #16 ,%d3
jbne L(console_plot_pixel_exit)
addal %d0,%a1
addal %d0,%a1
addal %d1,%a1
andb #1 ,%d2
jbne L(white_16)
clrw %a1@
jbra L(console_plot_pixel_exit)
L(white_16):
movew #0 x0fff,%a1@
jbra L(console_plot_pixel_exit)
L(console_plot_pixel_exit):
func_return console_plot_pixel
#endif /* CONSOLE_DEBUG */
__INITDATA
.align 4
m68k_init_mapped_size:
.long 0
#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA) || \
defined(CONFIG_HP300) || defined(CONFIG_APOLLO)
L(custom):
L(iobase):
.long 0
#endif
#ifdef CONSOLE_DEBUG
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 */
L(console_font):
.long 0 /* pointer to console font (struct font_desc) */
L(console_font_data):
.long 0 /* pointer to console font data */
#endif /* CONSOLE_DEBUG */
#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_MVME147)
M147_SCC_CTRL_A = 0 xfffe3002
M147_SCC_DATA_A = 0 xfffe3003
#endif
#if defined (CONFIG_MVME16x)
M162_SCC_CTRL_A = 0 xfff45005
M167_CYCAR = 0 xfff450ee
M167_CYIER = 0 xfff45011
M167_CYLICR = 0 xfff45026
M167_CYTEOIR = 0 xfff45085
M167_CYTDR = 0 xfff450f8
M167_PCSCCMICR = 0 xfff4201d
M167_PCSCCTICR = 0 xfff4201e
M167_PCSCCRICR = 0 xfff4201f
M167_PCTPIACKR = 0 xfff42025
#endif
#if defined (CONFIG_BVME6000)
BVME_SCC_CTRL_A = 0 xffb0000b
BVME_SCC_DATA_A = 0 xffb0000f
#endif
#if defined(CONFIG_MAC)
L(mac_videobase):
.long 0
L(mac_videodepth):
.long 0
L(mac_dimensions):
.long 0
L(mac_rowbytes):
.long 0
L(mac_sccbase):
.long 0
#endif /* CONFIG_MAC */
#if defined (CONFIG_APOLLO)
LSRB0 = 0 x10412
LTHRB0 = 0 x10416
LCPUCTRL = 0 x10100
#endif
#if defined(CONFIG_HP300)
DCADATA = 0 x11
DCALSR = 0 x1b
APCIDATA = 0 x00
APCILSR = 0 x14
L(uartbase):
.long 0
L(uart_scode):
.long -1
#endif
__FINIT
.data
.align 4
availmem:
.long 0
m68k_pgtable_cachemode:
.long 0
m68k_supervisor_cachemode:
.long 0
#if defined(CONFIG_MVME16x)
mvme_bdid:
.long 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0
#endif
#if defined(CONFIG_Q40)
q40_mem_cptr:
.long 0
L(q40_do_debug):
.long 0
#endif
#if defined(CONFIG_VIRT)
GF_PUT_CHAR = 0 x00
L(virt_gf_tty_base):
.long 0
#endif /* CONFIG_VIRT */
Messung V0.5 in Prozent C=90 H=89 G=89
¤ Dauer der Verarbeitung: 0.278 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland