diff options
Diffstat (limited to 'arch/m68k')
38 files changed, 4316 insertions, 2151 deletions
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index 9cd2d1838..cb60ea268 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -29,14 +29,21 @@ LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds # without -fno-strength-reduce the 53c7xx.c driver fails ;-( CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 -ifdef CONFIG_OPTIMIZE_040 +# enable processor switch if compiled only for a single cpu +ifndef CONFIG_M68020 +ifndef CONFIG_M68030 + +ifndef CONFIG_M68060 CFLAGS := $(CFLAGS) -m68040 endif -ifdef CONFIG_OPTIMIZE_060 +ifndef CONFIG_M68040 CFLAGS := $(CFLAGS) -m68060 endif +endif +endif + ifdef CONFIG_KGDB # If configured for kgdb support, include debugging infos and keep the # frame pointer @@ -116,6 +123,7 @@ endif archclean: rm -f vmlinux.gz + rm -f arch/m68k/kernel/m68k_defs.h arch/m68k/kernel/m68k_defs.d archmrproper: diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c index 25955213e..4fb886456 100644 --- a/arch/m68k/amiga/amiints.c +++ b/arch/m68k/amiga/amiints.c @@ -15,7 +15,7 @@ * - IRQ_FLG_SLOW: handler is inserted at bottom of list and before * they're executed irq level is set to the previous * one, but handlers don't need to be reentrant, if - * reentrance occured, slow handlers will be just + * reentrance occurred, slow handlers will be just * called again. * The whole interrupt handling for CIAs is moved to cia.c * /Roman Zippel @@ -367,7 +367,7 @@ void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server) for (;;) { for (; node; node = node->next) node->handler(irq, node->dev_id, fp); - /* if reentrance occured, serve slow handlers again */ + /* if reentrance occurred, serve slow handlers again */ custom.intena = ami_intena_vals[irq]; if (!server->reentrance) { server->count--; diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 63cb5265c..37b5bde3c 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -52,7 +52,6 @@ static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); /* amiga specific keyboard functions */ extern int amiga_keyb_init(void); extern int amiga_kbdrate (struct kbd_repeat *); -extern void amiga_kbd_reset_setup(char*, int); /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); @@ -343,7 +342,6 @@ __initfunc(void config_amiga(void)) mach_sched_init = amiga_sched_init; mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; - kbd_reset_setup = amiga_kbd_reset_setup; mach_init_IRQ = amiga_init_IRQ; mach_default_handler = &amiga_default_handler; mach_request_irq = amiga_request_irq; diff --git a/arch/m68k/amiga/pcmcia.c b/arch/m68k/amiga/pcmcia.c index 3faac7eda..e1b29387a 100644 --- a/arch/m68k/amiga/pcmcia.c +++ b/arch/m68k/amiga/pcmcia.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/sched.h> +#include <linux/timer.h> #include <asm/amigayle.h> #include <asm/amipcmcia.h> @@ -26,7 +27,7 @@ void pcmcia_reset(void) unsigned char b; gayle_reset = 0x00; - while (jiffies - reset_start_time < 1*HZ/100); + while (time_before(jiffies, reset_start_time + 1*HZ/100)); b = gayle_reset; } diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c index c4cffcdf9..18e29814e 100644 --- a/arch/m68k/apollo/dn_ints.c +++ b/arch/m68k/apollo/dn_ints.c @@ -30,7 +30,7 @@ void dn_process_int(int irq, struct pt_regs *fp) { dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp); } else { - printk("spurious irq %d occured\n",irq); + printk("spurious irq %d occurred\n",irq); } #if 0 diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index e6535f6ff..79ef5f9fd 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -825,7 +825,7 @@ __initfunc(int atari_keyb_init(void)) /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's * self-test is finished */ self_test_last_rcv = jiffies; - while( jiffies < self_test_last_rcv + HZ/4 ) + while (time_before(jiffies, self_test_last_rcv + HZ/4)) barrier(); /* if not incremented: no 0xf1 received */ if (ikbd_self_test == 1) @@ -861,8 +861,3 @@ int atari_kbdrate( struct kbd_repeat *k ) return( 0 ); } - -/* for "kbd-reset" cmdline param */ -__initfunc(void atari_kbd_reset_setup(char *str, int *ints)) -{ -} diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index 8db027ab4..5be79acaf 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -60,7 +60,6 @@ static int atari_get_hardware_list(char *buffer); extern int atari_keyb_init(void); extern int atari_kbdrate (struct kbd_repeat *); extern void atari_kbd_leds (unsigned int); -extern void atari_kbd_reset_setup(char*, int); /* atari specific irq functions */ extern void atari_init_IRQ (void); extern int atari_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), @@ -251,7 +250,6 @@ __initfunc(void config_atari(void)) mach_keyb_init = atari_keyb_init; mach_kbdrate = atari_kbdrate; mach_kbd_leds = atari_kbd_leds; - kbd_reset_setup = atari_kbd_reset_setup; mach_init_IRQ = atari_init_IRQ; mach_request_irq = atari_request_irq; mach_free_irq = atari_free_irq; diff --git a/arch/m68k/bvme6000/bvmeints.c b/arch/m68k/bvme6000/bvmeints.c index a79f5555d..04633375f 100644 --- a/arch/m68k/bvme6000/bvmeints.c +++ b/arch/m68k/bvme6000/bvmeints.c @@ -119,9 +119,12 @@ void bvme6000_free_irq(unsigned int irq, void *dev_id) void bvme6000_process_int (unsigned long vec, struct pt_regs *fp) { if (vec > 255) - panic ("bvme6000_process_int: Illegal vector %ld", vec); - irq_tab[vec].count++; - irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp); + printk ("bvme6000_process_int: Illegal vector %ld", vec); + else + { + irq_tab[vec].count++; + irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp); + } } int bvme6000_get_irq_list (char *buf) diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c index 74d15e995..543b04c74 100644 --- a/arch/m68k/bvme6000/config.c +++ b/arch/m68k/bvme6000/config.c @@ -91,8 +91,7 @@ void bvme6000_reset() static void bvme6000_get_model(char *model) { - /* XXX Need to detect if BVME4000 or BVME6000 */ - sprintf(model, "BVME6000"); + sprintf(model, "BVME%d000", m68k_cputype == CPU_68060 ? 6 : 4); } @@ -152,13 +151,17 @@ __initfunc(void config_bvme6000(void)) pit->pbddr = 0xf3; /* Mostly outputs */ pit->pcdr = 0x01; /* PA transceiver disabled */ pit->pcddr = 0x03; /* WDOG disable */ + + /* Disable snooping for Ethernet and VME accesses */ + + bvme_acr_addrctl = 0; } void bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp) { unsigned long *new = (unsigned long *)vectors; - unsigned long *old = (unsigned long *)0xf8000000;; + unsigned long *old = (unsigned long *)0xf8000000; /* Wait for button release */ while (*config_reg_ptr & BVME_ABORT_STATUS) diff --git a/arch/m68k/config.in b/arch/m68k/config.in index 8fe84aecd..a67227d60 100644 --- a/arch/m68k/config.in +++ b/arch/m68k/config.in @@ -44,6 +44,7 @@ bool 'HP9000/300 support' CONFIG_HP300 if [ "$CONFIG_HP300" = "y" ]; then bool 'DIO bus support' CONFIG_DIO fi +define_bool CONFIG_SUN3 n if [ "$CONFIG_PCI" = "y" ]; then bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC fi @@ -53,22 +54,11 @@ bool '68020 support' CONFIG_M68020 bool '68030 support' CONFIG_M68030 bool '68040 support' CONFIG_M68040 bool '68060 support' CONFIG_M68060 -if [ "$CONFIG_M68020" = "n" -a "$CONFIG_M68030" = "n" ]; then - if [ "$CONFIG_M68040" = "y" -a "$CONFIG_M68060" = "n" ]; then - bool 'Use 68040 specific optimizations' CONFIG_OPTIMIZE_040 - fi - if [ "$CONFIG_M68040" = "n" -a "$CONFIG_M68060" = "y" ]; then - bool 'Use 68060 specific optimizations' CONFIG_OPTIMIZE_060 - fi -fi -if [ "$CONFIG_VME" = "y" -a "$CONFIG_M68060" = "y" ]; then - define_bool CONFIG_060_WRITETHROUGH y -fi bool 'Advanced configuration options' CONFIG_ADVANCED if [ "$CONFIG_ADVANCED" = "y" ]; then bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS bool 'Use one physical chunk of memory only' CONFIG_SINGLE_MEMORY_CHUNK - if [ "$CONFIG_M68060" = "y" -a "$CONFIG_VME" = "n" ]; then + if [ "$CONFIG_M68060" = "y" ]; then bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH fi fi @@ -140,19 +130,19 @@ mainmenu_option next_comment comment 'SCSI low-level drivers' if [ "$CONFIG_AMIGA" = "y" ]; then - tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI + dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'A4000T SCSI support' CONFIG_A4000T_SCSI fi fi if [ "$CONFIG_ZORRO" = "y" ]; then - tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI - tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI - bool 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI - bool 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI - bool 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI - bool 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI - bool 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI + dep_tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI + dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI + dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI + dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI + dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI + dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI + dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'A4091 SCSI support' CONFIG_A4091_SCSI bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI @@ -173,7 +163,7 @@ if [ "$CONFIG_ATARI" = "y" ]; then fi if [ "$CONFIG_MAC" = "y" ]; then bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI - bool 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP + dep_tristate 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI fi #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI @@ -226,14 +216,14 @@ if [ "$CONFIG_APOLLO" = "y" ] ; then fi if [ "$CONFIG_MAC" = "y" ]; then bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT - bool 'AV Macintosh onboard MACE ethernet' CONFIG_MACMACE - bool 'Macintosh onboard SONIC ethernet' CONFIG_MACSONIC +# bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE + bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC fi if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then - bool 'MVME16x Ethernet support' CONFIG_MVME16x_NET + tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET fi if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then - bool 'BVME6000 Ethernet support' CONFIG_BVME6000_NET + tristate 'BVME6000 Ethernet support' CONFIG_BVME6000_NET fi if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari Lance support' CONFIG_ATARILANCE @@ -367,8 +357,6 @@ if [ "$CONFIG_VME" = "n" ]; then endmenu fi -source fs/nls/Config.in - mainmenu_option next_comment comment 'Kernel hacking' diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig index 5a9f39e52..ab9152f5d 100644 --- a/arch/m68k/defconfig +++ b/arch/m68k/defconfig @@ -28,8 +28,6 @@ CONFIG_M68020=y CONFIG_M68030=y CONFIG_M68040=y # CONFIG_M68060 is not set -# CONFIG_OPTIMIZE_040 is not set -# CONFIG_OPTIMIZE_060 is not set # CONFIG_ADVANCED is not set # CONFIG_SINGLE_MEMORY_CHUNK is not set # CONFIG_RMW_INSNS is not set @@ -77,21 +75,26 @@ CONFIG_BLK_DEV_INITRD=y # # Networking options # +CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ACCT is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set # # (it is safe to leave these untouched) # -# CONFIG_INET_PCTCP is not set # CONFIG_INET_RARP is not set -CONFIG_PATH_MTU_DISCOVERY=y CONFIG_IP_NOSR=y # CONFIG_SKB_LARGE is not set # CONFIG_IPV6 is not set @@ -101,8 +104,20 @@ CONFIG_IP_NOSR=y # # CONFIG_IPX is not set # CONFIG_ATALK is not set -# CONFIG_AX25 is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set # CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set +# CONFIG_CPU_IS_SLOW is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set # # SCSI support @@ -115,12 +130,15 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set # CONFIG_CHR_DEV_SG is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers @@ -149,6 +167,7 @@ CONFIG_NETDEVICES=y # CONFIG_SLIP is not set # CONFIG_PPP is not set # CONFIG_ARIADNE is not set +# CONFIG_ARIADNE2 is not set # CONFIG_A2065 is not set # CONFIG_HYDRA is not set # CONFIG_APNE is not set @@ -186,7 +205,10 @@ CONFIG_FB_AMIGA_OCS=y CONFIG_FB_AMIGA_ECS=y CONFIG_FB_AMIGA_AGA=y # CONFIG_FB_CYBER is not set +# CONFIG_FB_VIRGE is not set +# CONFIG_FB_CVPPC is not set # CONFIG_FB_RETINAZ3 is not set +# CONFIG_FB_CLGEN is not set # CONFIG_FB_ATARI is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S index 1e4d0cf72..06d22b7b7 100644 --- a/arch/m68k/fpsp040/skeleton.S +++ b/arch/m68k/fpsp040/skeleton.S @@ -40,6 +40,7 @@ #include <linux/linkage.h> #include <asm/entry.h> +#include "../kernel/m68k_defs.h" |SKELETON idnt 2,1 | Motorola 040 Floating Point Software Package @@ -375,12 +376,12 @@ fpsp_fmt_error: .global fpsp_done fpsp_done: btst #0x5,%sp@ | supervisor bit set in saved SR? - beq Lnotkern + beq .Lnotkern rte -Lnotkern: +.Lnotkern: SAVE_ALL_INT GET_CURRENT(%d0) - tstl %curptr@(LTASK_NEEDRESCHED) + tstl %curptr@(TASK_NEEDRESCHED) jne SYMBOL_NAME(ret_from_exception) | deliver signals, | reschedule etc.. RESTORE_ALL diff --git a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c index 97fb6e480..6808de799 100644 --- a/arch/m68k/hp300/config.c +++ b/arch/m68k/hp300/config.c @@ -55,11 +55,6 @@ static void hp300_kbd_leds(unsigned int leds) { } -/* for "kbd-reset" cmdline param */ -__initfunc(void hp300_kbd_reset_setup(char *str, int i)) -{ -} - static void hp300_get_model(char *model) { strcpy(model, "HP9000/300"); @@ -74,7 +69,6 @@ __initfunc(void config_hp300(void)) mach_init_IRQ = hp300_init_IRQ; mach_request_irq = hp300_request_irq; mach_free_irq = hp300_free_irq; - kbd_reset_setup = hp300_kbd_reset_setup; mach_get_model = hp300_get_model; mach_get_irq_list = hp300_get_irq_list; mach_gettimeoffset = hp300_gettimeoffset; diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S index cde14e120..859ba3dd3 100644 --- a/arch/m68k/ifpsp060/iskeleton.S +++ b/arch/m68k/ifpsp060/iskeleton.S @@ -36,6 +36,7 @@ #include <linux/linkage.h> #include <asm/entry.h> +#include "../kernel/m68k_defs.h" |################################ @@ -69,12 +70,12 @@ .global _060_isp_done _060_isp_done: btst #0x5,%sp@ | supervisor bit set in saved SR? - beq Lnotkern + beq .Lnotkern rte -Lnotkern: +.Lnotkern: SAVE_ALL_INT GET_CURRENT(%d0) - tstl %curptr@(LTASK_NEEDRESCHED) + tstl %curptr@(TASK_NEEDRESCHED) jne SYMBOL_NAME(ret_from_exception) | deliver signals, | reschedule etc.. RESTORE_ALL diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 977120c1e..280a5b450 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -26,10 +26,13 @@ endif head.o: head.S m68k_defs.h -m68k_defs.h: m68k_defs.c m68k_defs.head $(TOPDIR)/include/linux/sched.h - $(CC) ${CFLAGS} -S m68k_defs.c +m68k_defs.h: m68k_defs.c m68k_defs.head + rm -f m68k_defs.d + SUNPRO_DEPENDENCIES="m68k_defs.d m68k_defs.h" \ + $(CC) $(filter-out -MD,$(CFLAGS)) -S m68k_defs.c cp m68k_defs.head m68k_defs.h - sed -n < m68k_defs.s >> m68k_defs.h '/^#define/s/ #/ /p' + grep '^#define' m68k_defs.s >> m68k_defs.h rm m68k_defs.s +-include m68k_defs.d include $(TOPDIR)/Rules.make diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index b3e15387c..e21e4b21c 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -34,8 +34,10 @@ #include <linux/config.h> #include <linux/linkage.h> #include <asm/entry.h> +#include <asm/errno.h> #include <asm/setup.h> #include <asm/segment.h> +#include <asm/traps.h> #include "m68k_defs.h" @@ -43,7 +45,7 @@ .globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception) .globl SYMBOL_NAME(ret_from_signal) .globl SYMBOL_NAME(inthandler), SYMBOL_NAME(sys_call_table) -.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone) +.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone), SYMBOL_NAME(sys_vfork) .globl SYMBOL_NAME(ret_from_interrupt), SYMBOL_NAME(bad_interrupt) .text @@ -65,24 +67,24 @@ ENTRY(trap) ENTRY(reschedule) | save top of frame - movel %sp,%curptr@(TS_ESP0) + movel %sp,%curptr@(TASK_TSS+TSS_ESP0) pea SYMBOL_NAME(ret_from_exception) jmp SYMBOL_NAME(schedule) badsys: - movel #-LENOSYS,LPT_OFF_D0(%sp) + movel #-ENOSYS,PT_D0(%sp) jra SYMBOL_NAME(ret_from_exception) do_trace: - movel #-LENOSYS,LPT_OFF_D0(%sp) | needed for strace + movel #-ENOSYS,PT_D0(%sp) | needed for strace subql #4,%sp SAVE_SWITCH_STACK jbsr SYMBOL_NAME(syscall_trace) RESTORE_SWITCH_STACK addql #4,%sp jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0) - movel %d0,%sp@(LPT_OFF_D0) | save the return value + movel %d0,%sp@(PT_D0) | save the return value subql #4,%sp | dummy return address SAVE_SWITCH_STACK jbsr SYMBOL_NAME(syscall_trace) @@ -98,34 +100,34 @@ ENTRY(system_call) GET_CURRENT(%d0) | save top of frame - movel %sp,%curptr@(TS_ESP0) + movel %sp,%curptr@(TASK_TSS+TSS_ESP0) cmpl #NR_syscalls,%d2 jcc badsys - btst #LPF_TRACESYS_BIT,%curptr@(LTASK_FLAGS+LPF_TRACESYS_OFF) + btst #PF_TRACESYS_BIT,%curptr@(TASK_FLAGS+PF_TRACESYS_OFF) jne do_trace jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0) - movel %d0,%sp@(LPT_OFF_D0) | save the return value + movel %d0,%sp@(PT_D0) | save the return value SYMBOL_NAME_LABEL(ret_from_exception) - btst #5,%sp@(LPT_OFF_SR) | check if returning to kernel + btst #5,%sp@(PT_SR) | check if returning to kernel bnes 2f | if so, skip resched, signals | only allow interrupts when we are really the last one on the | kernel stack, otherwise stack overflow can occur during | heavy interupt load andw #ALLOWINT,%sr - tstl %curptr@(LTASK_NEEDRESCHED) + tstl %curptr@(TASK_NEEDRESCHED) jne SYMBOL_NAME(reschedule) cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals jeq 2f | check for delayed trace - bclr #LPF_DTRACE_BIT,%curptr@(LTASK_FLAGS+LPF_DTRACE_OFF) + bclr #PF_DTRACE_BIT,%curptr@(TASK_FLAGS+PF_DTRACE_OFF) jne do_delayed_trace 5: - tstl %curptr@(LTASK_STATE) | state + tstl %curptr@(TASK_STATE) | state jne SYMBOL_NAME(reschedule) - tstl %curptr@(LTASK_SIGPENDING) + tstl %curptr@(TASK_SIGPENDING) jne Lsignal_return 2: RESTORE_ALL @@ -141,7 +143,7 @@ Lsignal_return: RESTORE_ALL do_delayed_trace: - bclr #7,%sp@(LPT_OFF_SR) | clear trace bit in SR + bclr #7,%sp@(PT_SR) | clear trace bit in SR pea 1 | send SIGTRAP movel %curptr,%sp@- pea LSIGTRAP @@ -158,7 +160,7 @@ SYMBOL_NAME_LABEL(inthandler) GET_CURRENT(%d0) addql #1,SYMBOL_NAME(local_irq_count) | put exception # in d0 - bfextu %sp@(LPT_OFF_FORMATVEC){#4,#10},%d0 + bfextu %sp@(PT_VECTOR){#4,#10},%d0 movel %sp,%sp@- movel %d0,%sp@- | put vector # on stack @@ -172,7 +174,7 @@ SYMBOL_NAME_LABEL(ret_from_interrupt) RESTORE_ALL 1: #if 1 - bfextu %sp@(LPT_OFF_SR){#5,#3},%d0 | Check for nested interrupt. + bfextu %sp@(PT_SR){#5,#3},%d0 | Check for nested interrupt. #if MAX_NOINT_IPL > 0 cmpiw #MAX_NOINT_IPL,%d0 #endif @@ -210,6 +212,14 @@ ENTRY(sys_clone) RESTORE_SWITCH_STACK rts +ENTRY(sys_vfork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr SYMBOL_NAME(m68k_vfork) + addql #4,%sp + RESTORE_SWITCH_STACK + rts + ENTRY(sys_sigsuspend) SAVE_SWITCH_STACK pea %sp@(SWITCH_STACK_SIZE) @@ -240,37 +250,31 @@ ENTRY(sys_rt_sigreturn) SYMBOL_NAME_LABEL(resume) /* - * Beware - when entering resume, offset of tss is in d1, - * prev (the current task) is in a0, next (the new task) - * is in a1 and d2.b is non-zero if the mm structure is - * shared between the tasks, so don't change these + * Beware - when entering resume, prev (the current task) is + * in a0, next (the new task) is in a1,so don't change these * registers until their contents are no longer needed. */ - /* offset of tss struct (processor state) from beginning - of task struct */ - addl %d1,%a0 - /* save sr */ - movew %sr,%a0@(LTSS_SR) + movew %sr,%a0@(TASK_TSS+TSS_SR) /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ movec %sfc,%d0 - movew %d0,%a0@(LTSS_FS) + movew %d0,%a0@(TASK_TSS+TSS_FS) /* save usp */ /* it is better to use a movel here instead of a movew 8*) */ movec %usp,%d0 - movel %d0,%a0@(LTSS_USP) + movel %d0,%a0@(TASK_TSS+TSS_USP) /* save non-scratch registers on stack */ SAVE_SWITCH_STACK /* save current kernel stack pointer */ - movel %sp,%a0@(LTSS_KSP) + movel %sp,%a0@(TASK_TSS+TSS_KSP) /* save floating point context */ - fsave %a0@(LTSS_FPCTXT+27*4) + fsave %a0@(TASK_TSS+TSS_FPSTATE) #if defined(CONFIG_M68060) #if !defined(CPU_M68060_ONLY) @@ -278,27 +282,27 @@ SYMBOL_NAME_LABEL(resume) beqs 1f #endif /* The 060 FPU keeps status in bits 15-8 of the first longword */ - tstb %a0@(LTSS_FPCTXT+27*4+2) + tstb %a0@(TASK_TSS+TSS_FPSTATE+2) jeq 3f #if !defined(CPU_M68060_ONLY) jra 2f #endif #endif /* CONFIG_M68060 */ #if !defined(CPU_M68060_ONLY) -1: tstb %a0@(LTSS_FPCTXT+27*4) +1: tstb %a0@(TASK_TSS+TSS_FPSTATE) jeq 3f #endif -2: fmovemx %fp0-%fp7,%a0@(LTSS_FPCTXT) - fmoveml %fpcr/%fpsr/%fpiar,%a0@(LTSS_FPCTXT+24*4) +2: fmovemx %fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG) + fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL) 3: - /* get pointer to tss struct (a1 contains new task) */ + /* switch to new task (a1 contains new task) */ movel %a1,%curptr - addl %d1,%a1 /* Skip address space switching if they are the same. */ - tstb %d2 - jne 4f + movel %a0@(TASK_MM),%d0 + cmpl %a1@(TASK_MM),%d0 + jeq 4f #if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060) /* 68040 or 68060 ? */ @@ -316,7 +320,7 @@ SYMBOL_NAME_LABEL(resume) movec %d0,%cacr /* switch the root pointer */ - pmove %a1@(LTSS_CRP),%crp + pmove %a1@(TASK_TSS+TSS_CRP),%crp #endif #if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060) @@ -333,7 +337,7 @@ SYMBOL_NAME_LABEL(resume) pflushan /* switch the root pointer */ - movel %a1@(LTSS_CRP+4),%d0 + movel %a1@(TASK_TSS+TSS_CRP+4),%d0 movec %d0,%urp #if defined (CONFIG_M68060) @@ -359,37 +363,37 @@ SYMBOL_NAME_LABEL(resume) beqs 1f #endif /* The 060 FPU keeps status in bits 15-8 of the first longword */ - tstb %a1@(LTSS_FPCTXT+27*4+2) + tstb %a1@(TASK_TSS+TSS_FPSTATE+2) jeq 3f #if !defined(CPU_M68060_ONLY) jra 2f #endif #endif /* CONFIG_M68060 */ #if !defined(CPU_M68060_ONLY) -1: tstb %a1@(LTSS_FPCTXT+27*4) +1: tstb %a1@(TASK_TSS+TSS_FPSTATE) jeq 3f #endif -2: fmovemx %a1@(LTSS_FPCTXT),%fp0-%fp7 - fmoveml %a1@(LTSS_FPCTXT+24*4),%fpcr/%fpsr/%fpiar -3: frestore %a1@(LTSS_FPCTXT+27*4) +2: fmovemx %a1@(TASK_TSS+TSS_FPREG),%fp0-%fp7 + fmoveml %a1@(TASK_TSS+TSS_FPCNTL),%fpcr/%fpsr/%fpiar +3: frestore %a1@(TASK_TSS+TSS_FPSTATE) /* restore the kernel stack pointer */ - movel %a1@(LTSS_KSP),%sp + movel %a1@(TASK_TSS+TSS_KSP),%sp /* restore non-scratch registers */ RESTORE_SWITCH_STACK /* restore user stack pointer */ - movel %a1@(LTSS_USP),%a0 + movel %a1@(TASK_TSS+TSS_USP),%a0 movel %a0,%usp /* restore fs (sfc,%dfc) */ - movew %a1@(LTSS_FS),%a0 + movew %a1@(TASK_TSS+TSS_FS),%a0 movec %a0,%sfc movec %a0,%dfc /* restore status register */ - movew %a1@(LTSS_SR),%sr + movew %a1@(TASK_TSS+TSS_SR),%sr rts @@ -586,6 +590,7 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_sendfile) .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .long SYMBOL_NAME(sys_vfork) /* 190 */ .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 .long SYMBOL_NAME(sys_ni_syscall) 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 diff --git a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c index 122bf63be..e2e6715e7 100644 --- a/arch/m68k/kernel/m68k_defs.c +++ b/arch/m68k/kernel/m68k_defs.c @@ -10,14 +10,78 @@ #include <linux/stddef.h> #include <linux/sched.h> +#include <linux/kernel_stat.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/amigahw.h> +#include <video/font.h> #define DEFINE(sym, val) \ - asm volatile("\n#define " #sym " %0" : : "i" (val)) + asm volatile("\n#define " #sym " %c0" : : "i" (val)) int main(void) { - DEFINE(TS_TSS, offsetof(struct task_struct, tss)); - DEFINE(TS_ESP0, offsetof(struct task_struct, tss.esp0)); - DEFINE(TS_FPU, offsetof(struct task_struct, tss.fp)); + /* offsets into the task struct */ + DEFINE(TASK_STATE, offsetof(struct task_struct, state)); + DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, sigpending)); + DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, need_resched)); + DEFINE(TASK_TSS, offsetof(struct task_struct, tss)); + DEFINE(TASK_MM, offsetof(struct task_struct, mm)); + + /* offsets into the thread struct */ + DEFINE(TSS_KSP, offsetof(struct thread_struct, ksp)); + DEFINE(TSS_USP, offsetof(struct thread_struct, usp)); + DEFINE(TSS_SR, offsetof(struct thread_struct, sr)); + DEFINE(TSS_FS, offsetof(struct thread_struct, fs)); + DEFINE(TSS_CRP, offsetof(struct thread_struct, crp)); + DEFINE(TSS_ESP0, offsetof(struct thread_struct, esp0)); + DEFINE(TSS_FPREG, offsetof(struct thread_struct, fp)); + DEFINE(TSS_FPCNTL, offsetof(struct thread_struct, fpcntl)); + DEFINE(TSS_FPSTATE, offsetof(struct thread_struct, fpstate)); + + /* offsets into the pt_regs */ + DEFINE(PT_D0, offsetof(struct pt_regs, d0)); + DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0)); + DEFINE(PT_SR, offsetof(struct pt_regs, sr)); + + /* bitfields are a bit difficult */ + DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4); + + /* offsets into the irq_handler struct */ + DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler)); + DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id)); + DEFINE(IRQ_NEXT, offsetof(struct irq_node, next)); + + /* offsets into the kernel_stat struct */ + DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); + + /* offsets into the bi_record struct */ + DEFINE(BIR_TAG, offsetof(struct bi_record, tag)); + DEFINE(BIR_SIZE, offsetof(struct bi_record, size)); + DEFINE(BIR_DATA, offsetof(struct bi_record, data)); + + /* offsets into fbcon_font_desc (video/font.h) */ + DEFINE(FBCON_FONT_DESC_IDX, offsetof(struct fbcon_font_desc, idx)); + DEFINE(FBCON_FONT_DESC_NAME, offsetof(struct fbcon_font_desc, name)); + DEFINE(FBCON_FONT_DESC_WIDTH, offsetof(struct fbcon_font_desc, width)); + DEFINE(FBCON_FONT_DESC_HEIGHT, offsetof(struct fbcon_font_desc, height)); + DEFINE(FBCON_FONT_DESC_DATA, offsetof(struct fbcon_font_desc, data)); + DEFINE(FBCON_FONT_DESC_PREF, offsetof(struct fbcon_font_desc, pref)); + + /* offsets into the custom struct */ + DEFINE(CUSTOMBASE, &custom); + DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar)); + DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr)); + DEFINE(C_INTENA, offsetof(struct CUSTOM, intena)); + DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq)); + DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr)); + DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat)); + DEFINE(C_SERPER, offsetof(struct CUSTOM, serper)); + DEFINE(CIAABASE, &ciaa); + DEFINE(CIABBASE, &ciab); + DEFINE(C_PRA, offsetof(struct CIA, pra)); + DEFINE(ZTWOBASE, zTwoBase); + return 0; } diff --git a/arch/m68k/kernel/m68k_defs.h b/arch/m68k/kernel/m68k_defs.h index 992d390c7..b32e6a1c9 100644 --- a/arch/m68k/kernel/m68k_defs.h +++ b/arch/m68k/kernel/m68k_defs.h @@ -3,6 +3,6 @@ */ #define TS_MAGICKEY 0x5a5a5a5a -#define TS_TSS 478 -#define TS_ESP0 498 -#define TS_FPU 502 +#define TS_TSS 482 +#define TS_ESP0 502 +#define TS_FPU 506 diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 40b692e0c..793ca6ec7 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -13,6 +13,7 @@ #include <asm/machdep.h> #include <asm/pgtable.h> #include <asm/irq.h> +#include <asm/io.h> #include <asm/semaphore.h> #include <asm/checksum.h> #include <asm/hardirq.h> @@ -37,8 +38,10 @@ EXPORT_SYMBOL(mm_ptov); EXPORT_SYMBOL(mm_end_of_chunk); #endif EXPORT_SYMBOL(mm_vtop_fallback); +EXPORT_SYMBOL(m68k_realnum_memory); EXPORT_SYMBOL(m68k_memory); -EXPORT_SYMBOL(kernel_map); +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(m68k_debug_device); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_thread); @@ -49,6 +52,8 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(kernel_set_cachemode); +EXPORT_SYMBOL(kernel_thread); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index fb9bac400..c7c3f458e 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -56,16 +56,13 @@ asmlinkage void ret_from_exception(void); */ asmlinkage int sys_idle(void) { - int ret = -EPERM; - - lock_kernel(); if (current->pid != 0) - goto out; + return -EPERM; /* endless idle loop with no priority at all */ - current->priority = -100; + current->priority = 0; current->counter = -100; - for (;;){ + for (;;) { if (!current->need_resched) #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) /* block out HSYNC on the atari (falcon) */ @@ -73,14 +70,9 @@ asmlinkage int sys_idle(void) #else /* portable version */ __asm__("stop #0x2000" : : : "cc"); #endif /* machine compilation types */ - check_pgt_cache(); - run_task_queue(&tq_scheduler); schedule(); + check_pgt_cache(); } - ret = 0; -out: - unlock_kernel(); - return ret; } void machine_restart(char * __unused) @@ -115,6 +107,44 @@ void show_regs(struct pt_regs * regs) printk("USP: %08lx\n", rdusp()); } +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + int pid; + mm_segment_t fs; + + fs = get_fs(); + set_fs (KERNEL_DS); + + { + register long retval __asm__ ("d0"); + register long clone_arg __asm__ ("d1") = flags | CLONE_VM; + + __asm__ __volatile__ + ("clrl %%d2\n\t" + "trap #0\n\t" /* Linux/m68k system call */ + "tstl %0\n\t" /* child or parent */ + "jne 1f\n\t" /* parent - jump */ + "lea %%sp@(-8192),%6\n\t" /* reload current */ + "movel %3,%%sp@-\n\t" /* push argument */ + "jsr %4@\n\t" /* call fn */ + "movel %0,%%d1\n\t" /* pass exit value */ + "movel %2,%0\n\t" /* exit */ + "trap #0\n" + "1:" + : "=d" (retval) + : "0" (__NR_clone), "i" (__NR_exit), + "r" (arg), "a" (fn), "d" (clone_arg), "r" (current) + : "d0", "d2"); + pid = retval; + } + + set_fs (fs); + return pid; +} + void flush_thread(void) { unsigned long zero = 0; @@ -137,6 +167,19 @@ asmlinkage int m68k_fork(struct pt_regs *regs) return do_fork(SIGCHLD, rdusp(), regs); } +asmlinkage int m68k_vfork(struct pt_regs *regs) +{ + int child; + struct semaphore sem = MUTEX_LOCKED; + + child = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs); + + if (child > 0) + down(&sem); + + return child; +} + asmlinkage int m68k_clone(struct pt_regs *regs) { unsigned long clone_flags; @@ -147,7 +190,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs) newsp = regs->d2; if (!newsp) newsp = rdusp(); - return do_fork(clone_flags, newsp, regs); + return do_fork(clone_flags & ~CLONE_VFORK, newsp, regs); } int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 9888d83c1..5aeb2534b 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -325,12 +325,15 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = 0; goto out; } - if (pid == 1) /* you may not mess with init */ - goto out; ret = -ESRCH; - if (!(child = find_task_by_pid(pid))) + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!!! */ + if (!child) goto out; ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out; if (request == PTRACE_ATTACH) { if (child == current) goto out; @@ -375,7 +378,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_PEEKDATA: { unsigned long tmp; + down(&child->mm->mmap_sem); ret = read_long(child, addr, &tmp); + up(&child->mm->mmap_sem); if (ret >= 0) ret = put_user(tmp, (unsigned long *) data); goto out; @@ -408,7 +413,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: + down(&child->mm->mmap_sem); ret = write_long(child,addr,data); + up(&child->mm->mmap_sem); goto out; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index e12786344..ade12c46d 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -48,6 +48,7 @@ extern int end; extern unsigned long availmem; int m68k_num_memory = 0; +int m68k_realnum_memory = 0; struct mem_info m68k_memory[NUM_MEMINFO]; static struct mem_info m68k_ramdisk = { 0, 0 }; @@ -62,8 +63,6 @@ void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initd int (*mach_keyb_init) (void) __initdata; int (*mach_kbdrate) (struct kbd_repeat *) = NULL; void (*mach_kbd_leds) (unsigned int) = NULL; -/* machine dependent "kbd-reset" setup function */ -void (*kbd_reset_setup) (char *, int) __initdata = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata; void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; @@ -159,6 +158,7 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record)) record = (struct bi_record *)((u_long)record+record->size); } + m68k_realnum_memory = m68k_num_memory; #ifdef CONFIG_SINGLE_MEMORY_CHUNK if (m68k_num_memory > 1) { printk("Ignoring last %i chunks of physical memory\n", @@ -398,9 +398,9 @@ void floppy_eject(void) } #endif -__initfunc(unsigned long arch_kbd_init(void)) +/* for "kbd-reset" cmdline param */ +void __init kbd_reset_setup(char *str, int *ints) { - return mach_keyb_init(); } void arch_gettod(int *year, int *mon, int *day, int *hour, diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index af5af69b6..a2b9ce1d4 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -361,7 +361,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp, : "a0"); #undef frame_offset /* - * If we ever get here an exception occured while + * If we ever get here an exception occurred while * building the above stack-frame. */ goto badframe; @@ -460,7 +460,7 @@ rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, : "a0"); #undef frame_offset /* - * If we ever get here an exception occured while + * If we ever get here an exception occurred while * building the above stack-frame. */ goto badframe; diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 75da52541..a85da4e10 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -112,7 +112,8 @@ asmlinkage int old_select(struct sel_arg_struct *arg) * * This is really horribly ugly. */ -asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +asmlinkage int sys_ipc (uint call, int first, int second, + int third, void *ptr, long fifth) { int version, ret; @@ -122,88 +123,76 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, if (call <= SEMCTL) switch (call) { case SEMOP: - ret = sys_semop (first, (struct sembuf *)ptr, second); - goto out; + return sys_semop (first, (struct sembuf *)ptr, second); case SEMGET: - ret = sys_semget (first, second, third); - goto out; + return sys_semget (first, second, third); case SEMCTL: { union semun fourth; - ret = -EINVAL; if (!ptr) - goto out; - if ((ret = get_user(fourth.__pad, (void **) ptr))) - goto out; - ret = sys_semctl (first, second, third, fourth); - goto out; + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); } default: - ret = -EINVAL; - goto out; + return -EINVAL; } if (call <= MSGCTL) switch (call) { case MSGSND: - ret = sys_msgsnd (first, (struct msgbuf *) ptr, + return sys_msgsnd (first, (struct msgbuf *) ptr, second, third); - goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; - ret = -EINVAL; if (!ptr) - goto out; - ret = -EFAULT; - if (copy_from_user (&tmp, ptr, sizeof (tmp))) - goto out; - ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); - goto out; + return -EINVAL; + if (copy_from_user (&tmp, + (struct ipc_kludge *)ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); } - case 1: default: - ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); - goto out; + default: + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); } case MSGGET: - ret = sys_msgget ((key_t) first, second); - goto out; + return sys_msgget ((key_t) first, second); case MSGCTL: - ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); - goto out; + return sys_msgctl (first, second, + (struct msqid_ds *) ptr); default: - ret = -EINVAL; - goto out; + return -EINVAL; } if (call <= SHMCTL) switch (call) { case SHMAT: switch (version) { - case 0: default: { + default: { ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); + ret = sys_shmat (first, (char *) ptr, + second, &raddr); if (ret) - goto out; - ret = put_user (raddr, (ulong *) third); - goto out; + return ret; + return put_user (raddr, (ulong *) third); } } case SHMDT: - ret = sys_shmdt ((char *)ptr); - goto out; + return sys_shmdt ((char *)ptr); case SHMGET: - ret = sys_shmget (first, second, third); - goto out; + return sys_shmget (first, second, third); case SHMCTL: - ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); - goto out; + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); default: - ret = -EINVAL; - goto out; + return -EINVAL; } - ret = -EINVAL; -out: - unlock_kernel(); - return ret; + + return -EINVAL; } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 8f11a00d8..107d0de7f 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -5,6 +5,9 @@ * * This file contains the m68k-specific time handling details. * Most of the stuff is located in the machine specific files. + * + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills */ #include <linux/config.h> /* CONFIG_HEARTBEAT */ @@ -65,9 +68,10 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. */ - if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec > 500000 - (tick >> 1) && - xtime.tv_usec < 500000 + (tick >> 1)) { + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && + xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else @@ -146,27 +150,38 @@ void time_init(void) mach_sched_init(timer_interrupt); } +extern rwlock_t xtime_lock; + /* * This version of gettimeofday has near microsecond resolution. */ void do_gettimeofday(struct timeval *tv) { + extern volatile unsigned long lost_ticks; unsigned long flags; - - save_flags(flags); - cli(); - *tv = xtime; - tv->tv_usec += mach_gettimeoffset(); - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; + unsigned long usec, sec, lost; + + read_lock_irqsave(&xtime_lock, flags); + usec = mach_gettimeoffset(); + lost = lost_ticks; + if (lost) + usec += lost * (1000000/HZ); + sec = xtime.tv_sec; + usec += xtime.tv_usec; + read_unlock_irqrestore(&xtime_lock, flags); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; } - restore_flags(flags); + + tv->tv_sec = sec; + tv->tv_usec = usec; } void do_settimeofday(struct timeval *tv) { - cli(); + write_lock_irq(&xtime_lock); /* This is revolting. We need to set the xtime.tv_usec * correctly. However, the value in this location is * is value at the last tick. @@ -175,14 +190,16 @@ void do_settimeofday(struct timeval *tv) */ tv->tv_usec -= mach_gettimeoffset(); - if (tv->tv_usec < 0) { + while (tv->tv_usec < 0) { tv->tv_usec += 1000000; tv->tv_sec--; } xtime = *tv; - time_state = TIME_BAD; - time_maxerror = MAXPHASE; - time_esterror = MAXPHASE; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_state = TIME_ERROR; /* p. 24, (a) */ + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; sti(); } diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index f410182e0..8e902d0bd 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -55,9 +55,6 @@ extern char m68k_command_line[CL_SIZE]; void *mac_env; /* Loaded by the boot asm */ -/* The logical video addr. determined by head.S - testing */ -extern unsigned long mac_videobase; - /* The phys. video addr. - might be bogus on some machines */ unsigned long mac_orig_videoaddr; @@ -65,7 +62,6 @@ unsigned long mac_orig_videoaddr; extern int mac_keyb_init(void); extern int mac_kbdrate(struct kbd_repeat *k); extern void mac_kbd_leds(unsigned int leds); -extern void mac_kbd_reset_setup(char*, int); /* Mac specific irq functions */ extern void mac_init_IRQ (void); @@ -100,17 +96,15 @@ extern void mac_debug_init(void); extern void mac_debugging_long(int, long); #ifdef CONFIG_MAGIC_SYSRQ - -/* XXX FIXME: Atari scancodes still */ static char mac_sysrq_xlate[128] = - "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ - "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ - "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ - "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ - "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */ - "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ - "\000\000\000()/*789456123" /* 0x60 - 0x6f */ - "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ + "\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80)o" /* 0x10 - 0x1f */ + "u(ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\000\033\000\000\000\000\000\000\000\000\000\000\000" /* 0x30 - 0x3f */ + "\000.\000*\000+\000\000\000\000\000/\r\000-\000" /* 0x40 - 0x4f */ + "\000\00001234567a89\000\000\000" /* 0x50 - 0x5f */ + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x60 - 0x6f */ + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ #endif extern void (*kd_mksound)(unsigned int, unsigned int); @@ -243,9 +237,7 @@ __initfunc(int mac_parse_bootinfo(const struct bi_record *record)) mac_bi_data.id = *data; break; case BI_MAC_VADDR: - /* save booter supplied videobase; use the one mapped in head.S! */ - mac_orig_videoaddr = *data; - mac_bi_data.videoaddr = mac_videobase; + mac_bi_data.videoaddr = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); break; case BI_MAC_VDEPTH: mac_bi_data.videodepth = *data; @@ -309,7 +301,6 @@ __initfunc(void config_mac(void)) mach_keyb_init = mac_keyb_init; mach_kbdrate = mac_kbdrate; mach_kbd_leds = mac_kbd_leds; - kbd_reset_setup = mac_kbd_reset_setup; mach_init_IRQ = mac_init_IRQ; mach_request_irq = mac_request_irq; mach_free_irq = mac_free_irq; @@ -336,7 +327,7 @@ __initfunc(void config_mac(void)) #endif kd_mksound = mac_mksound; #ifdef CONFIG_MAGIC_SYSRQ - mach_sysrq_key = 98; /* HELP */ + mach_sysrq_key = 114; /* HELP */ mach_sysrq_shift_state = 8; /* Alt */ mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */ mach_sysrq_xlate = mac_sysrq_xlate; @@ -399,10 +390,10 @@ static struct mac_model mac_data_table[]= * */ - { MAC_MODEL_II, "II", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS}, - { MAC_MODEL_IIX, "IIx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS}, - { MAC_MODEL_IICX, "IIcx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS}, - { MAC_MODEL_SE30, "SE/30", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS}, + { MAC_MODEL_II, "II", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_IIX, "IIx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_IICX, "IIcx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_SE30, "SE/30", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, /* * Weirdified MacII hardware - all subtley different. Gee thanks @@ -425,7 +416,7 @@ static struct mac_model mac_data_table[]= */ { MAC_MODEL_CLII, "Classic II", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_CCL, "Color Classic", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_CCL, "Color Classic", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, /* * Some Mac LC machines. Basically the same as the IIci, ADB like IIsi @@ -461,11 +452,11 @@ static struct mac_model mac_data_table[]= * Performa - more LC type machines */ - { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, @@ -477,8 +468,8 @@ static struct mac_model mac_data_table[]= * Centris - just guessing again; maybe like Quadra */ - { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, /* @@ -551,7 +542,7 @@ void mac_identify(void) m++; } if(m->ident==-1) - mac_boom(5); + panic("mac model config data corrupt!\n"); } /* diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c index 62a8a6187..5aa7ce6cf 100644 --- a/arch/m68k/mac/debug.c +++ b/arch/m68k/mac/debug.c @@ -36,7 +36,10 @@ extern unsigned long mac_videobase; extern unsigned long mac_videodepth; extern unsigned long mac_rowbytes; -#define DEBUG_SCREEN +extern void mac_serial_print(char *); + +#define DEBUG_HEADS +#undef DEBUG_SCREEN #define DEBUG_SERIAL /* @@ -129,121 +132,6 @@ void mac_debugging_long(int pos, long addr) #endif } -/* - * Penguin - used by head.S console; obsolete - */ -char that_penguin[]={ -#include "that_penguin.h" -}; - -#ifdef DEBUG_SCREEN -/* - * B/W version of penguin, unfinished - any takers?? - */ -static char bw_penguin[]={ -#include "bw_penguin.h" -}; -#endif - -void mac_debugging_penguin(int peng) -{ -#ifdef DEBUG_SCREEN - unsigned char *pengoffset; - unsigned char *pptr; - unsigned char *bwpdptr=bw_penguin; - int i; -#endif - -#ifdef DEBUG_SERIAL - printk("Penguin: #%d !\n", peng); -#endif - -#ifdef DEBUG_SCREEN - if (!MACH_IS_MAC) - return; - - if (mac_videodepth ==1) - pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes) - +5*peng; - else - pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes) - +20*peng; - - pptr=pengoffset; - - for(i=0;i<36;i++) - { - memcpy(pptr,bwpdptr,4); - bwpdptr+=4; - pptr+=mac_rowbytes; - } -#endif -} - -#ifdef DEBUG_SCREEN -/* - * B/W version of flaming Mac, unfinished (see above). - */ -static char bw_kaboom_map[]={ -#include "bw_mac.h" -}; -#endif - -#ifdef DEBUG_SCREEN -static void mac_boom_boom(void) -{ - static unsigned char *boomoffset=NULL; - unsigned char *pptr; - unsigned char *bwpdptr=bw_kaboom_map; - int i; - -#ifdef DEBUG_SERIAL - printk("BOOM !\n"); -#endif - - if (!MACH_IS_MAC) - return; - - if(!boomoffset) - if (mac_videodepth == 1) { - boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes); - } else { - boomoffset=(unsigned char *)(mac_videobase+256*mac_rowbytes); - } - else - if (mac_videodepth == 1) - boomoffset+=5; - else - boomoffset+=32; - - pptr=boomoffset; - - for(i=0;i<36;i++) - { - memcpy(pptr,bwpdptr,4); - bwpdptr+=4; - pptr+=mac_rowbytes; - } -} -#endif - -void mac_boom(int booms) -{ -#ifdef DEBUG_SCREEN - int i; -#endif - - if (!MACH_IS_MAC) - return; - -#ifdef DEBUG_SCREEN - for(i=0;i<booms;i++) - mac_boom_boom(); - while(1); -#endif -} - - #ifdef DEBUG_SERIAL /* * TODO: serial debug code @@ -284,6 +172,29 @@ static struct console mac_console_driver = { NULL }; +/* + * Crude hack to get console output to the screen before the framebuffer + * is initialized (happens a lot later in 2.1!). + * We just use the console routines declared in head.S, this will interfere + * with regular framebuffer console output and should be used exclusively + * to debug kernel problems manifesting before framebuffer init (aka WSOD) + * + * To keep this hack from interfering with the regular console driver, either + * deregister this driver before/on framebuffer console init, or silence this + * function after the fbcon driver is running (will lose console messages!?). + * To debug real early bugs, need to write a 'mac_register_console_hack()' + * that is called from start_kernel() before setup_arch() and just registers + * this driver if Mac. + */ + +void mac_debug_console_write (struct console *co, const char *str, + unsigned int count) +{ + mac_serial_print(str); +} + + + /* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/ #define uSEC 1 @@ -486,19 +397,30 @@ __initfunc(void mac_debug_init(void)) /* Mac modem port */ mac_init_scc_port( B9600|CS8, 0 ); mac_console_driver.write = mac_scca_console_write; +#ifdef CONFIG_SERIAL_CONSOLE mac_console_driver.wait_key = mac_scca_console_wait_key; +#endif scc_port = 0; } else if (!strcmp( m68k_debug_device, "ser2" )) { /* Mac printer port */ mac_init_scc_port( B9600|CS8, 1 ); mac_console_driver.write = mac_sccb_console_write; +#ifdef CONFIG_SERIAL_CONSOLE mac_console_driver.wait_key = mac_sccb_console_wait_key; +#endif scc_port = 1; } +#endif +#ifdef DEBUG_HEADS + if ( !strcmp( m68k_debug_device, "scn" ) + || !strcmp( m68k_debug_device, "con" )) { + /* display, using head.S console routines */ + mac_console_driver.write = mac_debug_console_write; + } +#endif if (mac_console_driver.write) register_console(&mac_console_driver); -#endif } /* diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c index 95078a384..1731c929c 100644 --- a/arch/m68k/mac/macboing.c +++ b/arch/m68k/mac/macboing.c @@ -1,6 +1,12 @@ /* * Mac bong noise generator. Note - we ought to put a boingy noise * here 8) + * + * ---------------------------------------------------------------------- + * 16.11.98: + * rewrote some functions, added support for Enhanced ASC (Quadras) + * after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck + * Juergen Mellinger (juergen.mellinger@t-online.de) */ #include <linux/sched.h> @@ -9,124 +15,281 @@ #include <asm/macintosh.h> #include <asm/mac_asc.h> +static int mac_asc_inited = 0; +/* + * dumb triangular wave table + */ +static __u8 mac_asc_wave_tab[ 0x800 ]; + +/* + * Alan's original sine table; needs interpolating to 0x800 + * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric) + */ static const signed char sine_data[] = { 0, 39, 75, 103, 121, 127, 121, 103, 75, 39, 0, -39, -75, -103, -121, -127, -121, -103, -75, -39 }; -#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0])) -static void nosound( unsigned long ignored ); -static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound }; +/* + * where the ASC hides ... + */ +static volatile __u8* mac_asc_regs = ( void* )0x50F14000; -static volatile unsigned char *asc_base=(void *)0x50F14000; +/* + * sample rate; is this a good default value? + */ +static unsigned long mac_asc_samplespersec = 11050; +static int mac_bell_duration = 0; +static unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */ +static unsigned long mac_bell_phasepersample; + +/* + * some function protos + */ +static void mac_init_asc( void ); +static void mac_nosound( unsigned long ); +static void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int ); +static void mac_quadra_ring_bell( unsigned long ); +static void mac_av_start_bell( unsigned int, unsigned int, unsigned int ); +static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ) = NULL; +/* + * our timer to start/continue/stop the bell + */ +static struct timer_list mac_sound_timer = { NULL, NULL, 0, 0, mac_nosound }; -void mac_mksound( unsigned int hz, unsigned int ticks ) +/* + * Sort of initialize the sound chip (called from mac_mksound on the first + * beep). + */ +static void mac_init_asc( void ) { - static int inited = 0; - unsigned long flags; - int samples=512; + int i; - if (macintosh_config->ident == MAC_MODEL_C660 - || macintosh_config->ident == MAC_MODEL_Q840) + /* + * do some machine specific initialization + * BTW: + * the NetBSD Quadra patch identifies the Enhanced Apple Sound Chip via + * mac_asc_regs[ 0x800 ] & 0xF0 != 0 + * this makes no sense here, because we have to set the default sample + * rate anyway if we want correct frequencies + */ + switch ( macintosh_config->ident ) { - /* - * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O. - * It appears to be similar to the "AWACS" custom ASIC in the Power Mac - * [678]100. Because Singer and AWACS may have a similar hardware - * interface, this would imply that the code in drivers/sound/dmasound.c - * for AWACS could be used as a basis for Singer support. All we have to - * do is figure out how to do DMA on the 660AV/840AV through the PSC and - * figure out where the Singer hardware sits in memory. (I'd look in the - * vicinity of the AWACS location in a Power Mac [678]100 first, or the - * current location of the Apple Sound Chip--ASC--in other Macs.) The - * Power Mac [678]100 info can be found in MkLinux Mach kernel sources. - * - * Quoted from Apple's Tech Info Library, article number 16405: - * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power - * Macintosh models have 16-bit audio input and output capability - * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer - * codec circuitry in the AVs. The Audio Waveform Amplifier and - * Converter (AWAC) chip in the Power Macintosh performs the same - * 16-bit I/O functionality. The PowerBook 500 series computers - * support 16-bit stereo output, but only mono input." - * - * http://til.info.apple.com/techinfo.nsf/artnum/n16405 - * - * --David Kilzer - */ + case MAC_MODEL_IIFX: + /* + * The IIfx is always special ... + */ + mac_asc_regs = ( void* )0x50010000; + break; + /* + * not sure about how correct this list is + * machines with the EASC enhanced apple sound chip + */ + case MAC_MODEL_Q630: + case MAC_MODEL_P475: + mac_special_bell = mac_quadra_start_bell; + mac_asc_samplespersec = 22150; + break; + case MAC_MODEL_Q650: + case MAC_MODEL_Q700: + case MAC_MODEL_Q800: + case MAC_MODEL_Q900: + case MAC_MODEL_Q950: + /* + * Currently not implemented! + */ + /* + * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O. + * It appears to be similar to the "AWACS" custom ASIC in the Power Mac + * [678]100. Because Singer and AWACS may have a similar hardware + * interface, this would imply that the code in drivers/sound/dmasound.c + * for AWACS could be used as a basis for Singer support. All we have to + * do is figure out how to do DMA on the 660AV/840AV through the PSC and + * figure out where the Singer hardware sits in memory. (I'd look in the + * vicinity of the AWACS location in a Power Mac [678]100 first, or the + * current location of the Apple Sound Chip--ASC--in other Macs.) The + * Power Mac [678]100 info can be found in MkLinux Mach kernel sources. + * + * Quoted from Apple's Tech Info Library, article number 16405: + * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power + * Macintosh models have 16-bit audio input and output capability + * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer + * codec circuitry in the AVs. The Audio Waveform Amplifier and + * Converter (AWAC) chip in the Power Macintosh performs the same + * 16-bit I/O functionality. The PowerBook 500 series computers + * support 16-bit stereo output, but only mono input." + * + * http://til.info.apple.com/techinfo.nsf/artnum/n16405 + * + * --David Kilzer + */ + mac_special_bell = mac_av_start_bell; + break; + } + + /* + * init the wave table with a simple triangular wave + * A sine wave would sure be nicer here ... + */ + for ( i = 0; i < 0x400; i++ ) + { + mac_asc_wave_tab[ i ] = i / 4; + mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4; + } + mac_asc_inited = 1; +} +/* + * Called to make noise; current single entry to the boing driver. + * Does the job for simple ASC, calls other routines else. + * XXX Fixme: + * Should be split into asc_mksound, easc_mksound, av_mksound and + * function pointer set in mac_init_asc which would be called at + * init time. + * _This_ is rather ugly ... + */ +void mac_mksound( unsigned int freq, unsigned int length ) +{ + __u32 cfreq = ( freq << 5 ) / 468; + __u32 flags; + int i; + + if ( !mac_asc_inited ) + mac_init_asc(); + + if ( mac_special_bell ) + { + mac_special_bell( freq, length, 128 ); return; } - - if(!inited) + + if ( freq < 20 || freq > 20000 || length == 0 ) { - int i=0; - int j=0; - int k=0; - int l=0; - - /* - * The IIfx strikes again! - */ - - if(macintosh_config->ident==MAC_MODEL_IIFX) - asc_base=(void *)0x50010000; - - for(i=0;i<samples;i++) - { - asc_base[i]=sine_data[j]; - asc_base[i+512]=sine_data[j]; - asc_base[i+1024]=sine_data[j]; - asc_base[i+1536]=sine_data[j]; - j++; - if(j==DATA_SIZE) - j=0; - if(i&1) - k++; - if(k==DATA_SIZE) - k=0; - if((i&3)==3) - l++; - if(l==DATA_SIZE) - l=0; - } - inited=1; + mac_nosound( 0 ); + return; } - save_flags(flags); + + save_flags( flags ); cli(); - del_timer( &sound_timer ); - if (hz > 20 && hz < 32767) { - int i; - u_long asc_pulses=((hz<<5)*samples)/468; - for(i=0;i<4;i++) + del_timer( &mac_sound_timer ); + + for ( i = 0; i < 0x800; i++ ) + mac_asc_regs[ i ] = 0; + for ( i = 0; i < 0x800; i++ ) + mac_asc_regs[ i ] = mac_asc_wave_tab[ i ]; + + for ( i = 0; i < 8; i++ ) + *( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq; + + mac_asc_regs[ 0x807 ] = 0; + mac_asc_regs[ ASC_VOLUME ] = 128; + mac_asc_regs[ 0x805 ] = 0; + mac_asc_regs[ 0x80F ] = 0; + mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE; + mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE; + + mac_sound_timer.expires = jiffies + length; + add_timer( &mac_sound_timer ); + + restore_flags( flags ); +} + +/* + * regular ASC: stop whining .. + */ +static void mac_nosound( unsigned long ignored ) +{ + mac_asc_regs[ ASC_ENABLE ] = 0; +} + +/* + * EASC entry; init EASC, don't load wavetable, schedule 'start whining'. + */ +static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) +{ + __u32 flags; + + /* if the bell is already ringing, ring longer */ + if ( mac_bell_duration > 0 ) + { + mac_bell_duration += length; + return; + } + + mac_bell_duration = length; + mac_bell_phase = 0; + mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec; + /* this is reasonably big for small frequencies */ + + save_flags( flags ); + cli(); + + /* set the volume */ + mac_asc_regs[ 0x806 ] = volume; + + /* set up the ASC registers */ + if ( mac_asc_regs[ 0x801 ] != 1 ) + { + /* select mono mode */ + mac_asc_regs[ 0x807 ] = 0; + /* select sampled sound mode */ + mac_asc_regs[ 0x802 ] = 0; + /* ??? */ + mac_asc_regs[ 0x801 ] = 1; + mac_asc_regs[ 0x803 ] |= 0x80; + mac_asc_regs[ 0x803 ] &= 0x7F; + } + + mac_sound_timer.function = mac_quadra_ring_bell; + mac_sound_timer.expires = jiffies + 1; + add_timer( &mac_sound_timer ); + + restore_flags( flags ); +} + +/* + * EASC 'start/continue whining'; I'm not sure why the above function didn't + * already load the wave table, or at least call this one... + * This piece keeps reloading the wave table until done. + */ +static void mac_quadra_ring_bell( unsigned long ignored ) +{ + int i, count = mac_asc_samplespersec / HZ; + __u32 flags; + + /* + * we neither want a sound buffer overflow nor underflow, so we need to match + * the number of samples per timer interrupt as exactly as possible. + * using the asc interrupt will give better results in the future + * ...and the possibility to use a real sample (a boingy noise, maybe...) + */ + + save_flags( flags ); + cli(); + + del_timer( &mac_sound_timer ); + + if ( mac_bell_duration-- > 0 ) + { + for ( i = 0; i < count; i++ ) { - asc_base[ASC_FREQ(i,0)]=0x00; - asc_base[ASC_FREQ(i,1)]=20; - asc_base[ASC_FREQ(i,2)]=0x00; - asc_base[ASC_FREQ(i,3)]=20; - asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF; - asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF; - asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF; - asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF; + mac_bell_phase += mac_bell_phasepersample; + mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ]; } - asc_base[ASC_CHAN]=0x03; - asc_base[ASC_VOLUME]=128; - asc_base[ASC_MODE]=ASC_MODE_SAMPLE; - asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE; - if (ticks) { - sound_timer.expires = jiffies + ticks; - add_timer( &sound_timer ); - } - } else { - nosound( 0 ); + mac_sound_timer.expires = jiffies + 1; + add_timer( &mac_sound_timer ); } - restore_flags(flags); + else + mac_asc_regs[ 0x801 ] = 0; + + restore_flags( flags ); } - -static void nosound( unsigned long ignored ) +/* + * AV code - please fill in. + */ +static void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) { - asc_base[ASC_ENABLE]=0; -} +} diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index b703cb275..87e6692d4 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c @@ -163,7 +163,14 @@ static unsigned long nubus_irqs[8]; static unsigned long *mac_irqs[8]; /* - * VIA2 / RBV register base pointers + * Some special nutcases ... + */ + +static unsigned long mac_ide_irqs = 0; +static unsigned long nubus_stuck_events = 0; + +/* + * VIA/RBV/OSS/PSC register base pointers */ volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS; @@ -217,9 +224,13 @@ void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs); static void via_do_nubus(int slot, void *via, struct pt_regs *regs); /* #define DEBUG_MACINTS */ -/* #define DEBUG_NUBUS_INT */ + +#define DEBUG_SPURIOUS +#define DEBUG_NUBUS_SPURIOUS +#define DEBUG_NUBUS_INT + /* #define DEBUG_VIA */ -/* #define DEBUG_VIA_NUBUS */ +#define DEBUG_VIA_NUBUS void mac_init_IRQ(void) { @@ -247,7 +258,7 @@ void mac_init_IRQ(void) /* yes, this is messy - the IIfx deserves a class of his own */ if (macintosh_config->ident == MAC_MODEL_IIFX) { - /* no real VIA2, the OSS seems _very_different */ + /* no real VIA2, the OSS seems _very_ different */ via2_is_oss = 1; /* IIfx has OSS, at a different base address than RBV */ rbv_regp = (unsigned char *) OSS_BAS; @@ -351,6 +362,12 @@ void mac_init_IRQ(void) mac_irqs[7] = &nubus_irqs[0]; /* + * Nubus Macs: turn off the Nubus dispatch interrupt for now + */ + + mac_turnoff_irq(IRQ_MAC_NUBUS); + + /* * AV Macs: shutup the PSC ints */ if (macintosh_config->ident == MAC_MODEL_C660 @@ -430,8 +447,10 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re return 0; } - /* add similar hack for Nubus pseudo-irq here - hide nubus_request_irq */ - + /* + * code below: only for VIA irqs currently + * add similar hack for Nubus pseudo-irq here - hide nubus_request_irq + */ via = (volatile unsigned char *) via_table[srcidx]; if (!via) return -EINVAL; @@ -459,7 +478,7 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re if (irq == IRQ_IDX(IRQ_MAC_SCSI)) { /* * Set vPCR for SCSI interrupts. (what about RBV here?) - * 980429 MS: RBV is ok, OSS seems to be differentt + * 980429 MS: RBV is ok, OSS seems to be different */ if (!via2_is_oss) if (macintosh_config->scsi_type == MAC_SCSI_OLD) { @@ -602,7 +621,10 @@ void mac_disable_irq (unsigned int irq) /* * In opposite to {en,dis}able_irq, requests between turn{off,on}_irq are not - * "stored". This is done with the VIA interrupt enable register + * "stored". This is done with the VIA interrupt enable register on VIAs. + * + * Note: Using these functions on non-VIA/OSS/PSC ints will panic, or at least + * have undesired side effects. */ void mac_turnon_irq( unsigned int irq ) @@ -615,14 +637,14 @@ void mac_turnon_irq( unsigned int irq ) if (!via) return; - if (srcidx == SRC_VIA2 && via2_is_rbv) + if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */ via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); - else if (srcidx == SRC_VIA2 && via2_is_oss) + else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */ via_write(oss_regp, oss_map[irqidx]+8, 2); - else if (srcidx > SRC_VIA2) + else if (srcidx > SRC_VIA2) /* hope AVs have VIA2 */ via_write(via, (0x104 + 0x10*srcidx), via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx))); - else + else /* VIA1+2 */ via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx))); } @@ -637,9 +659,9 @@ void mac_turnoff_irq( unsigned int irq ) if (!via) return; - if (srcidx == SRC_VIA2 && via2_is_rbv) + if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */ via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx))); - else if (srcidx == SRC_VIA2 && via2_is_oss) + else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */ via_write(oss_regp, oss_map[irqidx]+8, 0); /* * VIA2 is fixed. The stuff above VIA2 is for later @@ -648,7 +670,7 @@ void mac_turnoff_irq( unsigned int irq ) else if (srcidx > SRC_VIA2) via_write(via, (0x104 + 0x10*srcidx), via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx))); - else + else /* VIA1+2 */ via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx))); } @@ -694,12 +716,18 @@ int mac_irq_pending( unsigned int irq ) return (pending); } +/* + * for /proc/interrupts: log interrupt stats broken down by + * autovector int first, then by actual interrupt source. + */ + int mac_get_irq_list (char *buf) { int i, len = 0; int srcidx, irqidx; for (i = VIA1_SOURCE_BASE; i < NUM_MAC_SOURCES+8; ++i) { + /* XXX fixme: IRQ_SRC_MASK should cover VIA1 - Nubus */ srcidx = ((i & IRQ_SRC_MASK)>>3) - 1; irqidx = (i & IRQ_IDX_MASK); @@ -764,6 +792,32 @@ int mac_get_irq_list (char *buf) } if (num_spurious) len += sprintf(buf+len, "spurio.: %10u\n", num_spurious); + + /* + * XXX Fixme: Nubus sources are never logged above ... + */ + + len += sprintf(buf+len, "Nubus interrupts:\n"); + + for (i = 0; i < 7; i++) { + if (nubus_handler[i].handler == nubus_wtf) + continue; + len += sprintf(buf+len, "nubus %01X: %10lu ", + i+9, + nubus_irqs[i]); + len += sprintf(buf+len, "%s\n", + nubus_param[i].devname); + + } + len += sprintf(buf+len, "nubus spurious ints: %10lu\n", + nubus_irqs[7]); + len += sprintf(buf+len, "nubus stuck events : %10lu\n", + nubus_stuck_events); +#ifdef CONFIG_BLK_DEV_IDE + len += sprintf(buf+len, "nubus/IDE interrupt: %10lu\n", + mac_ide_irqs); +#endif + return len; } @@ -784,8 +838,9 @@ void via_scsi_clear(void) void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs) { -#ifdef DEBUG_VIA - printk("Unexpected IRQ %d\n", irq); +#ifdef DEBUG_SPURIOUS + if (console_loglevel > 6) + printk("Unexpected IRQ %d on device %p\n", irq, dev_id); #endif } @@ -861,6 +916,18 @@ void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp) } /* + * Unexpected via interrupt + */ + +void via_wtf(int slot, void *via, struct pt_regs *regs) +{ +#ifdef DEBUG_SPURIOUS + if (console_loglevel > 6) + printk("Unexpected nubus event %d on via %p\n",slot,via); +#endif +} + +/* * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's * via6522.c :-), disable/pending masks added. * The int *viaidx etc. is just to keep the prototype happy ... @@ -1115,17 +1182,6 @@ void rbv_irq(int irq, void *dev_id, struct pt_regs *regs) } /* - * Unexpected via interrupt - */ - -void via_wtf(int slot, void *via, struct pt_regs *regs) -{ -#ifdef DEBUG_VIA - printk("Unexpected event %d on via %p\n",slot,via); -#endif -} - -/* * Nubus / SCSI interrupts; OSS style * The OSS is even more different than the RBV. OSS appears to stand for * Obscenely Screwed Silicon ... @@ -1264,8 +1320,9 @@ void oss_irq(int irq, void *dev_id, struct pt_regs *regs) void nubus_wtf(int slot, void *via, struct pt_regs *regs) { -#ifdef DEBUG_VIA_NUBUS - printk("Unexpected interrupt on nubus slot %d\n",slot); +#ifdef DEBUG_NUBUS_SPURIOUS + if (console_loglevel > 6) + printk("Unexpected interrupt on nubus slot %d\n",slot); #endif } @@ -1279,9 +1336,10 @@ void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs) int i; /* 1+2: compatibility with PSC ! */ for (i = 1; i < 3; i++) /* currently only these two used */ - if (scc_handler[i].handler != mac_default_handler) + if (scc_handler[i].handler != mac_default_handler) { (scc_handler[i].handler)(i, scc_handler[i].dev_id, regs); - + scc_irqs[i]++; + } } /* @@ -1310,7 +1368,7 @@ void psc_irq(int irq, void *dev_id, struct pt_regs *regs) if(events==0) { #ifdef DEBUG_VIA - printk("rbv_irq: nothing pending, flags %x mask %x!\n", + printk("psc_irq: nothing pending, flags %x mask %x!\n", via_read(via, pIFR), via_read(via,pIER)); #endif mac_irqs[srcidx][7]++; @@ -1319,7 +1377,7 @@ void psc_irq(int irq, void *dev_id, struct pt_regs *regs) #ifdef DEBUG_VIA /* - * limited verbosity for RBV interrupts (add more if needed) + * limited verbosity for PSC interrupts (add more if needed) */ if ( srcidx == 1 && events != 1<<3 && events != 1<<1 ) /* SCSI IRQ */ printk("psc_irq: irq %d srcidx+1 %d events %x !\n", irq, srcidx+1, events); @@ -1423,6 +1481,7 @@ int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct if (!nubus_active && !via2_is_oss) { request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK, "nubus dispatch", via_do_nubus); + mac_turnon_irq(IRQ_MAC_NUBUS); } nubus_active|=1<<slot; @@ -1472,6 +1531,7 @@ int nubus_free_irq(int slot) * IDE interrupt hook */ extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *); +extern int (*mac_ide_irq_p_hook)(void); #endif /* @@ -1479,13 +1539,13 @@ extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *); */ static void via_do_nubus(int slot, void *via, struct pt_regs *regs) { - unsigned char map; + unsigned char map, allints; int i; int ct=0; - -/* printk("nubus interrupt\n");*/ + int ide_pending = 0; /* lock the nubus interrupt */ + /* That's just 'clear Nubus IRQ bit in VIA2' BTW. Pretty obsolete ? */ if (via2_is_rbv) via_write(rbv_regp, rIFR, 0x82); else @@ -1493,36 +1553,69 @@ static void via_do_nubus(int slot, void *via, struct pt_regs *regs) #ifdef CONFIG_BLK_DEV_MAC_IDE /* IDE hack */ - if (mac_ide_intr_hook) + if (mac_ide_intr_hook) { /* 'slot' is lacking the machspec bit in 2.0 */ /* need to pass proper dev_id = hwgroup here */ mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs); + mac_ide_irqs++; + } #endif while(1) { if (via2_is_rbv) - map = ~via_read(rbv_regp, rBufA); + allints = ~via_read(rbv_regp, rBufA); else - map = ~via_read(via2_regp, vBufA); + allints = ~via_read(via2_regp, vBufA); - if( (map = (map&nubus_active)) ==0 ) { -#ifdef DEBUG_NUBUS_INT - printk("nubus_irq: nothing pending, map %x mask %x\n", - map, nubus_active); +#ifdef CONFIG_BLK_DEV_MAC_IDE + if (mac_ide_irq_p_hook) + ide_pending = mac_ide_irq_p_hook(); +#endif + + if ( (map = (allints&nubus_active)) == 0 +#ifdef CONFIG_BLK_DEV_MAC_IDE + && !ide_pending #endif - nubus_irqs[7]++; + ) + { + if (ct == 0) { +#ifdef DEBUG_VIA_NUBUS + if (console_loglevel > 5) + printk("nubus_irq: nothing pending, map %x mask %x active %x\n", + allints, nubus_active, map); +#endif + nubus_irqs[7]++; + } + /* clear it */ + if (allints) + if (via2_is_rbv) + via_write(rbv_regp, rIFR, 0x02); + else + via_write(via2_regp, vIFR, 0x02); break; } -#ifdef DEBUG_NUBUS_INT - printk("nubus_irq: map %x mask %x\n", map, nubus_active); + +#ifdef DEBUG_VIA_NUBUS + if (console_loglevel > 6) + printk("nubus_irq: map %x mask %x active %x\n", + allints, nubus_active, map); +#endif + +#ifdef CONFIG_BLK_DEV_MAC_IDE + if (mac_ide_intr_hook && ide_pending) { + mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs); + mac_ide_irqs++; + } #endif if(ct++>2) { -#ifdef DEBUG_NUBUS_INT - printk("nubus stuck events - %d/%d\n", map, nubus_active); -#endif + if (console_loglevel > 5) + printk("nubus stuck events - %x/%x/%x ide %x\n", + allints, nubus_active, map, ide_pending); + nubus_stuck_events++; + return; } @@ -1579,12 +1672,14 @@ static void oss_do_nubus(int slot, void *via, struct pt_regs *regs) printk("nubus_irq: map %x mask %x\n", map, nubus_active); #endif if( (map = (map&nubus_active)) ==0 ) { + if (ct == 0) { #ifdef CONFIG_BLK_DEV_MAC_IDE - if (!mac_ide_intr_hook) - printk("nubus_irq: nothing pending, map %x mask %x\n", - map, nubus_active); + if (!mac_ide_intr_hook) + printk("nubus_irq: nothing pending, map %x mask %x\n", + map, nubus_active); #endif - nubus_irqs[7]++; + nubus_irqs[7]++; + } break; } diff --git a/arch/m68k/mac/mackeyb.c b/arch/m68k/mac/mackeyb.c index 64cd5e1f8..5a6ae7c75 100644 --- a/arch/m68k/mac/mackeyb.c +++ b/arch/m68k/mac/mackeyb.c @@ -1,5 +1,12 @@ /* - * linux/arch/m68k/mac/mackeyb.c + * linux/arch/m68k/mac/mackeyb.c + * + * Keyboard driver for Macintosh computers. + * + * Adapted from drivers/macintosh/key_mac.c and arch/m68k/atari/akakeyb.c + * (see that file for its authors and contributors). + * + * Copyright (C) 1997 Michael Schmitz. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive @@ -10,6 +17,7 @@ * misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c) */ +#include <linux/config.h> #include <linux/types.h> #include <linux/mm.h> #include <linux/kd.h> @@ -59,8 +67,15 @@ extern void put_queue(int); static void mac_leds_done(struct adb_request *); static void keyboard_input(unsigned char *, int, struct pt_regs *); static void mouse_input(unsigned char *, int, struct pt_regs *); -/* Hook for mouse driver */ -void (*adb_mouse_interrupt_hook) (char *, int); + +#ifdef CONFIG_ADBMOUSE +/* XXX: Hook for mouse driver */ +void (*adb_mouse_interrupt_hook)(unsigned char *, int); +int adb_emulate_buttons = 0; +int adb_button2_keycode = 0x7d; /* right control key */ +int adb_button3_keycode = 0x7c; /* right option key */ +#endif + /* The mouse driver - for debugging */ extern void adb_mouse_interrupt(char *, int); /* end keyb */ @@ -275,9 +290,11 @@ input_keycode(int keycode, int repeat) kbd = kbd_table + fg_console; up_flag = (keycode & 0x80); keycode &= 0x7f; + if (!repeat) del_timer(&repeat_timer); +#ifdef CONFIG_ADBMOUSE /* * XXX: Add mouse button 2+3 fake codes here if mouse open. * As we only report up/down events, keep track of faked buttons. @@ -289,7 +306,8 @@ input_keycode(int keycode, int repeat) * (wanted: command and alt/option, or KP= and KP( ...) * Debug version; might be rewritten to be faster on normal keys. */ - if (adb_mouse_interrupt_hook || console_loglevel >= 8) { + if (adb_emulate_buttons + && (adb_mouse_interrupt_hook || console_loglevel >= 8)) { unsigned char button, button2, button3, fake_event; static unsigned char button2state=0, button3state=0; /* up */ /* faked ADB packet */ @@ -297,21 +315,20 @@ input_keycode(int keycode, int repeat) button = 0; fake_event = 0; - switch (keycode) { /* which 'button' ? */ - case 0x7c: /* R-option */ - button2 = (!up_flag); /* new state */ - if (button2 != button2state) /* change ? */ - button = 2; - button2state = button2; /* save state */ - fake_event = 2; - break; - case 0x7d: /* R-control */ - button3 = (!up_flag); /* new state */ - if (button3 != button3state) /* change ? */ - button = 3; - button3state = button3; /* save state */ - fake_event = 3; - break; + if (keycode == adb_button2_keycode) { /* which 'button' ? */ + /* R-option */ + button2 = (!up_flag); /* new state */ + if (button2 != button2state) /* change ? */ + button = 2; + button2state = button2; /* save state */ + fake_event = 2; + } else if (keycode == adb_button3_keycode) { + /* R-control */ + button3 = (!up_flag); /* new state */ + if (button3 != button3state) /* change ? */ + button = 3; + button3state = button3; /* save state */ + fake_event = 3; } #ifdef DEBUG_ADBMOUSE if (fake_event && console_loglevel >= 8) @@ -340,6 +357,7 @@ input_keycode(int keycode, int repeat) if (fake_event) return; } +#endif /* CONFIG_ADBMOUSE */ /* * Convert R-shift/control/option to L version. @@ -365,16 +383,18 @@ input_keycode(int keycode, int repeat) * transition into a key-down transition. * MSch: need to turn each caps-lock event into a down-up * double event (keyboard code assumes caps-lock is a toggle) + * 981127: fix LED behavior (kudos atong!) */ -#if 0 - if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK)) - up_flag = 0; -#else - if (keycode == 0x39) { + switch (keycode) { + case 0x39: handle_scancode(keycode); /* down */ up_flag = 0x80; /* see below ... */ + mark_bh(KEYBOARD_BH); + break; + case 0x47: + mark_bh(KEYBOARD_BH); + break; } -#endif } handle_scancode(keycode + up_flag); @@ -740,8 +760,3 @@ __initfunc(int mac_keyb_init(void)) return 0; } - -/* for "kbd-reset" cmdline param */ -__initfunc(void mac_kbd_reset_setup(char *str, int *ints)) -{ -} diff --git a/arch/m68k/mac/via6522.c b/arch/m68k/mac/via6522.c index 08ca49071..05e6f44e4 100644 --- a/arch/m68k/mac/via6522.c +++ b/arch/m68k/mac/via6522.c @@ -304,10 +304,11 @@ void mac_reset(void) unsigned long flags; unsigned long *reset_hook; - save_flags(flags); - cli(); - /* need ROMBASE in booter */ + /* indeed, plus need to MAP THE ROM !! */ + + if (mac_bi_data.rombase == 0) + mac_bi_data.rombase = 0x40800000; /* works on some */ rom_reset = (void *) (mac_bi_data.rombase + 0xa); @@ -318,12 +319,22 @@ void mac_reset(void) printk("ROM reset hook: %p\n", *reset_hook); rom_reset = *reset_hook; #endif + if (macintosh_config->ident == MAC_MODEL_SE30) { + /* + * MSch: Machines known to crash on ROM reset ... + */ + printk("System halted.\n"); + while(1); + } else { + save_flags(flags); + cli(); - rom_reset(); + rom_reset(); - restore_flags(flags); + restore_flags(flags); + } - /* We never make it this far... */ + /* We never make it this far... it usually panics above. */ printk ("Restart failed. Please restart manually.\n"); /* XXX - delay do we need to spin here ? */ diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 62129782b..ef1b855bd 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -8,6 +8,7 @@ #include <linux/mm.h> #include <linux/kernel.h> #include <linux/ptrace.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/traps.h> @@ -32,8 +33,7 @@ extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code) { - struct task_struct *tsk = current; - struct mm_struct *mm = tsk->mm; + struct mm_struct *mm = current->mm; struct vm_area_struct * vma; unsigned long fixup; int write; @@ -41,9 +41,17 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, #ifdef DEBUG printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n", regs->sr, regs->pc, address, error_code, - tsk->mm->pgd); + current->mm->pgd); #endif + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || mm == &init_mm) + goto no_context; + down(&mm->mmap_sem); vma = find_vma(mm, address); @@ -86,7 +94,14 @@ good_area: if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(current, vma, address, write); + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + if (!handle_mm_fault(current, vma, address, write)) + goto do_sigbus; /* There seems to be a missing invalidate somewhere in do_no_page. * Until I found it, this one cures the problem and makes @@ -106,10 +121,15 @@ bad_area: /* User mode accesses just cause a SIGSEGV */ if (user_mode(regs)) { - force_sig (SIGSEGV, tsk); + siginfo_t info; + info.si_signo = SIGSEGV; + info.si_code = SEGV_MAPERR; + info.si_addr = (void *)address; + force_sig_info(SIGSEGV, &info, current); return 1; } +no_context: /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->pc)) != 0) { struct pt_regs *tregs; @@ -136,5 +156,22 @@ bad_area: die_if_kernel("Oops", regs, error_code); do_exit(SIGKILL); +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +do_sigbus: + up(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + force_sig(SIGBUS, current); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + goto no_context; + return 1; } diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index 395fb41b6..8e520702f 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -28,8 +28,9 @@ #include <asm/atari_stram.h> #endif +#undef DEBUG + extern void die_if_kernel(char *,struct pt_regs *,long); -extern void init_kpointer_table(void); extern void show_net_buffers(void); int do_check_pgt_cache(int low, int high) @@ -122,17 +123,14 @@ void show_mem(void) unsigned long mm_cachebits = 0; #endif -pte_t *kernel_page_table (unsigned long *memavailp) +static pte_t *__init kernel_page_table(unsigned long *memavailp) { pte_t *ptablep; - if (memavailp) { - ptablep = (pte_t *)*memavailp; - *memavailp += PAGE_SIZE; - } - else - ptablep = (pte_t *)__get_free_page(GFP_KERNEL); + ptablep = (pte_t *)*memavailp; + *memavailp += PAGE_SIZE; + clear_page((unsigned long)ptablep); flush_page_to_ram((unsigned long) ptablep); flush_tlb_kernel_page((unsigned long) ptablep); nocache_page ((unsigned long)ptablep); @@ -140,199 +138,164 @@ pte_t *kernel_page_table (unsigned long *memavailp) return ptablep; } -__initfunc(static unsigned long -map_chunk (unsigned long addr, unsigned long size, unsigned long *memavailp)) -{ -#define ONEMEG (1024*1024) -#define L3TREESIZE (256*1024) +static pmd_t *last_pgtable __initdata = NULL; - static unsigned long mem_mapped = 0; - static unsigned long virtaddr = 0; - static pte_t *ktablep = NULL; - unsigned long *kpointerp; - unsigned long physaddr; - extern pte_t *kpt; - int pindex; /* index into pointer table */ - pgd_t *page_dir = pgd_offset_k (virtaddr); - - if (!pgd_present (*page_dir)) { - /* we need a new pointer table */ - kpointerp = (unsigned long *) get_kpointer_table (); - pgd_set (page_dir, (pmd_t *) kpointerp); - memset (kpointerp, 0, PTRS_PER_PMD * sizeof (pmd_t)); - } - else - kpointerp = (unsigned long *) pgd_page (*page_dir); +static pmd_t *__init kernel_ptr_table(unsigned long *memavailp) +{ + if (!last_pgtable) { + unsigned long pmd, last; + int i; - /* - * pindex is the offset into the pointer table for the - * descriptors for the current virtual address being mapped. - */ - pindex = (virtaddr >> 18) & 0x7f; + last = (unsigned long)kernel_pg_dir; + for (i = 0; i < PTRS_PER_PGD; i++) { + if (!pgd_val(kernel_pg_dir[i])) + continue; + pmd = pgd_page(kernel_pg_dir[i]); + if (pmd > last) + last = pmd; + } + last_pgtable = (pmd_t *)last; #ifdef DEBUG - printk ("mm=%ld, kernel_pg_dir=%p, kpointerp=%p, pindex=%d\n", - mem_mapped, kernel_pg_dir, kpointerp, pindex); + printk("kernel_ptr_init: %p\n", last_pgtable); #endif + } - /* - * if this is running on an '040, we already allocated a page - * table for the first 4M. The address is stored in kpt by - * arch/head.S - * - */ - if (CPU_IS_040_OR_060 && mem_mapped == 0) - ktablep = kpt; - - for (physaddr = addr; - physaddr < addr + size; - mem_mapped += L3TREESIZE, virtaddr += L3TREESIZE) { - -#ifdef DEBUG - printk ("pa=%#lx va=%#lx ", physaddr, virtaddr); -#endif + if (((unsigned long)(last_pgtable + PTRS_PER_PMD) & ~PAGE_MASK) == 0) { + last_pgtable = (pmd_t *)*memavailp; + *memavailp += PAGE_SIZE; - if (pindex > 127 && mem_mapped >= 32*ONEMEG) { - /* we need a new pointer table every 32M */ -#ifdef DEBUG - printk ("[new pointer]"); -#endif + clear_page((unsigned long)last_pgtable); + flush_page_to_ram((unsigned long)last_pgtable); + flush_tlb_kernel_page((unsigned long)last_pgtable); + nocache_page((unsigned long)last_pgtable); + } else + last_pgtable += PTRS_PER_PMD; - kpointerp = (unsigned long *)get_kpointer_table (); - pgd_set(pgd_offset_k(virtaddr), (pmd_t *)kpointerp); - pindex = 0; - } + return last_pgtable; +} - if (CPU_IS_040_OR_060) { - int i; - unsigned long ktable; +static unsigned long __init +map_chunk (unsigned long addr, long size, unsigned long *memavailp) +{ +#define PTRTREESIZE (256*1024) +#define ROOTTREESIZE (32*1024*1024) + static unsigned long virtaddr = 0; + unsigned long physaddr; + pgd_t *pgd_dir; + pmd_t *pmd_dir; + pte_t *pte_dir; - /* Don't map the first 4 MB again. The pagetables - * for this range have already been initialized - * in boot/head.S. Otherwise the pages used for - * tables would be reinitialized to copyback mode. - */ + physaddr = (addr | m68k_supervisor_cachemode | + _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); + if (CPU_IS_040_OR_060) + physaddr |= _PAGE_GLOBAL040; - if (mem_mapped < 4 * ONEMEG) - { + while (size > 0) { +#ifdef DEBUG + if (!(virtaddr & (PTRTREESIZE-1))) + printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK, + virtaddr); +#endif + pgd_dir = pgd_offset_k(virtaddr); + if (virtaddr && CPU_IS_020_OR_030) { + if (!(virtaddr & (ROOTTREESIZE-1)) && + size >= ROOTTREESIZE) { #ifdef DEBUG - printk ("Already initialized\n"); + printk ("[very early term]"); #endif - physaddr += L3TREESIZE; - pindex++; + pgd_val(*pgd_dir) = physaddr; + size -= ROOTTREESIZE; + virtaddr += ROOTTREESIZE; + physaddr += ROOTTREESIZE; continue; } + } + if (!pgd_present(*pgd_dir)) { + pmd_dir = kernel_ptr_table(memavailp); #ifdef DEBUG - printk ("[setup table]"); + printk ("[new pointer %p]", pmd_dir); #endif + pgd_set(pgd_dir, pmd_dir); + } else + pmd_dir = pmd_offset(pgd_dir, virtaddr); - /* - * 68040, use page tables pointed to by the - * kernel pointer table. - */ - - if ((pindex & 15) == 0) { - /* Need new page table every 4M on the '040 */ + if (CPU_IS_020_OR_030) { + if (virtaddr) { #ifdef DEBUG - printk ("[new table]"); + printk ("[early term]"); #endif - ktablep = kernel_page_table (memavailp); - } - - ktable = virt_to_phys(ktablep); - - /* - * initialize section of the page table mapping - * this 256K portion. - */ - for (i = 0; i < 64; i++) { - pte_val(ktablep[i]) = physaddr | _PAGE_PRESENT - | m68k_supervisor_cachemode | _PAGE_GLOBAL040 - | _PAGE_ACCESSED; + pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr; + physaddr += PTRTREESIZE; + } else { + int i; +#ifdef DEBUG + printk ("[zero map]"); +#endif + pte_dir = (pte_t *)kernel_ptr_table(memavailp); + pmd_dir->pmd[0] = virt_to_phys(pte_dir) | + _PAGE_TABLE | _PAGE_ACCESSED; + pte_val(*pte_dir++) = 0; physaddr += PAGE_SIZE; + for (i = 1; i < 64; physaddr += PAGE_SIZE, i++) + pte_val(*pte_dir++) = physaddr; } - ktablep += 64; - - /* - * make the kernel pointer table point to the - * kernel page table. Each entries point to a - * 64 entry section of the page table. - */ - - kpointerp[pindex++] = ktable | _PAGE_TABLE | _PAGE_ACCESSED; + size -= PTRTREESIZE; + virtaddr += PTRTREESIZE; } else { - /* - * 68030, use early termination page descriptors. - * Each one points to 64 pages (256K). - */ -#ifdef DEBUG - printk ("[early term] "); -#endif - if (virtaddr == 0UL) { - /* map the first 256K using a 64 entry - * 3rd level page table. - * UNMAP the first entry to trap - * zero page (NULL pointer) references - */ - int i; - unsigned long *tbl; - - tbl = (unsigned long *)get_kpointer_table(); - - kpointerp[pindex++] = virt_to_phys(tbl) | _PAGE_TABLE |_PAGE_ACCESSED; - - for (i = 0; i < 64; i++, physaddr += PAGE_SIZE) - tbl[i] = physaddr | _PAGE_PRESENT | _PAGE_ACCESSED; - - /* unmap the zero page */ - tbl[0] = 0; - } else { - /* not the first 256K */ - kpointerp[pindex++] = physaddr | _PAGE_PRESENT | _PAGE_ACCESSED; + if (!pmd_present(*pmd_dir)) { #ifdef DEBUG - printk ("%lx=%lx ", virt_to_phys(&kpointerp[pindex-1]), - kpointerp[pindex-1]); + printk ("[new table]"); #endif - physaddr += 64 * PAGE_SIZE; + pte_dir = kernel_page_table(memavailp); + pmd_set(pmd_dir, pte_dir); } + pte_dir = pte_offset(pmd_dir, virtaddr); + + if (virtaddr) { + if (!pte_present(*pte_dir)) + pte_val(*pte_dir) = physaddr; + } else + pte_val(*pte_dir) = 0; + size -= PAGE_SIZE; + virtaddr += PAGE_SIZE; + physaddr += PAGE_SIZE; } + + } #ifdef DEBUG - printk ("\n"); + printk("\n"); #endif - } - return mem_mapped; + return virtaddr; } extern unsigned long free_area_init(unsigned long, unsigned long); +extern void init_pointer_table(unsigned long ptable); /* References to section boundaries */ extern char _text, _etext, _edata, __bss_start, _end; extern char __init_begin, __init_end; -extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; - /* * paging_init() continues the virtual memory environment setup which * was begun by the code in arch/head.S. */ -__initfunc(unsigned long paging_init(unsigned long start_mem, - unsigned long end_mem)) +unsigned long __init paging_init(unsigned long start_mem, + unsigned long end_mem) { int chunk; unsigned long mem_avail = 0; #ifdef DEBUG { - extern pte_t *kpt; - printk ("start of paging_init (%p, %p, %lx, %lx, %lx)\n", - kernel_pg_dir, kpt, availmem, start_mem, end_mem); + extern unsigned long availmem; + printk ("start of paging_init (%p, %lx, %lx, %lx)\n", + kernel_pg_dir, availmem, start_mem, end_mem); } #endif - init_kpointer_table(); - /* Fix the cache mode in the page descriptors for the 680[46]0. */ if (CPU_IS_040_OR_060) { int i; @@ -366,6 +329,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, m68k_memory[chunk].size, &start_mem); } + flush_tlb_all(); #ifdef DEBUG printk ("memory available is %ldKB\n", mem_avail >> 10); @@ -385,21 +349,16 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, start_mem += PAGE_SIZE; memset((void *)empty_zero_page, 0, PAGE_SIZE); -#if 0 /* * allocate the "swapper" page directory and * record in task 0 (swapper) tss */ - swapper_pg_dir = (pgd_t *)get_kpointer_table(); - - init_mm.pgd = swapper_pg_dir; -#endif - - memset (swapper_pg_dir, 0, sizeof(pgd_t)*PTRS_PER_PGD); + init_mm.pgd = (pgd_t *)kernel_ptr_table(&start_mem); + memset (init_mm.pgd, 0, sizeof(pgd_t)*PTRS_PER_PGD); /* setup CPU root pointer for swapper task */ task[0]->tss.crp[0] = 0x80000000 | _PAGE_TABLE; - task[0]->tss.crp[1] = virt_to_phys (swapper_pg_dir); + task[0]->tss.crp[1] = virt_to_phys(init_mm.pgd); #ifdef DEBUG printk ("task 0 pagedir at %p virt, %#lx phys\n", @@ -430,16 +389,16 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, #ifdef DEBUG printk ("before free_area_init\n"); #endif - - return PAGE_ALIGN(free_area_init (start_mem, end_mem)); + return PAGE_ALIGN(free_area_init(start_mem, end_mem)); } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { int codepages = 0; int datapages = 0; int initpages = 0; unsigned long tmp; + int i; end_mem &= PAGE_MASK; high_memory = (void *) end_mem; @@ -480,6 +439,14 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) #endif free_page(tmp); } + + /* insert pointer tables allocated so far into the tablelist */ + init_pointer_table((unsigned long)kernel_pg_dir); + for (i = 0; i < PTRS_PER_PGD; i++) { + if (pgd_val(kernel_pg_dir[i])) + init_pointer_table(pgd_page(kernel_pg_dir[i])); + } + printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c index 802771ab4..d2cd29011 100644 --- a/arch/m68k/mm/kmap.c +++ b/arch/m68k/mm/kmap.c @@ -2,6 +2,9 @@ * linux/arch/m68k/mm/kmap.c * * Copyright (C) 1997 Roman Hodek + * + * 10/01/99 cleaned up the code and changing to the same interface + * used by other architectures /Roman Zippel */ #include <linux/mm.h> @@ -9,250 +12,88 @@ #include <linux/string.h> #include <linux/types.h> #include <linux/malloc.h> +#include <linux/vmalloc.h> #include <asm/setup.h> #include <asm/segment.h> #include <asm/page.h> #include <asm/pgtable.h> +#include <asm/io.h> #include <asm/system.h> +#undef DEBUG -extern pte_t *kernel_page_table (unsigned long *memavailp); - -/* Granularity of kernel_map() allocations */ -#define KMAP_STEP (256*1024) - -/* Size of pool of KMAP structures; that is needed, because kernel_map() can - * be called at times where kmalloc() isn't initialized yet. */ -#define KMAP_POOL_SIZE 16 - -/* structure for maintainance of kmap regions */ -typedef struct kmap { - struct kmap *next, *prev; /* linking of list */ - unsigned long addr; /* start address of region */ - unsigned long mapaddr; /* address returned to user */ - unsigned long size; /* size of region */ - unsigned free : 1; /* flag whether free or allocated */ - unsigned kmalloced : 1; /* flag whether got this from kmalloc() */ - unsigned pool_alloc : 1; /* flag whether got this is alloced in pool */ -} KMAP; - -KMAP kmap_pool[KMAP_POOL_SIZE] = { - { NULL, NULL, KMAP_START, KMAP_START, KMAP_END-KMAP_START, 1, 0, 1 }, - { NULL, NULL, 0, 0, 0, 0, 0, 0 }, -}; +#define PTRTREESIZE (256*1024) /* - * anchor of kmap region list - * - * The list is always ordered by addresses, and regions are always adjacent, - * i.e. there must be no holes between them! + * For 040/060 we can use the virtual memory area like other architectures, + * but for 020/030 we want to use early termination page descriptor and we + * can't mix this with normal page descriptors, so we have to copy that code + * (mm/vmalloc.c) and return appriorate aligned addresses. */ -KMAP *kmap_regions = &kmap_pool[0]; - -/* for protecting the kmap_regions list against races */ -static struct semaphore kmap_sem = MUTEX; +#ifdef CPU_M68040_OR_M68060_ONLY +#define IO_SIZE PAGE_SIZE -/* - * Low-level allocation and freeing of KMAP structures - */ -static KMAP *alloc_kmap( int use_kmalloc ) +static inline struct vm_struct *get_io_area(unsigned long size) { - KMAP *p; - int i; - - /* first try to get from the pool if possible */ - for( i = 0; i < KMAP_POOL_SIZE; ++i ) { - if (!kmap_pool[i].pool_alloc) { - kmap_pool[i].kmalloced = 0; - kmap_pool[i].pool_alloc = 1; - return( &kmap_pool[i] ); - } - } - - if (use_kmalloc && (p = (KMAP *)kmalloc( sizeof(KMAP), GFP_KERNEL ))) { - p->kmalloced = 1; - return( p ); - } - - return( NULL ); -} - -static void free_kmap( KMAP *p ) -{ - if (p->kmalloced) - kfree( p ); - else - p->pool_alloc = 0; + return get_vm_area(size); } -/* - * Get a free region from the kmap address range - */ -static KMAP *kmap_get_region( unsigned long size, int use_kmalloc ) +static inline void free_io_area(void *addr) { - KMAP *p, *q; - - /* look for a suitable free region */ - for( p = kmap_regions; p; p = p->next ) - if (p->free && p->size >= size) - break; - if (!p) { - printk( KERN_ERR "kernel_map: address space for " - "allocations exhausted\n" ); - return( NULL ); - } - - if (p->size > size) { - /* if free region is bigger than we need, split off the rear free part - * into a new region */ - if (!(q = alloc_kmap( use_kmalloc ))) { - printk( KERN_ERR "kernel_map: out of memory\n" ); - return( NULL ); - } - q->addr = p->addr + size; - q->size = p->size - size; - p->size = size; - q->free = 1; - - q->prev = p; - q->next = p->next; - p->next = q; - if (q->next) q->next->prev = q; - } - - p->free = 0; - return( p ); + return vfree((void *)(PAGE_MASK & (unsigned long)addr)); } +#else -/* - * Free a kernel_map region again - */ -static void kmap_put_region( KMAP *p ) -{ - KMAP *q; - - p->free = 1; +#define IO_SIZE (256*1024) - /* merge with previous region if possible */ - q = p->prev; - if (q && q->free) { - if (q->addr + q->size != p->addr) { - printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" ); - return; - } - q->size += p->size; - q->next = p->next; - if (p->next) p->next->prev = q; - free_kmap( p ); - p = q; - } - - /* merge with following region if possible */ - q = p->next; - if (q && q->free) { - if (p->addr + p->size != q->addr) { - printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" ); - return; - } - p->size += q->size; - p->next = q->next; - if (q->next) q->next->prev = p; - free_kmap( q ); - } -} +static struct vm_struct *iolist = NULL; - -/* - * kernel_map() helpers - */ -static inline pte_t * -pte_alloc_kernel_map(pmd_t *pmd, unsigned long address, - unsigned long *memavailp) +static struct vm_struct *get_io_area(unsigned long size) { - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *page = kernel_page_table(memavailp); - if (pmd_none(*pmd)) { - if (page) { - pmd_set(pmd, page); - memset( page, 0, PAGE_SIZE ); - return page + address; - } - pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - if (memavailp) - panic("kernel_map: slept during init?!?"); - cache_page((unsigned long) page); - free_page((unsigned long) page); - } - if (pmd_bad(*pmd)) { - printk( KERN_ERR "Bad pmd in pte_alloc_kernel_map: %08lx\n", - pmd_val(*pmd)); - pmd_set(pmd, BAD_PAGETABLE); + unsigned long addr; + struct vm_struct **p, *tmp, *area; + + area = (struct vm_struct *)kmalloc(sizeof(*area), GFP_KERNEL); + if (!area) return NULL; + addr = KMAP_START; + for (p = &iolist; (tmp = *p) ; p = &tmp->next) { + if (size + addr < (unsigned long)tmp->addr) + break; + if (addr > KMAP_END-size) + return NULL; + addr = tmp->size + (unsigned long)tmp->addr; } - return (pte_t *) pmd_page(*pmd) + address; -} - -static inline void -kernel_map_pte(pte_t *pte, unsigned long address, unsigned long size, - unsigned long phys_addr, pgprot_t prot) -{ - unsigned long end; - - address &= ~PMD_MASK; - end = address + size; - if (end > PMD_SIZE) - end = PMD_SIZE; - do { - pte_val(*pte) = phys_addr + pgprot_val(prot); - address += PAGE_SIZE; - phys_addr += PAGE_SIZE; - pte++; - } while (address < end); + area->addr = (void *)addr; + area->size = size + IO_SIZE; + area->next = *p; + *p = area; + return area; } -static inline int -kernel_map_pmd (pmd_t *pmd, unsigned long address, unsigned long size, - unsigned long phys_addr, pgprot_t prot, - unsigned long *memavailp) +static inline void free_io_area(void *addr) { - unsigned long end; + struct vm_struct **p, *tmp; - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - phys_addr -= address; - - if (CPU_IS_040_OR_060) { - do { - pte_t *pte = pte_alloc_kernel_map(pmd, address, memavailp); - if (!pte) - return -ENOMEM; - kernel_map_pte(pte, address, end - address, - address + phys_addr, prot); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address < end); - } else { - /* On the 68030 we use early termination page descriptors. - Each one points to 64 pages (256K). */ - int i = (address >> (PMD_SHIFT-4)) & 15; - do { - (&pmd_val(*pmd))[i++] = (address + phys_addr) | pgprot_val(prot); - address += PMD_SIZE / 16; - } while (address < end); + if (!addr) + return; + addr = (void *)((unsigned long)addr & -IO_SIZE); + for (p = &iolist ; (tmp = *p) ; p = &tmp->next) { + if (tmp->addr == addr) { + *p = tmp->next; + __iounmap(tmp->addr, tmp->size); + kfree(tmp); + return; + } } - return 0; } +#endif /* * Map some physical address range into the kernel address space. The @@ -260,304 +101,245 @@ kernel_map_pmd (pmd_t *pmd, unsigned long address, unsigned long size, */ /* Rewritten by Andreas Schwab to remove all races. */ -unsigned long kernel_map(unsigned long phys_addr, unsigned long size, - int cacheflag, unsigned long *memavailp) +void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) { - unsigned long retaddr, from, end; - pgd_t *dir; - pgprot_t prot; - KMAP *kmap; - - /* Round down 'phys_addr' to 256 KB and adjust size */ - retaddr = phys_addr & (KMAP_STEP-1); - size += retaddr; - phys_addr &= ~(KMAP_STEP-1); - /* Round up the size to 256 KB. It doesn't hurt if too much is - mapped... */ - size = (size + KMAP_STEP - 1) & ~(KMAP_STEP-1); - - down( &kmap_sem ); - kmap = kmap_get_region(size, memavailp == NULL); - if (!kmap) { - up(&kmap_sem); - return 0; - } - from = kmap->addr; - retaddr += from; - kmap->mapaddr = retaddr; - end = from + size; - up( &kmap_sem ); + struct vm_struct *area; + unsigned long virtaddr, retaddr; + long offset; + pgd_t *pgd_dir; + pmd_t *pmd_dir; + pte_t *pte_dir; + + /* + * Don't allow mappings that wrap.. + */ + if (!size || size > physaddr + size) + return NULL; +#ifdef DEBUG + printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag); +#endif + /* + * Mappings have to be aligned + */ + offset = physaddr & (IO_SIZE - 1); + physaddr &= -IO_SIZE; + size = (size + offset + IO_SIZE - 1) & -IO_SIZE; + + /* + * Ok, go for it.. + */ + area = get_io_area(size); + if (!area) + return NULL; + + virtaddr = (unsigned long)area->addr; + retaddr = virtaddr + offset; +#ifdef DEBUG + printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr); +#endif + + /* + * add cache and table flags to physical address + */ if (CPU_IS_040_OR_060) { - pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_GLOBAL040 | - _PAGE_ACCESSED | _PAGE_DIRTY); + physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 | + _PAGE_ACCESSED | _PAGE_DIRTY); switch (cacheflag) { - case KERNELMAP_FULL_CACHING: - pgprot_val(prot) |= _PAGE_CACHE040; + case IOMAP_FULL_CACHING: + physaddr |= _PAGE_CACHE040; break; - case KERNELMAP_NOCACHE_SER: + case IOMAP_NOCACHE_SER: default: - pgprot_val(prot) |= _PAGE_NOCACHE_S; + physaddr |= _PAGE_NOCACHE_S; break; - case KERNELMAP_NOCACHE_NONSER: - pgprot_val(prot) |= _PAGE_NOCACHE; + case IOMAP_NOCACHE_NONSER: + physaddr |= _PAGE_NOCACHE; break; - case KERNELMAP_NO_COPYBACK: - pgprot_val(prot) |= _PAGE_CACHE040W; + case IOMAP_WRITETHROUGH: + physaddr |= _PAGE_CACHE040W; break; } - } else - pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_ACCESSED | - _PAGE_DIRTY | - ((cacheflag == KERNELMAP_FULL_CACHING || - cacheflag == KERNELMAP_NO_COPYBACK) - ? 0 : _PAGE_NOCACHE030)); - - phys_addr -= from; - dir = pgd_offset_k(from); - while (from < end) { - pmd_t *pmd = pmd_alloc_kernel(dir, from); - - if (kernel_map_pmd(pmd, from, end - from, phys_addr + from, - prot, memavailp)) { - printk( KERN_ERR "kernel_map: out of memory\n" ); - return 0UL; + } else { + physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); + switch (cacheflag) { + case IOMAP_NOCACHE_SER: + case IOMAP_NOCACHE_NONSER: + default: + physaddr |= _PAGE_NOCACHE030; + break; + case IOMAP_FULL_CACHING: + case IOMAP_WRITETHROUGH: + break; } - from = (from + PGDIR_SIZE) & PGDIR_MASK; - dir++; } - return retaddr; -} - + while (size > 0) { +#ifdef DEBUG + if (!(virtaddr & (PTRTREESIZE-1))) + printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr); +#endif + pgd_dir = pgd_offset_k(virtaddr); + pmd_dir = pmd_alloc_kernel(pgd_dir, virtaddr); + if (!pmd_dir) { + printk("ioremap: no mem for pmd_dir\n"); + return NULL; + } -/* - * kernel_unmap() helpers - */ -static inline void pte_free_kernel_unmap( pmd_t *pmd ) -{ - unsigned long page = pmd_page(*pmd); - mem_map_t *pagemap = &mem_map[MAP_NR(page)]; - - pmd_clear(pmd); - cache_page(page); - - if (PageReserved( pagemap )) { - /* need to unreserve pages that were allocated with memavailp != NULL; - * this works only if 'page' is page-aligned */ - if (page & ~PAGE_MASK) - return; - clear_bit( PG_reserved, &pagemap->flags ); - atomic_set( &pagemap->count, 1 ); - } - free_page( page ); -} + if (CPU_IS_020_OR_030) { + pmd_dir->pmd[(virtaddr/PTRTREESIZE)&-16] = physaddr; + physaddr += PTRTREESIZE; + virtaddr += PTRTREESIZE; + size -= PTRTREESIZE; + } else { + pte_dir = pte_alloc_kernel(pmd_dir, virtaddr); + if (!pte_dir) { + printk("ioremap: no mem for pte_dir\n"); + return NULL; + } -/* - * This not only unmaps the requested region, but also loops over the whole - * pmd to determine whether the other pte's are clear (so that the page can be - * freed.) If so, it returns 1, 0 otherwise. - */ -static inline int -kernel_unmap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size) -{ - pte_t *pte; - unsigned long addr2, end, end2; - int all_clear = 1; - - if (pmd_none(*pmd)) - return( 0 ); - if (pmd_bad(*pmd)) { - printk( KERN_ERR "kernel_unmap_pte_range: bad pmd (%08lx)\n", - pmd_val(*pmd) ); - pmd_clear(pmd); - return( 0 ); - } - address &= ~PMD_MASK; - addr2 = 0; - pte = pte_offset(pmd, addr2); - end = address + size; - if (end > PMD_SIZE) - end = PMD_SIZE; - end2 = addr2 + PMD_SIZE; - while( addr2 < end2 ) { - if (!pte_none(*pte)) { - if (address <= addr2 && addr2 < end) - pte_clear(pte); - else - all_clear = 0; + pte_val(*pte_dir) = physaddr; + virtaddr += PAGE_SIZE; + physaddr += PAGE_SIZE; + size -= PAGE_SIZE; } - ++pte; - addr2 += PAGE_SIZE; } - return( all_clear ); -} - -static inline void -kernel_unmap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size) -{ - pmd_t * pmd; - unsigned long end; +#ifdef DEBUG + printk("\n"); +#endif + flush_tlb_all(); - if (pgd_none(*dir)) - return; - if (pgd_bad(*dir)) { - printk( KERN_ERR "kernel_unmap_pmd_range: bad pgd (%08lx)\n", - pgd_val(*dir) ); - pgd_clear(dir); - return; - } - pmd = pmd_offset(dir, address); - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - - if (CPU_IS_040_OR_060) { - do { - if (kernel_unmap_pte_range(pmd, address, end - address)) - pte_free_kernel_unmap( pmd ); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address < end); - } else { - /* On the 68030 clear the early termination descriptors */ - int i = (address >> (PMD_SHIFT-4)) & 15; - do { - (&pmd_val(*pmd))[i++] = 0; - address += PMD_SIZE / 16; - } while (address < end); - } + return (void *)retaddr; } /* - * Unmap a kernel_map()ed region again + * Unmap a ioremap()ed region again */ -void kernel_unmap( unsigned long addr ) +void iounmap(void *addr) { - unsigned long end; - pgd_t *dir; - KMAP *p; - - down( &kmap_sem ); - - /* find region for 'addr' in list; must search for mapaddr! */ - for( p = kmap_regions; p; p = p->next ) - if (!p->free && p->mapaddr == addr) - break; - if (!p) { - printk( KERN_ERR "kernel_unmap: trying to free invalid region\n" ); - return; - } - addr = p->addr; - end = addr + p->size; - kmap_put_region( p ); - - dir = pgd_offset_k( addr ); - while( addr < end ) { - kernel_unmap_pmd_range( dir, addr, end - addr ); - addr = (addr + PGDIR_SIZE) & PGDIR_MASK; - dir++; - } - - up( &kmap_sem ); - /* flushing for a range would do, but there's no such function for kernel - * address space... */ - flush_tlb_all(); + free_io_area(addr); } - /* - * kernel_set_cachemode() helpers + * __iounmap unmaps nearly everything, so be careful + * it doesn't free currently pointer/page tables anymore but it + * wans't used anyway and might be added later. */ -static inline void set_cmode_pte( pmd_t *pmd, unsigned long address, - unsigned long size, unsigned cmode ) -{ pte_t *pte; - unsigned long end; - - if (pmd_none(*pmd)) - return; - - pte = pte_offset( pmd, address ); - address &= ~PMD_MASK; - end = address + size; - if (end >= PMD_SIZE) - end = PMD_SIZE; - - for( ; address < end; pte++ ) { - pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode; - address += PAGE_SIZE; - } -} - - -static inline void set_cmode_pmd( pgd_t *dir, unsigned long address, - unsigned long size, unsigned cmode ) +void __iounmap(void *addr, unsigned long size) { - pmd_t *pmd; - unsigned long end; + unsigned long virtaddr = (unsigned long)addr; + pgd_t *pgd_dir; + pmd_t *pmd_dir; + pte_t *pte_dir; + + while (size > 0) { + pgd_dir = pgd_offset_k(virtaddr); + if (pgd_bad(*pgd_dir)) { + printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir)); + pgd_clear(pgd_dir); + return; + } + pmd_dir = pmd_offset(pgd_dir, virtaddr); - if (pgd_none(*dir)) - return; + if (CPU_IS_020_OR_030) { + int pmd_off = (virtaddr/PTRTREESIZE) & -16; - pmd = pmd_offset( dir, address ); - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; + if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) { + pmd_dir->pmd[pmd_off] = 0; + virtaddr += PTRTREESIZE; + size -= PTRTREESIZE; + continue; + } + } - if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) { - /* 68030 early termination descriptor */ - pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode; - return; - } - else { - /* "normal" tables */ - for( ; address < end; pmd++ ) { - set_cmode_pte( pmd, address, end - address, cmode ); - address = (address + PMD_SIZE) & PMD_MASK; + if (pmd_bad(*pmd_dir)) { + printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir)); + pmd_clear(pmd_dir); + return; } + pte_dir = pte_offset(pmd_dir, virtaddr); + + pte_val(*pte_dir) = 0; + virtaddr += PAGE_SIZE; + size -= PAGE_SIZE; } -} + flush_tlb_all(); +} /* * Set new cache mode for some kernel address space. * The caller must push data for that range itself, if such data may already * be in the cache. */ -void kernel_set_cachemode( unsigned long address, unsigned long size, - unsigned cmode ) +void kernel_set_cachemode(void *addr, unsigned long size, int cmode) { - pgd_t *dir = pgd_offset_k( address ); - unsigned long end = address + size; - + unsigned long virtaddr = (unsigned long)addr; + pgd_t *pgd_dir; + pmd_t *pmd_dir; + pte_t *pte_dir; + if (CPU_IS_040_OR_060) { - switch( cmode ) { - case KERNELMAP_FULL_CACHING: + switch (cmode) { + case IOMAP_FULL_CACHING: cmode = _PAGE_CACHE040; break; - case KERNELMAP_NOCACHE_SER: - default: + case IOMAP_NOCACHE_SER: + default: cmode = _PAGE_NOCACHE_S; break; - case KERNELMAP_NOCACHE_NONSER: + case IOMAP_NOCACHE_NONSER: cmode = _PAGE_NOCACHE; break; - case KERNELMAP_NO_COPYBACK: + case IOMAP_WRITETHROUGH: cmode = _PAGE_CACHE040W; break; } - } else - cmode = ((cmode == KERNELMAP_FULL_CACHING || - cmode == KERNELMAP_NO_COPYBACK) ? - 0 : _PAGE_NOCACHE030); - - for( ; address < end; dir++ ) { - set_cmode_pmd( dir, address, end - address, cmode ); - address = (address + PGDIR_SIZE) & PGDIR_MASK; + } else { + switch (cmode) { + case IOMAP_NOCACHE_SER: + case IOMAP_NOCACHE_NONSER: + default: + cmode = _PAGE_NOCACHE030; + break; + case IOMAP_FULL_CACHING: + case IOMAP_WRITETHROUGH: + cmode = 0; + } + } + + while (size > 0) { + pgd_dir = pgd_offset_k(virtaddr); + if (pgd_bad(*pgd_dir)) { + printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir)); + pgd_clear(pgd_dir); + return; + } + pmd_dir = pmd_offset(pgd_dir, virtaddr); + + if (CPU_IS_020_OR_030) { + int pmd_off = (virtaddr/PTRTREESIZE) & -16; + + if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) { + pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] & + _CACHEMASK040) | cmode; + virtaddr += PTRTREESIZE; + size -= PTRTREESIZE; + continue; + } + } + + if (pmd_bad(*pmd_dir)) { + printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir)); + pmd_clear(pmd_dir); + return; + } + pte_dir = pte_offset(pmd_dir, virtaddr); + + pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode; + virtaddr += PAGE_SIZE; + size -= PAGE_SIZE; } - /* flushing for a range would do, but there's no such function for kernel - * address space... */ + flush_tlb_all(); } diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c index 39cc1d1a9..a97578ec2 100644 --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -10,6 +10,7 @@ #include <linux/string.h> #include <linux/types.h> #include <linux/malloc.h> +#include <linux/init.h> #include <asm/setup.h> #include <asm/segment.h> @@ -97,6 +98,31 @@ static ptable_desc ptable_list = { &ptable_list, &ptable_list }; #define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t)) +void __init init_pointer_table(unsigned long ptable) +{ + ptable_desc *dp; + unsigned long page = ptable & PAGE_MASK; + unsigned char mask = 1 << ((ptable - page)/PTABLE_SIZE); + + dp = PAGE_PD(page); + if (!(PD_MARKBITS(dp) & mask)) { + PD_MARKBITS(dp) = 0xff; + (dp->prev = ptable_list.prev)->next = dp; + (dp->next = &ptable_list)->prev = dp; + } + + PD_MARKBITS(dp) &= ~mask; +#ifdef DEBUG + printk("init_pointer_table: %lx, %x\n", ptable, PD_MARKBITS(dp)); +#endif + + /* unreserve the page so it's possible to free that page */ + dp->flags &= ~(1 << PG_reserved); + atomic_set(&dp->count, 1); + + return; +} + pmd_t *get_pointer_table (void) { ptable_desc *dp = ptable_list.next; @@ -176,103 +202,6 @@ int free_pointer_table (pmd_t *ptable) return 0; } -/* maximum pages used for kpointer tables */ -#define KPTR_PAGES 4 -/* # of reserved slots */ -#define RESERVED_KPTR 4 -extern pmd_tablepage kernel_pmd_table; /* reserved in head.S */ - -static struct kpointer_pages { - pmd_tablepage *page[KPTR_PAGES]; - u_char alloced[KPTR_PAGES]; -} kptr_pages; - -void init_kpointer_table(void) { - short i = KPTR_PAGES-1; - - /* first page is reserved in head.S */ - kptr_pages.page[i] = &kernel_pmd_table; - kptr_pages.alloced[i] = ~(0xff>>RESERVED_KPTR); - for (i--; i>=0; i--) { - kptr_pages.page[i] = NULL; - kptr_pages.alloced[i] = 0; - } -} - -pmd_t *get_kpointer_table (void) -{ - /* For pointer tables for the kernel virtual address space, - * use the page that is reserved in head.S that can hold up to - * 8 pointer tables. 3 of these tables are always reserved - * (kernel_pg_dir, swapper_pg_dir and kernel pointer table for - * the first 16 MB of RAM). In addition, the 4th pointer table - * in this page is reserved. On Amiga and Atari, it is used to - * map in the hardware registers. It may be used for other - * purposes on other 68k machines. This leaves 4 pointer tables - * available for use by the kernel. 1 of them are usually used - * for the vmalloc tables. This allows mapping of 3 * 32 = 96 MB - * of physical memory. But these pointer tables are also used - * for other purposes, like kernel_map(), so further pages can - * now be allocated. - */ - pmd_tablepage *page; - pmd_table *table; - long nr, offset = -8; - short i; - - for (i=KPTR_PAGES-1; i>=0; i--) { - asm volatile("bfffo %1{%2,#8},%0" - : "=d" (nr) - : "d" ((u_char)~kptr_pages.alloced[i]), "d" (offset)); - if (nr) - break; - } - if (i < 0) { - printk("No space for kernel pointer table!\n"); - return NULL; - } - if (!(page = kptr_pages.page[i])) { - if (!(page = (pmd_tablepage *)get_free_page(GFP_KERNEL))) { - printk("No space for kernel pointer table!\n"); - return NULL; - } - flush_tlb_kernel_page((unsigned long) page); - nocache_page((u_long)(kptr_pages.page[i] = page)); - } - asm volatile("bfset %0@{%1,#1}" - : /* no output */ - : "a" (&kptr_pages.alloced[i]), "d" (nr-offset)); - table = &(*page)[nr-offset]; - memset(table, 0, sizeof(pmd_table)); - return ((pmd_t *)table); -} - -void free_kpointer_table (pmd_t *pmdp) -{ - pmd_table *table = (pmd_table *)pmdp; - pmd_tablepage *page = (pmd_tablepage *)((u_long)table & PAGE_MASK); - long nr; - short i; - - for (i=KPTR_PAGES-1; i>=0; i--) { - if (kptr_pages.page[i] == page) - break; - } - nr = ((u_long)table - (u_long)page) / sizeof(pmd_table); - if (!table || i < 0 || (i == KPTR_PAGES-1 && nr < RESERVED_KPTR)) { - printk("Attempt to free invalid kernel pointer table: %p\n", table); - return; - } - asm volatile("bfclr %0@{%1,#1}" - : /* no output */ - : "a" (&kptr_pages.alloced[i]), "d" (nr)); - if (!kptr_pages.alloced[i]) { - kptr_pages.page[i] = 0; - cache_page ((u_long)page); - free_page ((u_long)page); - } -} - static unsigned long transp_transl_matches( unsigned long regval, unsigned long vaddr ) { @@ -308,7 +237,6 @@ static unsigned long transp_transl_matches( unsigned long regval, */ unsigned long mm_vtop (unsigned long vaddr) { -#ifndef CONFIG_SINGLE_MEMORY_CHUNK int i=0; unsigned long voff = vaddr; unsigned long offset = 0; @@ -324,10 +252,6 @@ unsigned long mm_vtop (unsigned long vaddr) offset += m68k_memory[i].size; i++; }while (i < m68k_num_memory); -#else - if (vaddr < m68k_memory[0].size) - return m68k_memory[0].addr + vaddr; -#endif return mm_vtop_fallback(vaddr); } @@ -449,7 +373,6 @@ unsigned long mm_vtop_fallback (unsigned long vaddr) #ifndef CONFIG_SINGLE_MEMORY_CHUNK unsigned long mm_ptov (unsigned long paddr) { -#ifndef CONFIG_SINGLE_MEMORY_CHUNK int i = 0; unsigned long offset = 0; @@ -466,11 +389,6 @@ unsigned long mm_ptov (unsigned long paddr) offset += m68k_memory[i].size; i++; }while (i < m68k_num_memory); -#else - unsigned long base = m68k_memory[0].addr; - if (paddr >= base && paddr < (base + m68k_memory[0].size)) - return (paddr - base); -#endif /* * assume that the kernel virtual address is the same as the @@ -560,7 +478,7 @@ unsigned long mm_ptov (unsigned long paddr) * Jes was worried about performance (urhh ???) so its optional */ -extern void (*mach_l2_flush)(int) = NULL; +void (*mach_l2_flush)(int) = NULL; #endif /* diff --git a/arch/m68k/mvme16x/16xints.c b/arch/m68k/mvme16x/16xints.c index fbb370a07..9cc0d39d1 100644 --- a/arch/m68k/mvme16x/16xints.c +++ b/arch/m68k/mvme16x/16xints.c @@ -106,9 +106,12 @@ void mvme16x_free_irq(unsigned int irq, void *dev_id) void mvme16x_process_int (unsigned long vec, struct pt_regs *fp) { if (vec < 64 || vec > 255) - panic ("mvme16x_process_int: Illegal vector %ld", vec); - irq_tab[vec-64].count++; - irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp); + printk ("mvme16x_process_int: Illegal vector %ld", vec); + else + { + irq_tab[vec-64].count++; + irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp); + } } int mvme16x_get_irq_list (char *buf) diff --git a/arch/m68k/vmlinux.lds b/arch/m68k/vmlinux.lds index 88ee16b66..b79c9dd87 100644 --- a/arch/m68k/vmlinux.lds +++ b/arch/m68k/vmlinux.lds @@ -35,6 +35,9 @@ SECTIONS _edata = .; /* End of data section */ + . = ALIGN(16); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + . = ALIGN(4096); /* Init code and data */ __init_begin = .; .text.init : { *(.text.init) } |