Commit 88af9fa8 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] arch specific files for MMUless NEC v850 port

This is the V850 support maintained by Miles Bader at NEC

Again this is just arch and include/asm- files. It matches 2.5.45-uc1 + v850
fixes which is close to what was in my old tree (some clean up done since then)
plus Kconfig
parent 9ce59cdc
This diff is collapsed.
#
# arch/v850/Makefile
#
# Copyright (C) 2001,02 NEC Corporation
# Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies. Remember to do have actions
# for "archclean" and "archdep" for cleaning up and making dependencies for
# this architecture
#
# 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
# for more details.
#
arch_dir = arch/v850
CFLAGS += -mv850e
# r16 is a fixed pointer to the current task
CFLAGS += -ffixed-r16 -mno-prolog-function
CFLAGS += -fno-builtin
CFLAGS += -D__linux__ -DUTS_SYSNAME=\"uClinux\"
HEAD := $(arch_dir)/kernel/head.o $(arch_dir)/kernel/init_task.o
core-y += $(arch_dir)/kernel/
libs-y += $(arch_dir)/lib/
include $(TOPDIR)/Rules.make
# Deal with the initial contents of the root device
ifdef ROOT_FS_IMAGE
core-y += root_fs_image.o
# Because the kernel build-system erases all explicit .o build rules, we
# have to use an intermediate target to fool it into building for us.
# This results in it being built anew each time, but that's alright.
root_fs_image.o: root_fs_image_force
# Note that we use the build-system's objcopy, as the v850 tools are fairly
# old, and don't have the --rename-section option.
root_fs_image_force: $(ROOT_FS_IMAGE)
objcopy -I binary -O elf32-little -B i386 --rename-section .data=.root,alloc,load,readonly,data,contents $< root_fs_image.o
endif
prepare: include/asm-$(ARCH)/asm-consts.h
# Generate constants from C code for use by asm files
arch/$(ARCH)/kernel/asm-consts.s: include/asm include/linux/version.h \
include/config/MARKER
include/asm-$(ARCH)/asm-consts.h.tmp: arch/$(ARCH)/kernel/asm-consts.s
@$(generate-asm-offsets.h) < $< > $@
include/asm-$(ARCH)/asm-consts.h: include/asm-$(ARCH)/asm-consts.h.tmp
@echo -n ' Generating $@'
@$(update-if-changed)
CLEAN_FILES += include/asm-$(ARCH)/asm-consts.h.tmp \
include/asm-$(ARCH)/asm-consts.h \
arch/$(ARCH)/kernel/asm-consts.s \
root_fs_image.o
This port to the NEC V850E processor supports the following platforms:
+ The gdb v850e simulator (CONFIG_V850E_SIM); see the subdirectory `sim'
for some more support files for this.
+ The Midas labs RTE-V850E/MA1-CB evaluation board (CONFIG_RTE_CB_MA1),
with untested support for the RTE-V850E/NB85E-CB board
(CONFIG_RTE_CB_NB85E). This support has only been tested when running
with the Multi-debugger monitor ROM (for the Green Hills Multi debugger).
The optional NEC Solution Gear RTE-MOTHER-A motherboard is also
supported, which allows PCI boards to be used (CONFIG_RTE_MB_A_PCI).
+ The sim85e2c simulator, which is a verilog simulation of the V850E2
NA85E2C cpu core (CONFIG_V850E2_SIM85E2C).
+ A FPGA implementation of the V850E2 NA85E2C cpu core
(CONFIG_V850E2_FPGA85E2C).
+ The `Anna' (board/chip) implementation of the V850E2 processor.
Porting to anything with a V850E/MA1 or MA2 processor should be simple.
See the file <asm-v850/machdep.h> and the files it includes for an example of
how to add platform/chip-specific support.
/* Linker script for the Midas labs Anna V850E2 evaluation board
(CONFIG_V850E2_ANNA), with kernel in ROM (CONFIG_ROM_KERNEL). */
/* Note, all symbols are prefixed with an extra `_' for compatibility with
the existing linux sources. */
_jiffies = _jiffies_64 ;
MEMORY {
/* 8MB of flash ROM. */
ROM : ORIGIN = 0, LENGTH = 0x00800000
/* 1MB of static RAM. This memory is mirrored 64 times. */
SRAM : ORIGIN = 0x04000000, LENGTH = 0x00100000
/* 64MB of DRAM. */
SDRAM : ORIGIN = 0x08000000, LENGTH = 0x04000000
}
SECTIONS {
.intv : {
__intv_start = . ;
*(.intv.reset) /* Reset vector */
*(.intv.common) /* Vectors common to all v850e proc. */
*(.intv.mach) /* Machine-specific int. vectors. */
__intv_end = . ;
} > ROM
.text ALIGN (0x10) : {
__stext = . ;
*(.text)
*(.exit.text) /* 2.5 convention */
*(.text.exit) /* 2.4 convention */
*(.text.lock)
*(.exitcall.exit)
__real_etext = . ; /* There may be data after here. */
*(.rodata)
. = ALIGN (0x4) ;
*(.kstrtab)
. = ALIGN (4) ;
*(.call_table_data)
*(.call_table_text)
. = ALIGN (16) ; /* Exception table. */
___start___ex_table = . ;
*(__ex_table)
___stop___ex_table = . ;
___start___ksymtab = . ;/* Kernel symbol table. */
*(__ksymtab)
___stop___ksymtab = . ;
. = ALIGN (4) ;
__etext = . ;
} > ROM
.init_text ALIGN (4096) : {
*(.init.text) /* 2.5 convention */
*(.text.init) /* 2.4 convention */
. = ALIGN (16) ;
___setup_start = . ;
*(.init.setup) /* 2.5 convention */
*(.setup.init) /* 2.4 convention */
___setup_end = . ;
___initcall_start = . ;
*(.initcall.init)
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
. = ALIGN (4) ;
___initcall_end = . ;
} > ROM
/* Device contents for the root filesystem. */
.root ALIGN (4096) : {
__root_fs_image_start = . ;
*(.root)
__root_fs_image_end = . ;
} > ROM
__rom_copy_src_start = . ;
.data : {
__kram_start = . ;
__rom_copy_dst_start = . ;
__sdata = . ;
___data_start = . ;
*(.data)
*(.exit.data) /* 2.5 convention */
*(.data.exit) /* 2.4 convention */
. = ALIGN (16) ;
*(.data.cacheline_aligned)
. = ALIGN (0x2000) ;
*(.data.init_task)
. = ALIGN (0x2000) ;
__edata = . ;
} > SRAM AT> ROM
.init_data ALIGN (4096) : {
__init_start = . ;
*(.init.data) /* 2.5 convention */
*(.data.init) /* 2.4 convention */
__init_end = . ;
__rom_copy_dst_end = . ;
} > SRAM AT> ROM
.bss ALIGN (4096) : {
__sbss = . ;
*(.bss)
*(COMMON)
. = ALIGN (4) ;
__init_stack_end = . ;
__ebss = . ;
__kram_end = . ;
} > SRAM
.bootmap ALIGN (4096) : {
__bootmap = . ;
. = . + 4096 ; /* enough for 128MB. */
} > SRAM
}
/* Linker script for the Midas labs Anna V850E2 evaluation board
(CONFIG_V850E2_ANNA). */
/* Note, all symbols are prefixed with an extra `_' for compatibility with
the existing linux sources. */
_jiffies = _jiffies_64 ;
MEMORY {
/* 256KB of internal memory (followed by one mirror). */
iMEM0 : ORIGIN = 0, LENGTH = 0x00040000
/* 256KB of internal memory (followed by one mirror). */
iMEM1 : ORIGIN = 0x00040000, LENGTH = 0x00040000
/* 1MB of static RAM. This memory is mirrored 64 times. */
SRAM : ORIGIN = 0x04000000, LENGTH = 0x00100000
/* 64MB of DRAM. */
SDRAM : ORIGIN = 0x08000000, LENGTH = 0x04000000
}
SECTIONS {
.intv : {
__intv_start = . ;
*(.intv.reset) /* Reset vector */
*(.intv.common) /* Vectors common to all v850e proc. */
*(.intv.mach) /* Machine-specific int. vectors. */
__intv_end = . ;
} > iMEM0
.text : {
__kram_start = . ;
__stext = . ;
*(.text)
*(.exit.text) /* 2.5 convention */
*(.text.exit) /* 2.4 convention */
*(.text.lock)
*(.exitcall.exit)
__real_etext = . ; /* There may be data after here. */
*(.rodata)
. = ALIGN (0x4) ;
*(.kstrtab)
. = ALIGN (4) ;
*(.call_table_data)
*(.call_table_text)
. = ALIGN (16) ; /* Exception table. */
___start___ex_table = . ;
*(__ex_table)
___stop___ex_table = . ;
___start___ksymtab = . ;/* Kernel symbol table. */
*(__ksymtab)
___stop___ksymtab = . ;
. = ALIGN (4) ;
__etext = . ;
} > SRAM
.data ALIGN (0x4) : {
__sdata = . ;
___data_start = . ;
*(.data)
*(.exit.data) /* 2.5 convention */
*(.data.exit) /* 2.4 convention */
. = ALIGN (16) ;
*(.data.cacheline_aligned)
. = ALIGN (0x2000) ;
*(.data.init_task)
. = ALIGN (0x2000) ;
__edata = . ;
} > SRAM
.bss ALIGN (0x4) : {
__sbss = . ;
*(.bss)
*(COMMON)
. = ALIGN (4) ;
__init_stack_end = . ;
__ebss = . ;
} > SRAM
.init ALIGN (4096) : {
__init_start = . ;
*(.init.text) /* 2.5 convention */
*(.init.data)
*(.text.init) /* 2.4 convention */
*(.data.init)
. = ALIGN (16) ;
___setup_start = . ;
*(.init.setup) /* 2.5 convention */
*(.setup.init) /* 2.4 convention */
___setup_end = . ;
___initcall_start = . ;
*(.initcall.init)
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
. = ALIGN (4) ;
___initcall_end = . ;
__init_end = . ;
__kram_end = . ;
} > SRAM
.bootmap ALIGN (4096) : {
__bootmap = . ;
. = . + 4096 ; /* enough for 128MB. */
} > SRAM
/* Device contents for the root filesystem. */
.root : {
__root_fs_image_start = . ;
*(.root)
__root_fs_image_end = . ;
} > SDRAM
}
/* Linker script for the FPGA implementation of the V850E2 NA85E2C cpu core
(CONFIG_V850E2_FPGA85E2C). */
/* Note, all symbols are prefixed with an extra `_' for compatibility with
the existing linux sources. */
_jiffies = _jiffies_64 ;
MEMORY {
/* Reset vector. */
RESET : ORIGIN = 0, LENGTH = 0x10
/* Interrupt vectors. */
INTV : ORIGIN = 0x10, LENGTH = 0x470
/* The `window' in RAM were we're allowed to load stuff. */
RAM_LOW : ORIGIN = 0x480, LENGTH = 0x0005FB80
/* Some more ram above the window were we can put bss &c. */
RAM_HIGH : ORIGIN = 0x00060000, LENGTH = 0x000A0000
/* This is the area visible from the outside world (we can use
this only for uninitialized data). */
VISIBLE : ORIGIN = 0x00200000, LENGTH = 0x00060000
}
SECTIONS {
.reset : {
__kram_start = . ;
__intv_start = . ;
*(.intv.reset) /* Reset vector */
} > RESET
.r0_ram : {
__r0_ram = . ;
. = . + 32 ;
} > RAM_LOW
.text : {
__stext = . ;
*(.text)
*(.exit.text) /* 2.5 convention */
*(.text.exit) /* 2.4 convention */
*(.text.lock)
*(.exitcall.exit)
__real_etext = . ; /* There may be data after here. */
*(.rodata)
. = ALIGN (0x4) ;
*(.kstrtab)
. = ALIGN (4) ;
*(.call_table_data)
*(.call_table_text)
. = ALIGN (16) ; /* Exception table. */
___start___ex_table = . ;
*(__ex_table)
___stop___ex_table = . ;
___start___ksymtab = . ;/* Kernel symbol table. */
*(__ksymtab)
___stop___ksymtab = . ;
. = ALIGN (4) ;
__etext = . ;
} > RAM_LOW
.data : {
__sdata = . ;
*(.data)
*(.exit.data) /* 2.5 convention */
*(.data.exit) /* 2.4 convention */
. = ALIGN (16) ;
*(.data.cacheline_aligned)
. = ALIGN (0x2000) ;
*(.data.init_task)
. = ALIGN (0x2000) ;
__edata = . ;
} > RAM_LOW
/* Device contents for the root filesystem. */
.root : {
. = ALIGN (4096) ;
__root_fs_image_start = . ;
*(.root)
__root_fs_image_end = . ;
} > RAM_LOW
.init ALIGN (4096) : {
__init_start = . ;
*(.init.text) /* 2.5 convention */
*(.init.data)
*(.text.init) /* 2.4 convention */
*(.data.init)
. = ALIGN (16) ;
___setup_start = . ;
*(.init.setup) /* 2.5 convention */
*(.setup.init) /* 2.4 convention */
___setup_end = . ;
___initcall_start = . ;
*(.initcall.init)
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
. = ALIGN (4) ;
___initcall_end = . ;
} > RAM_LOW
/* Where the interrupt vectors are initially loaded. */
__intv_load_start = . ;
.intv : {
*(.intv.common) /* Vectors common to all v850e proc. */
*(.intv.mach) /* Machine-specific int. vectors. */
__intv_end = . ;
} > INTV AT> RAM_LOW
.bss : {
/* This is here so that when we free init memory the
load-time copy of the interrupt vectors and any empty
space at the end of the `RAM_LOW' area is freed too. */
. = ALIGN (4096);
__init_end = . ;
__sbss = . ;
*(.bss)
*(COMMON)
. = ALIGN (4) ;
__init_stack_end = . ;
__ebss = . ;
__kram_end = . ;
} > RAM_HIGH
.bootmap ALIGN (4096) : {
__bootmap = . ;
. = . + 4096 ; /* enough for 128MB. */
} > RAM_HIGH
.visible : {
_memcons_output = . ;
. = . + 0x8000 ;
_memcons_output_end = . ;
} > VISIBLE
}
#
# arch/v850/kernel/Makefile
#
# Copyright (C) 2001,02 NEC Corporation
# Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
#
# 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
# for more details.
#
EXTRA_TARGETS := head.o init_task.o
obj-y += intv.o entry.o process.o syscalls.o time.o semaphore.o setup.o \
signal.o irq.o mach.o ptrace.o bug.o
export-objs += v850_ksyms.o rte_mb_a_pci.o
obj-$(CONFIG_MODULES) += v850_ksyms.o
# chip-specific code
obj-$(CONFIG_V850E_MA1) += ma.o nb85e_utils.o nb85e_timer_d.o
obj-$(CONFIG_V850E_NB85E) += nb85e_intc.o
obj-$(CONFIG_V850E2_ANNA) += anna.o nb85e_intc.o nb85e_utils.o nb85e_timer_d.o
# platform-specific code
obj-$(CONFIG_V850E_SIM) += sim.o simcons.o
obj-$(CONFIG_V850E2_SIM85E2C) += sim85e2c.o nb85e_intc.o memcons.o
obj-$(CONFIG_V850E2_FPGA85E2C) += fpga85e2c.o nb85e_intc.o memcons.o
obj-$(CONFIG_RTE_CB) += rte_cb.o rte_cb_leds.o
obj-$(CONFIG_RTE_CB_MA1) += rte_ma1_cb.o
obj-$(CONFIG_RTE_CB_NB85E) += rte_nb85e_cb.o
obj-$(CONFIG_RTE_CB_MULTI) += rte_cb_multi.o
obj-$(CONFIG_RTE_MB_A_PCI) += rte_mb_a_pci.o
obj-$(CONFIG_RTE_GBUS_INT) += gbus_int.o
# feature-specific code
obj-$(CONFIG_V850E_MA1_HIGHRES_TIMER) += highres_timer.o
obj-$(CONFIG_PROC_FS) += procfs.o
include $(TOPDIR)/Rules.make
/*
* arch/v850/kernel/anna.c -- Anna V850E2 evaluation chip/board
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/major.h>
#include <linux/irq.h>
#include <asm/machdep.h>
#include <asm/atomic.h>
#include <asm/page.h>
#include <asm/nb85e_timer_d.h>
#include <asm/nb85e_uart.h>
#include "mach.h"
/* SRAM and SDRAM are vaguely contiguous (with a hole in between; see
mach_reserve_bootmem for details), so just use both as one big area. */
#define RAM_START SRAM_ADDR
#define RAM_END (SDRAM_ADDR + SDRAM_SIZE)
static void anna_led_tick (void);
void __init mach_early_init (void)
{
ANNA_ILBEN = 0;
ANNA_CSC(0) = 0x402F;
ANNA_CSC(1) = 0x4000;
ANNA_BPC = 0;
ANNA_BSC = 0xAAAA;
ANNA_BEC = 0;
ANNA_BHC = 0x00FF; /* icache all memory, dcache none */
ANNA_BCT(0) = 0xB088;
ANNA_BCT(1) = 0x0008;
ANNA_DWC(0) = 0x0027;
ANNA_DWC(1) = 0;
ANNA_BCC = 0x0006;
ANNA_ASC = 0;
ANNA_LBS = 0x0089;
ANNA_SCR3 = 0x21A9;
ANNA_RFS3 = 0x8121;
nb85e_intc_disable_irqs ();
}
void __init mach_setup (char **cmdline)
{
printk (KERN_INFO
"CPU: %s\n"
"Platform: %s\n",
CPU_MODEL_LONG,
PLATFORM_LONG);
#ifdef CONFIG_V850E_NB85E_UART_CONSOLE
nb85e_uart_cons_init (1);
#endif
ANNA_PORT_PM (0) = 0; /* Make all LED pins output pins. */
mach_tick = anna_led_tick;
}
void __init mach_get_physical_ram (unsigned long *ram_start,
unsigned long *ram_len)
{
*ram_start = RAM_START;
*ram_len = RAM_END - RAM_START;
}
void __init mach_reserve_bootmem ()
{
/* The space between SRAM and SDRAM is filled with duplicate
images of SRAM. Prevent the kernel from using them. */
reserve_bootmem (SRAM_ADDR + SRAM_SIZE,
SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE));
}
void mach_gettimeofday (struct timespec *tv)
{
tv->tv_sec = 0;
tv->tv_nsec = 0;
}
void __init mach_sched_init (struct irqaction *timer_action)
{
/* Start hardware timer. */
nb85e_timer_d_configure (0, HZ);
/* Install timer interrupt handler. */
setup_irq (IRQ_INTCMD(0), timer_action);
}
static struct nb85e_intc_irq_init irq_inits[] = {
{ "IRQ", 0, NUM_MACH_IRQS, 1, 7 },
{ "PIN", IRQ_INTP(0), IRQ_INTP_NUM, 1, 4 },
{ "CCC", IRQ_INTCCC(0), IRQ_INTCCC_NUM, 1, 5 },
{ "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 },
{ "DMA", IRQ_INTDMA(0), IRQ_INTDMA_NUM, 1, 2 },
{ "DMXER", IRQ_INTDMXER,1, 1, 2 },
{ "SRE", IRQ_INTSRE(0), IRQ_INTSRE_NUM, 3, 3 },
{ "SR", IRQ_INTSR(0), IRQ_INTSR_NUM, 3, 4 },
{ "ST", IRQ_INTST(0), IRQ_INTST_NUM, 3, 5 },
{ 0 }
};
#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
void __init mach_init_irqs (void)
{
nb85e_intc_init_irq_types (irq_inits, hw_itypes);
}
void machine_restart (char *__unused)
{
#ifdef CONFIG_RESET_GUARD
disable_reset_guard ();
#endif
asm ("jmp r0"); /* Jump to the reset vector. */
}
void machine_halt (void)
{
#ifdef CONFIG_RESET_GUARD
disable_reset_guard ();
#endif
local_irq_disable (); /* Ignore all interrupts. */
ANNA_PORT_IO(0) = 0xAA; /* Note that we halted. */
for (;;)
asm ("halt; nop; nop; nop; nop; nop");
}
void machine_power_off (void)
{
machine_halt ();
}
/* Called before configuring an on-chip UART. */
void anna_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud)
{
/* The Anna connects some general-purpose I/O pins on the CPU to
the RTS/CTS lines of UART 1's serial connection. I/O pins P07
and P37 are RTS and CTS respectively. */
if (chan == 1) {
ANNA_PORT_PM(0) &= ~0x80; /* P07 in output mode */
ANNA_PORT_PM(3) |= 0x80; /* P37 in input mode */
}
}
/* Minimum and maximum bounds for the moving upper LED boundary in the
clock tick display. We can't use the last bit because it's used for
UART0's CTS output. */
#define MIN_MAX_POS 0
#define MAX_MAX_POS 6
/* There are MAX_MAX_POS^2 - MIN_MAX_POS^2 cycles in the animation, so if
we pick 6 and 0 as above, we get 49 cycles, which is when divided into
the standard 100 value for HZ, gives us an almost 1s total time. */
#define TICKS_PER_FRAME \
(HZ / (MAX_MAX_POS * MAX_MAX_POS - MIN_MAX_POS * MIN_MAX_POS))
static void anna_led_tick ()
{
static unsigned counter = 0;
if (++counter == TICKS_PER_FRAME) {
static int pos = 0, max_pos = MAX_MAX_POS, dir = 1;
if (dir > 0 && pos == max_pos) {
dir = -1;
if (max_pos == MIN_MAX_POS)
max_pos = MAX_MAX_POS;
else
max_pos--;
} else {
if (dir < 0 && pos == 0)
dir = 1;
if (pos + dir <= max_pos) {
/* Each bit of port 0 has a LED. */
clear_bit (pos, &ANNA_PORT_IO(0));
pos += dir;
set_bit (pos, &ANNA_PORT_IO(0));
}
}
counter = 0;
}
}
/*
* This program is used to generate definitions needed by
* assembly language modules.
*
* We use the technique used in the OSF Mach kernel code:
* generate asm statements containing #defines,
* compile this file to assembler, and then extract the
* #defines from the assembly-language output.
*/
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <asm/irq.h>
#include <asm/hardirq.h>
#include <asm/errno.h>
#define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
#define BLANK() asm volatile("\n->" : : )
int main (void)
{
/* offsets into the task struct */
DEFINE (TASK_STATE, offsetof (struct task_struct, state));
DEFINE (TASK_FLAGS, offsetof (struct task_struct, flags));
DEFINE (TASK_PTRACE, offsetof (struct task_struct, ptrace));
DEFINE (TASK_BLOCKED, offsetof (struct task_struct, blocked));
DEFINE (TASK_THREAD, offsetof (struct task_struct, thread));
DEFINE (TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
DEFINE (TASK_MM, offsetof (struct task_struct, mm));
DEFINE (TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
DEFINE (TASK_PID, offsetof (struct task_struct, pid));
/* offsets into the kernel_stat struct */
DEFINE (STAT_IRQ, offsetof (struct kernel_stat, irqs));
/* signal defines */
DEFINE (SIGSEGV, SIGSEGV);
DEFINE (SEGV_MAPERR, SEGV_MAPERR);
DEFINE (SIGTRAP, SIGTRAP);
DEFINE (SIGCHLD, SIGCHLD);
DEFINE (SIGILL, SIGILL);
DEFINE (TRAP_TRACE, TRAP_TRACE);
/* ptrace flag bits */
DEFINE (PT_PTRACED, PT_PTRACED);
DEFINE (PT_DTRACE, PT_DTRACE);
/* error values */
DEFINE (ENOSYS, ENOSYS);
/* clone flag bits */
DEFINE (CLONE_VFORK, CLONE_VFORK);
DEFINE (CLONE_VM, CLONE_VM);
return 0;
}
/*
* arch/v850/kernel/bug.c -- Bug reporting functions
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/kernel.h>
#include <linux/reboot.h>
#include <linux/sched.h>
#include <asm/errno.h>
#include <asm/ptrace.h>
#include <asm/current.h>
/* We should use __builtin_return_address, but it doesn't work in gcc-2.90
(which is currently our standard compiler on the v850). */
#define ret_addr() ({ register u32 lp asm ("lp"); lp; })
#define stack_addr() ({ register u32 sp asm ("sp"); sp; })
void __bug ()
{
printk (KERN_CRIT "kernel BUG at PC 0x%x (SP ~0x%x)!\n",
ret_addr() - 4, /* - 4 for `jarl' */
stack_addr());
machine_halt ();
}
int bad_trap (int trap_num, struct pt_regs *regs)
{
printk (KERN_CRIT
"unimplemented trap %d called at 0x%08lx, pid %d!\n",
trap_num, regs->pc, current->pid);
return -ENOSYS;
}
int debug_trap (struct pt_regs *regs)
{
printk (KERN_CRIT "debug trap at 0x%08lx!\n", regs->pc);
return -ENOSYS;
}
#ifdef CONFIG_RESET_GUARD
void unexpected_reset (unsigned long ret_addr, unsigned long kmode,
struct task_struct *task, unsigned long sp)
{
printk (KERN_CRIT
"unexpected reset in %s mode, pid %d"
" (ret_addr = 0x%lx, sp = 0x%lx)\n",
kmode ? "kernel" : "user",
task ? task->pid : -1,
ret_addr, sp);
machine_halt ();
}
#endif /* CONFIG_RESET_GUARD */
This diff is collapsed.
/*
* arch/v850/kernel/fpga85e2c.h -- Machine-dependent defs for
* FPGA implementation of V850E2/NA85E2C
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
#include <linux/irq.h>
#include <asm/atomic.h>
#include <asm/page.h>
#include <asm/machdep.h>
#include <asm/bitops.h>
#include "mach.h"
extern void memcons_setup (void);
#define REG_DUMP_ADDR 0x220000
extern struct irqaction reg_snap_action; /* fwd decl */
void __init mach_early_init (void)
{
int i;
const u32 *src;
register u32 *dst asm ("ep");
extern int panic_timeout;
extern u32 _intv_end, _intv_load_start;
/* Set bus sizes: CS0 32-bit, CS1 16-bit, CS7 8-bit,
everything else 32-bit. */
BSC = 0x2AA6;
for (i = 2; i <= 6; i++)
CSDEV(i) = 0; /* 32 bit */
/* Ensure that the simulator halts on a panic, instead of going
into an infinite loop inside the panic function. */
panic_timeout = -1;
/* Move the interrupt vectors into their real location. Note that
any relocations there are relative to the real location, so we
don't have to fix anything up. We use a loop instead of calling
memcpy to keep this a leaf function (to avoid a function
prologue being generated). */
dst = 0x10; /* &_intv_start + 0x10. */
src = &_intv_load_start;
do {
u32 t0 = src[0], t1 = src[1], t2 = src[2], t3 = src[3];
u32 t4 = src[4], t5 = src[5], t6 = src[6], t7 = src[7];
dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3;
dst[4] = t4; dst[5] = t5; dst[6] = t6; dst[7] = t7;
dst += 8;
src += 8;
} while (dst < &_intv_end);
}
void __init mach_setup (char **cmdline)
{
printk (KERN_INFO "CPU: NEC V850E2 (NA85E2C FPGA implementation)\n");
memcons_setup ();
/* Setup up NMI0 to copy the registers to a known memory location.
The FGPA board has a button that produces NMI0 when pressed, so
this allows us to push the button, and then look at memory to see
what's in the registers (there's no other way to easily do so).
We have to use `setup_irq' instead of `request_irq' because it's
still too early to do memory allocation. */
setup_irq (IRQ_NMI (0), &reg_snap_action);
}
void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len)
{
*ram_start = ERAM_ADDR;
*ram_len = ERAM_SIZE;
}
void __init mach_sched_init (struct irqaction *timer_action)
{
/* Setup up the timer interrupt. The FPGA peripheral control
registers _only_ work with single-bit writes (set1/clr1)! */
__clear_bit (RPU_GTMC_CE_BIT, &RPU_GTMC);
__clear_bit (RPU_GTMC_CLK_BIT, &RPU_GTMC);
__set_bit (RPU_GTMC_CE_BIT, &RPU_GTMC);
/* We use the first RPU interrupt, which occurs every 8.192ms. */
setup_irq (IRQ_RPU (0), timer_action);
}
void mach_gettimeofday (struct timespec *tv)
{
tv->tv_sec = 0;
tv->tv_nsec = 0;
}
void machine_halt (void) __attribute__ ((noreturn));
void machine_halt (void)
{
for (;;) {
DWC(0) = 0x7777;
DWC(1) = 0x7777;
ASC = 0xffff;
FLGREG(0) = 1; /* Halt immediately. */
asm ("di; halt; nop; nop; nop; nop; nop");
}
}
void machine_restart (char *__unused)
{
machine_halt ();
}
void machine_power_off (void)
{
machine_halt ();
}
/* Interrupts */
struct nb85e_intc_irq_init irq_inits[] = {
{ "IRQ", 0, NUM_MACH_IRQS, 1, 7 },
{ "RPU", IRQ_RPU(0), IRQ_RPU_NUM, 1, 6 },
{ 0 }
};
#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
/* Initialize interrupts. */
void __init mach_init_irqs (void)
{
nb85e_intc_init_irq_types (irq_inits, hw_itypes);
}
/* An interrupt handler that copies the registers to a known memory location,
for debugging purposes. */
static void make_reg_snap (int irq, void *dummy, struct pt_regs *regs)
{
(*(unsigned *)REG_DUMP_ADDR)++;
(*(struct pt_regs *)(REG_DUMP_ADDR + sizeof (unsigned))) = *regs;
}
static int reg_snap_dev_id;
static struct irqaction reg_snap_action = {
make_reg_snap, 0, 0, "reg_snap", &reg_snap_dev_id, 0
};
/*
* arch/v850/kernel/gbus_int.c -- Midas labs GBUS interrupt support
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/types.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/sched.h> /* For some unfathomable reason,
request_irq/free_irq are declared here. */
#include <asm/machdep.h>
#include <asm/irq.h>
/* The number of shared GINT interrupts. */
#define NUM_GINTS 4
/* For each GINT interrupt, how many GBUS interrupts are using it. */
static unsigned gint_num_active_irqs[NUM_GINTS] = { 0 };
/* A table of GINTn interrupts we actually use. */
struct used_gint {
unsigned gint;
unsigned priority;
} used_gint[] = {
{ 1, GBUS_INT_PRIORITY_HIGH },
{ 3, GBUS_INT_PRIORITY_LOW }
};
#define NUM_USED_GINTS (sizeof used_gint / sizeof used_gint[0])
/* A table of which GINT is used by each GBUS interrupts (they are
assigned based on priority). */
static unsigned char gbus_int_gint[IRQ_GBUS_INT_NUM];
/* Interrupt enabling/disabling. */
/* Enable interrupt handling for interrupt IRQ. */
void gbus_int_enable_irq (unsigned irq)
{
unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
|= GBUS_INT_IRQ_MASK (irq);
}
/* Disable interrupt handling for interrupt IRQ. Note that any
interrupts received while disabled will be delivered once the
interrupt is enabled again, unless they are explicitly cleared using
`gbus_int_clear_pending_irq'. */
void gbus_int_disable_irq (unsigned irq)
{
unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
&= ~GBUS_INT_IRQ_MASK (irq);
}
/* Return true if interrupt handling for interrupt IRQ is enabled. */
int gbus_int_irq_enabled (unsigned irq)
{
unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
return (GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
& GBUS_INT_IRQ_MASK(irq));
}
/* Disable all GBUS irqs. */
int gbus_int_disable_irqs ()
{
unsigned w, n;
for (w = 0; w < GBUS_INT_NUM_WORDS; w++)
for (n = 0; n < IRQ_GINT_NUM; n++)
GBUS_INT_ENABLE (w, n) = 0;
}
/* Clear any pending interrupts for IRQ. */
void gbus_int_clear_pending_irq (unsigned irq)
{
GBUS_INT_CLEAR (GBUS_INT_IRQ_WORD(irq)) = GBUS_INT_IRQ_MASK (irq);
}
/* Return true if interrupt IRQ is pending (but disabled). */
int gbus_int_irq_pending (unsigned irq)
{
return (GBUS_INT_STATUS (GBUS_INT_IRQ_WORD(irq))
& GBUS_INT_IRQ_MASK(irq));
}
/* Delegating interrupts. */
/* Handle a shared GINT interrupt by passing to the appropriate GBUS
interrupt handler. */
static void gbus_int_handle_irq (int irq, void *dev_id, struct pt_regs *regs)
{
unsigned w;
unsigned gint = irq - IRQ_GINT (0);
for (w = 0; w < GBUS_INT_NUM_WORDS; w++) {
unsigned status = GBUS_INT_STATUS (w);
unsigned enable = GBUS_INT_ENABLE (w, gint);
/* Only pay attention to enabled interrupts. */
status &= enable;
if (status) {
unsigned base_irq
= IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD);
irq = base_irq;
do {
/* There's an active interrupt in word
W, find out which one, and call its
handler. */
while (! (status & 0x1)) {
irq++;
status >>= 1;
}
status &= ~0x1;
/* Recursively call handle_irq to handle it. */
handle_irq (irq, regs);
} while (status);
}
}
/* Toggle the `all enable' bit back and forth, which should cause
another edge transition if there are any other interrupts
still pending, and so result in another CPU interrupt. */
GBUS_INT_ENABLE (0, gint) &= ~0x1;
GBUS_INT_ENABLE (0, gint) |= 0x1;
}
/* Initialize GBUS interrupt sources. */
static void irq_nop (unsigned irq) { }
static unsigned gbus_int_startup_irq (unsigned irq)
{
unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
if (gint_num_active_irqs[gint] == 0) {
/* First enable the CPU interrupt. */
int rval =
request_irq (IRQ_GINT(gint), gbus_int_handle_irq,
SA_INTERRUPT,
"gbus_int_handler",
&gint_num_active_irqs[gint]);
if (rval != 0)
return rval;
}
gint_num_active_irqs[gint]++;
gbus_int_clear_pending_irq (irq);
gbus_int_enable_irq (irq);
return 0;
}
static void gbus_int_shutdown_irq (unsigned irq)
{
unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
gbus_int_disable_irq (irq);
if (--gint_num_active_irqs[gint] == 0)
/* Disable the CPU interrupt. */
free_irq (IRQ_GINT(gint), &gint_num_active_irqs[gint]);
}
/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
INITS (which is terminated by an entry with the name field == 0). */
void __init gbus_int_init_irq_types (struct gbus_int_irq_init *inits,
struct hw_interrupt_type *hw_irq_types)
{
struct gbus_int_irq_init *init;
for (init = inits; init->name; init++) {
int i;
struct hw_interrupt_type *hwit = hw_irq_types++;
hwit->typename = init->name;
hwit->startup = gbus_int_startup_irq;
hwit->shutdown = gbus_int_shutdown_irq;
hwit->enable = gbus_int_enable_irq;
hwit->disable = gbus_int_disable_irq;
hwit->ack = irq_nop;
hwit->end = irq_nop;
/* Initialize kernel IRQ infrastructure for this interrupt. */
init_irq_handlers(init->base, init->num, init->interval, hwit);
/* Set the interrupt priorities. */
for (i = 0; i < init->num; i++) {
int j;
for (j = 0; j < NUM_USED_GINTS; j++)
if (used_gint[j].priority > init->priority)
break;
/* Wherever we stopped looking is one past the
GINT we want. */
gbus_int_gint[init->base + i * init->interval
- GBUS_INT_BASE_IRQ]
= used_gint[j > 0 ? j - 1 : 0].gint;
}
}
}
/* Initialize IRQS. */
/* Chip interrupts (GINTn) shared among GBUS interrupts. */
static struct hw_interrupt_type gint_hw_itypes[NUM_USED_GINTS];
/* GBUS interrupts themselves. */
__init struct gbus_int_irq_init gbus_irq_inits[] = {
/* First set defaults. */
{ "GBUS_INT", IRQ_GBUS_INT(0), IRQ_GBUS_INT_NUM, 1, 6},
{ 0 }
};
#define NUM_GBUS_IRQ_INITS \
((sizeof gbus_irq_inits / sizeof gbus_irq_inits[0]) - 1)
static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS];
/* Initialize GBUS interrupts. */
void __init gbus_int_init_irqs (void)
{
int i;
/* First initialize the shared gint interrupts. */
for (i = 0; i < NUM_USED_GINTS; i++) {
unsigned gint = used_gint[i].gint;
struct nb85e_intc_irq_init gint_irq_init[2];
/* We initialize one GINT interrupt at a time. */
gint_irq_init[0].name = "GINT";
gint_irq_init[0].base = IRQ_GINT (gint);
gint_irq_init[0].num = 1;
gint_irq_init[0].interval = 1;
gint_irq_init[0].priority = used_gint[i].priority;
gint_irq_init[1].name = 0; /* Terminate the vector. */
nb85e_intc_init_irq_types (gint_irq_init, gint_hw_itypes);
}
/* Then the GBUS interrupts. */
gbus_int_disable_irqs ();
gbus_int_init_irq_types (gbus_irq_inits, gbus_hw_itypes);
/* Turn on the `all enable' bits, which are ANDed with
individual interrupt enable bits; we only want to bother with
the latter. They are the first bit in the first word of each
interrupt-enable area. */
for (i = 0; i < NUM_USED_GINTS; i++)
GBUS_INT_ENABLE (0, used_gint[i].gint) = 0x1;
}
/*
* arch/v850/kernel/head.S -- Lowest-level startup code
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <asm/clinkage.h>
#include <asm/current.h>
#include <asm/entry.h>
#include <asm/thread_info.h>
#include <asm/irq.h>
/* Make a slightly more convenient alias for C_SYMBOL_NAME. */
#define CSYM C_SYMBOL_NAME
.text
// Define `mach_early_init' as a weak symbol
.global CSYM(mach_early_init)
.weak CSYM(mach_early_init)
C_ENTRY(start):
// Make sure interrupts are turned off, just in case
di
#ifdef CONFIG_RESET_GUARD
// See if we got here via an unexpected reset
ld.w RESET_GUARD, r19 // Check current value of reset guard
mov RESET_GUARD_ACTIVE, r20
cmp r19, r20
bne 1f // Guard was not active
// If we get here, the reset guard was active. Load up some
// interesting values as arguments, and jump to the handler.
st.w r0, RESET_GUARD // Allow further resets to succeed
mov lp, r6 // Arg 0: return address
ld.b KM, r7 // Arg 1: kernel mode
mov sp, r9 // Arg 3: stack pointer
ld.w KSP, r19 // maybe switch to kernel stack
cmp r7, r0 // see if already in kernel mode
cmov z, r19, sp, sp // and switch to kernel stack if not
GET_CURRENT_TASK(r8) // Arg 2: task pointer
jr CSYM(unexpected_reset)
1: st.w r20, RESET_GUARD // Turn on reset guard
#endif /* CONFIG_RESET_GUARD */
// Setup a temporary stack for doing pre-initialization function calls.
//
// We can't use the initial kernel stack, because (1) it may be
// located in memory we're not allowed to touch, and (2) since
// it's in the data segment, calling memcpy to initialize that
// area from ROM will overwrite memcpy's return address.
mov hilo(CSYM(_init_stack_end) - 4), sp
// See if there's a platform-specific early-initialization routine
// defined; it's a weak symbol, so it will have an address of zero if
// there's not.
mov hilo(CSYM(mach_early_init)), r6
cmp r6, r0
bz 3f
// There is one, so call it. If this function is written in C, it
// should be very careful -- the stack pointer is valid, but very
// little else is (e.g., bss is not zeroed yet, and initialized data
// hasn't been).
jarl 2f, lp // first figure out return address
2: add 3f - ., lp
jmp [r6] // do call
3:
#ifdef CONFIG_ROM_KERNEL
// Copy the data area from ROM to RAM
mov hilo(CSYM(_rom_copy_dst_start)), r6
mov hilo(CSYM(_rom_copy_src_start)), r7
mov hilo(CSYM(_rom_copy_dst_end)), r8
sub r6, r8
jarl CSYM(memcpy), lp
#endif
// Load the initial thread's stack, and current task pointer (in r16)
mov hilo(CSYM(init_thread_union)), r19
movea THREAD_SIZE, r19, sp
ld.w TI_TASK[r19], CURRENT_TASK
#ifdef CONFIG_TIME_BOOTUP
/* This stuff must come after mach_early_init, because interrupts may
not work until after its been called. */
jarl CSYM(highres_timer_reset), lp
jarl CSYM(highres_timer_start), lp
#endif
// Kernel stack pointer save location
st.w sp, KSP
// Assert that we're in `kernel mode'
mov 1, r19
st.w r19, KM
#ifdef CONFIG_ZERO_BSS
// Zero bss area, since we can't rely upon any loader to do so
mov hilo(CSYM(_sbss)), r6
mov r0, r7
mov hilo(CSYM(_ebss)), r8
sub r6, r8
jarl CSYM(memset), lp
#endif
// Start Linux kernel.
mov hilo(CSYM(machine_halt)), lp
jr CSYM(start_kernel)
END(start)
/*
* arch/v850/kernel/highres_timer.c -- High resolution timing routines
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <asm/system.h>
#include <asm/nb85e_timer_d.h>
#include <asm/highres_timer.h>
#define HIGHRES_TIMER_USEC_SHIFT 12
/* Pre-calculated constant used for converting ticks to real time
units. We initialize it to prevent it being put into BSS. */
static u32 highres_timer_usec_prescale = 1;
void highres_timer_slow_tick_irq (void) __attribute__ ((noreturn));
void highres_timer_slow_tick_irq (void)
{
/* This is an interrupt handler, so it must be very careful to
not to trash any registers. At this point, the stack-pointer
(r3) has been saved in the chip ram location ENTRY_SP by the
interrupt vector, so we can use it as a scratch register; we
must also restore it before returning. */
asm ("ld.w %0[r0], sp;"
"add 1, sp;"
"st.w sp, %0[r0];"
"ld.w %1[r0], sp;" /* restore pre-irq stack-pointer */
"reti"
::
"i" (HIGHRES_TIMER_SLOW_TICKS_ADDR),
"i" (ENTRY_SP_ADDR)
: "memory");
}
void highres_timer_reset (void)
{
NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT) = 0;
HIGHRES_TIMER_SLOW_TICKS = 0;
}
void highres_timer_start (void)
{
u32 fast_tick_rate;
/* Start hardware timer. */
nb85e_timer_d_configure (HIGHRES_TIMER_TIMER_D_UNIT,
HIGHRES_TIMER_SLOW_TICK_RATE);
fast_tick_rate =
(NB85E_TIMER_D_BASE_FREQ
>> NB85E_TIMER_D_DIVLOG2 (HIGHRES_TIMER_TIMER_D_UNIT));
/* The obvious way of calculating microseconds from fast ticks
is to do:
usec = fast_ticks * 10^6 / fast_tick_rate
However, divisions are much slower than multiplications, and
the above calculation can overflow, so we do this instead:
usec = fast_ticks * (10^6 * 2^12 / fast_tick_rate) / 2^12
since we can pre-calculate (10^6 * (2^12 / fast_tick_rate))
and use a shift for dividing by 2^12, this avoids division,
and is almost as accurate (it differs by about 2 microseconds
at the extreme value of the fast-tick counter's ranger). */
highres_timer_usec_prescale = ((1000000 << HIGHRES_TIMER_USEC_SHIFT)
/ fast_tick_rate);
/* Enable the interrupt (which is hardwired to this use), and
give it the highest priority. */
NB85E_INTC_IC (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)) = 0;
}
void highres_timer_stop (void)
{
/* Stop the timer. */
NB85E_TIMER_D_TMCD (HIGHRES_TIMER_TIMER_D_UNIT) =
NB85E_TIMER_D_TMCD_CAE;
/* Disable its interrupt, just in case. */
nb85e_intc_disable_irq (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT));
}
inline void highres_timer_read_ticks (u32 *slow_ticks, u32 *fast_ticks)
{
int flags;
u32 fast_ticks_1, fast_ticks_2, _slow_ticks;
local_irq_save (flags);
fast_ticks_1 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT);
_slow_ticks = HIGHRES_TIMER_SLOW_TICKS;
fast_ticks_2 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT);
local_irq_restore (flags);
if (fast_ticks_2 < fast_ticks_1)
_slow_ticks++;
*slow_ticks = _slow_ticks;
*fast_ticks = fast_ticks_2;
}
inline void highres_timer_ticks_to_timeval (u32 slow_ticks, u32 fast_ticks,
struct timeval *tv)
{
unsigned long sec, sec_rem, usec;
usec = ((fast_ticks * highres_timer_usec_prescale)
>> HIGHRES_TIMER_USEC_SHIFT);
sec = slow_ticks / HIGHRES_TIMER_SLOW_TICK_RATE;
sec_rem = slow_ticks % HIGHRES_TIMER_SLOW_TICK_RATE;
usec += sec_rem * (1000000 / HIGHRES_TIMER_SLOW_TICK_RATE);
tv->tv_sec = sec;
tv->tv_usec = usec;
}
void highres_timer_read (struct timeval *tv)
{
u32 fast_ticks, slow_ticks;
highres_timer_read_ticks (&slow_ticks, &fast_ticks);
highres_timer_ticks_to_timeval (slow_ticks, fast_ticks, tv);
}
/*
* arch/v850/kernel/init_task.c -- Initial task/thread structures
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*/
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/init_task.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS (init_signals);
struct mm_struct init_mm = INIT_MM (init_mm);
/*
* Initial task structure.
*
* All other task structs will be allocated on slabs in fork.c
*/
struct task_struct init_task = INIT_TASK (init_task);
/*
* Initial thread structure.
*
* We need to make sure that this is 8192-byte aligned due to the
* way process stacks are handled. This is done by having a special
* "init_task" linker map entry.
*/
union thread_union init_thread_union
__attribute__((__section__(".data.init_task"))) =
{ INIT_THREAD_INFO(init_task) };
/*
* arch/v850/kernel/intv.S -- Interrupt vectors
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <asm/clinkage.h>
#include <asm/irq.h>
#include <asm/machdep.h>
#include <asm/entry.h>
#ifdef CONFIG_V850E_MA1_HIGHRES_TIMER
#include <asm/highres_timer.h>
#endif
/* Jump to an interrupt/trap handler. These handlers (defined in entry.S)
expect the stack-pointer to be saved in ENTRY_SP, so we use sp to do an
indirect jump (which avoids problems when the handler is more than a signed
22-bit offset away). */
#define JUMP_TO_HANDLER(name, sp_save_loc) \
st.w sp, sp_save_loc; \
mov hilo(name), sp; \
jmp [sp]
/* Reset vector. */
.section .intv.reset, "ax"
.org 0x0
mov hilo(C_SYMBOL_NAME(start)), r1;
jmp [r1]
/* Generic interrupt vectors. */
.section .intv.common, "ax"
.balign 0x10
JUMP_TO_HANDLER (nmi, NMI_ENTRY_SP) // NMI0
.balign 0x10
JUMP_TO_HANDLER (nmi, NMI_ENTRY_SP) // NMI1
.balign 0x10
JUMP_TO_HANDLER (nmi, NMI_ENTRY_SP) // NMI2
.balign 0x10
JUMP_TO_HANDLER (trap, ENTRY_SP) // TRAP0n
.balign 0x10
JUMP_TO_HANDLER (trap, ENTRY_SP) // TRAP1n
.balign 0x10
JUMP_TO_HANDLER (illegal_instruction, ENTRY_SP) // illegal insn trap
.balign 0x10
JUMP_TO_HANDLER (dbtrap, ENTRY_SP) // DBTRAP insn
/* Hardware interrupt vectors. */
.section .intv.mach, "ax"
.org 0x0
#if defined (CONFIG_V850E_MA1_HIGHRES_TIMER) && defined (IRQ_INTCMD)
/* Interrupts before the highres timer interrupt. */
.rept IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)
.balign 0x10
JUMP_TO_HANDLER (irq, ENTRY_SP)
.endr
/* The highres timer interrupt. */
.balign 0x10
JUMP_TO_HANDLER (C_SYMBOL_NAME (highres_timer_slow_tick_irq), ENTRY_SP)
/* Interrupts after the highres timer interrupt. */
.rept NUM_CPU_IRQS - IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT) - 1
.balign 0x10
JUMP_TO_HANDLER (irq, ENTRY_SP)
.endr
#else /* No highres timer */
.rept NUM_CPU_IRQS
.balign 0x10
JUMP_TO_HANDLER (irq, ENTRY_SP)
.endr
#endif /* Highres timer */
This diff is collapsed.
/*
* arch/v850/kernel/ma.c -- V850E/MA series of cpu chips
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
#include <linux/irq.h>
#include <asm/atomic.h>
#include <asm/page.h>
#include <asm/machdep.h>
#include <asm/nb85e_timer_d.h>
#include "mach.h"
void __init mach_sched_init (struct irqaction *timer_action)
{
/* Start hardware timer. */
nb85e_timer_d_configure (0, HZ);
/* Install timer interrupt handler. */
setup_irq (IRQ_INTCMD(0), timer_action);
}
static struct nb85e_intc_irq_init irq_inits[] = {
{ "IRQ", 0, NUM_MACH_IRQS, 1, 7 },
{ "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 },
{ "DMA", IRQ_INTDMA(0), IRQ_INTDMA_NUM, 1, 2 },
{ "CSI", IRQ_INTCSI(0), IRQ_INTCSI_NUM, 4, 4 },
{ "SER", IRQ_INTSER(0), IRQ_INTSER_NUM, 4, 3 },
{ "SR", IRQ_INTSR(0), IRQ_INTSR_NUM, 4, 4 },
{ "ST", IRQ_INTST(0), IRQ_INTST_NUM, 4, 5 },
{ 0 }
};
#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
/* Initialize MA chip interrupts. */
void __init ma_init_irqs (void)
{
nb85e_intc_init_irq_types (irq_inits, hw_itypes);
}
/* Called before configuring an on-chip UART. */
void ma_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud)
{
/* We only know about the first two UART channels (though
specific chips may have more). */
if (chan < 2) {
unsigned bits = 0x3 << (chan * 3);
/* Specify that the relevent pins on the chip should do
serial I/O, not direct I/O. */
MA_PORT4_PMC |= bits;
/* Specify that we're using the UART, not the CSI device. */
MA_PORT4_PFC |= bits;
}
}
/*
* arch/v850/kernel/mach.c -- Defaults for some things defined by "mach.h"
*
* Copyright (C) 2001 NEC Corporation
* Copyright (C) 2001 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include "mach.h"
/* Called with each timer tick, if non-zero. */
void (*mach_tick)(void) = 0;
/*
* arch/v850/kernel/mach.h -- Machine-dependent functions used by v850 port
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#ifndef __V850_MACH_H__
#define __V850_MACH_H__
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <asm/ptrace.h>
#include <asm/entry.h>
#include <asm/clinkage.h>
void mach_setup (char **cmdline);
void mach_gettimeofday (struct timespec *tv);
void mach_sched_init (struct irqaction *timer_action);
void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len);
void mach_init_irqs (void);
/* If defined, is called very early in the kernel initialization. The
stack pointer is valid, but very little has been initialized (e.g.,
bss is not zeroed yet) when this is called, so care must taken. */
void mach_early_init (void);
/* If defined, called after the bootmem allocator has been initialized,
to allow the platform-dependent code to reserve any areas of RAM that
the kernel shouldn't touch. */
void mach_reserve_bootmem (void) __attribute__ ((__weak__));
/* Called with each timer tick, if non-zero. */
extern void (*mach_tick) (void);
/* The following establishes aliases for various mach_ functions to the
name by which the rest of the kernal calls them. These statements
should only have an effect in the file that defines the actual functions. */
#define MACH_ALIAS(to, from) \
asm (".global " macrology_stringify (C_SYMBOL_NAME (to)) ";" \
macrology_stringify (C_SYMBOL_NAME (to)) \
" = " macrology_stringify (C_SYMBOL_NAME (from)))
/* e.g.: MACH_ALIAS (kernel_name, arch_spec_name); */
#endif /* __V850_MACH_H__ */
/*
* arch/v850/kernel/memcons.c -- Console I/O to a memory buffer
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/init.h>
/* If this device is enabled, the linker map should define start and
end points for its buffer. */
extern char memcons_output[], memcons_output_end;
/* Current offset into the buffer. */
static unsigned long memcons_offs = 0;
/* Spinlock protecting memcons_offs. */
static spinlock_t memcons_lock = SPIN_LOCK_UNLOCKED;
static size_t write (const char *buf, size_t len)
{
int flags;
char *point;
spin_lock_irqsave (memcons_lock, flags);
point = memcons_output + memcons_offs;
if (point + len >= &memcons_output_end) {
len = &memcons_output_end - point;
memcons_offs = 0;
} else
memcons_offs += len;
spin_unlock_irqrestore (memcons_lock, flags);
memcpy (point, buf, len);
return len;
}
/* Low-level console. */
static void memcons_write (struct console *co, const char *buf, unsigned len)
{
while (len > 0)
len -= write (buf, len);
}
static kdev_t memcons_device (struct console *co)
{
return MKDEV (TTY_MAJOR, 64 + co->index);
}
static struct console memcons =
{
name: "memcons",
write: memcons_write,
device: memcons_device,
flags: CON_PRINTBUFFER,
index: -1,
};
void memcons_setup (void)
{
register_console (&memcons);
printk (KERN_INFO "Console: static memory buffer (memcons)\n");
}
/* Higher level TTY interface. */
static struct tty_struct *tty_table[1] = { 0 };
static struct termios *tty_termios[1] = { 0 };
static struct termios *tty_termios_locked[1] = { 0 };
static struct tty_driver tty_driver = { 0 };
static int tty_ref_count = 0;
int memcons_tty_open (struct tty_struct *tty, struct file *filp)
{
return 0;
}
int memcons_tty_write (struct tty_struct *tty, int from_user,
const unsigned char *buf, int len)
{
return write (buf, len);
}
int memcons_tty_write_room (struct tty_struct *tty)
{
return &memcons_output_end - (memcons_output + memcons_offs);
}
int memcons_tty_chars_in_buffer (struct tty_struct *tty)
{
/* We have no buffer. */
return 0;
}
int __init memcons_tty_init (void)
{
tty_driver.name = "memcons";
tty_driver.major = TTY_MAJOR;
tty_driver.minor_start = 64;
tty_driver.num = 1;
tty_driver.type = TTY_DRIVER_TYPE_SYSCONS;
tty_driver.refcount = &tty_ref_count;
tty_driver.table = tty_table;
tty_driver.termios = tty_termios;
tty_driver.termios_locked = tty_termios_locked;
tty_driver.init_termios = tty_std_termios;
tty_driver.open = memcons_tty_open;
tty_driver.write = memcons_tty_write;
tty_driver.write_room = memcons_tty_write_room;
tty_driver.chars_in_buffer = memcons_tty_chars_in_buffer;
tty_register_driver (&tty_driver);
}
__initcall (memcons_tty_init);
/*
* arch/v850/kernel/nb85e_intc.c -- NB85E cpu core interrupt controller (INTC)
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/nb85e_intc.h>
static void irq_nop (unsigned irq) { }
static unsigned nb85e_intc_irq_startup (unsigned irq)
{
nb85e_intc_clear_pending_irq (irq);
nb85e_intc_enable_irq (irq);
return 0;
}
/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
INITS (which is terminated by an entry with the name field == 0). */
void __init nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits,
struct hw_interrupt_type *hw_irq_types)
{
struct nb85e_intc_irq_init *init;
for (init = inits; init->name; init++) {
int i;
struct hw_interrupt_type *hwit = hw_irq_types++;
hwit->typename = init->name;
hwit->startup = nb85e_intc_irq_startup;
hwit->shutdown = nb85e_intc_disable_irq;
hwit->enable = nb85e_intc_enable_irq;
hwit->disable = nb85e_intc_disable_irq;
hwit->ack = irq_nop;
hwit->end = irq_nop;
/* Initialize kernel IRQ infrastructure for this interrupt. */
init_irq_handlers(init->base, init->num, init->interval, hwit);
/* Set the interrupt priorities. */
for (i = 0; i < init->num; i++) {
unsigned irq = init->base + i * init->interval;
/* If the interrupt is currently enabled (all
interrupts are initially disabled), then
assume whoever enabled it has set things up
properly, and avoid messing with it. */
if (! nb85e_intc_irq_enabled (irq))
/* This write also (1) disables the
interrupt, and (2) clears any pending
interrupts. */
NB85E_INTC_IC (irq)
= (NB85E_INTC_IC_PR (init->priority)
| NB85E_INTC_IC_MK);
}
}
}
/*
* include/asm-v850/nb85e_timer_d.c -- `Timer D' component often used
* with the NB85E cpu core
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/kernel.h>
#include <asm/nb85e_utils.h>
#include <asm/nb85e_timer_d.h>
/* Start interval timer TIMER (0-3). The timer will issue the
corresponding INTCMD interrupt RATE times per second.
This function does not enable the interrupt. */
void nb85e_timer_d_configure (unsigned timer, unsigned rate)
{
unsigned divlog2, count;
/* Calculate params for timer. */
if (! calc_counter_params (
NB85E_TIMER_D_BASE_FREQ, rate,
NB85E_TIMER_D_TMCD_CS_MIN, NB85E_TIMER_D_TMCD_CS_MAX, 16,
&divlog2, &count))
printk (KERN_WARNING
"Cannot find interval timer %d setting suitable"
" for rate of %dHz.\n"
"Using rate of %dHz instead.\n",
timer, rate,
(NB85E_TIMER_D_BASE_FREQ >> divlog2) >> 16);
/* Do the actual hardware timer initialization: */
/* Enable timer. */
NB85E_TIMER_D_TMCD(timer) = NB85E_TIMER_D_TMCD_CAE;
/* Set clock divider. */
NB85E_TIMER_D_TMCD(timer)
= NB85E_TIMER_D_TMCD_CAE
| NB85E_TIMER_D_TMCD_CS(divlog2);
/* Set timer compare register. */
NB85E_TIMER_D_CMD(timer) = count;
/* Start counting. */
NB85E_TIMER_D_TMCD(timer)
= NB85E_TIMER_D_TMCD_CAE
| NB85E_TIMER_D_TMCD_CS(divlog2)
| NB85E_TIMER_D_TMCD_CE;
}
/*
* include/asm-v850/nb85e_utils.h -- Utility functions associated with
* the NB85E cpu core
*
* Copyright (C) 2001 NEC Corporation
* Copyright (C) 2001 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
/* Note: these functions are often associated with the N85E cpu core,
but not always, which is why they're not in `nb85e.c'. */
#include <asm/nb85e_utils.h>
/* Calculate counter clock-divider and count values to attain the
desired frequency RATE from the base frequency BASE_FREQ. The
counter is expected to have a clock-divider, which can divide the
system cpu clock by a power of two value from MIN_DIVLOG2 to
MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter
counts up and resets whenever it's equal to the compare register,
generating an interrupt or whatever when it does so). The returned
values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT
-- the counter compare value to use. Returns true if it was possible
to find a reasonable value, otherwise false (and the other return
values will be set to be as good as possible). */
int calc_counter_params (unsigned long base_freq,
unsigned long rate,
unsigned min_divlog2, unsigned max_divlog2,
unsigned counter_size,
unsigned *divlog2, unsigned *count)
{
unsigned _divlog2;
int ok = 0;
/* Find the lowest clock divider setting that can represent RATE. */
for (_divlog2 = min_divlog2; _divlog2 <= max_divlog2; _divlog2++) {
/* Minimum interrupt rate possible using this divider. */
int min_int_rate
= (base_freq >> _divlog2) >> counter_size;
if (min_int_rate <= rate) {
/* This setting is the highest resolution
setting that's slow enough enough to attain
RATE interrupts per second, so use it. */
ok = 1;
break;
}
}
if (_divlog2 > max_divlog2)
/* Can't find correct setting. */
_divlog2 = max_divlog2;
if (divlog2)
*divlog2 = _divlog2;
if (count)
*count = ((base_freq >> _divlog2) + rate/2) / rate;
return ok;
}
/*
* arch/v850/kernel/process.c -- Arch-dependent process handling
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/setup.h>
#include <asm/pgtable.h>
extern void ret_from_fork (void);
/* The idle loop. */
void default_idle (void)
{
while (1) {
while (! need_resched ())
asm ("halt; nop; nop; nop; nop; nop" ::: "cc");
schedule ();
}
}
void (*idle)(void) = default_idle;
/*
* The idle thread. There's no useful work to be
* done, so just try to conserve power and have a
* low exit latency (ie sit in a loop waiting for
* somebody to say that they'd like to reschedule)
*/
void cpu_idle (void)
{
/* endless idle loop with no priority at all */
(*idle) ();
}
struct spec_reg_name {
const char *name;
int gpr;
};
struct spec_reg_name spec_reg_names[] = {
{ "sp", GPR_SP },
{ "gp", GPR_GP },
{ "tp", GPR_TP },
{ "ep", GPR_EP },
{ "lp", GPR_LP },
{ 0, 0 }
};
void show_regs (struct pt_regs *regs)
{
int gpr_base, gpr_offs;
printk (" pc 0x%08lx psw 0x%08lx kernel_mode %d\n",
regs->pc, regs->psw, regs->kernel_mode);
printk (" ctpc 0x%08lx ctpsw 0x%08lx ctbp 0x%08lx\n",
regs->ctpc, regs->ctpsw, regs->ctbp);
for (gpr_base = 0; gpr_base < NUM_GPRS; gpr_base += 4) {
for (gpr_offs = 0; gpr_offs < 4; gpr_offs++) {
int gpr = gpr_base + gpr_offs;
long val = regs->gpr[gpr];
struct spec_reg_name *srn;
for (srn = spec_reg_names; srn->name; srn++)
if (srn->gpr == gpr)
break;
if (srn->name)
printk ("%7s 0x%08lx", srn->name, val);
else
printk (" r%02d 0x%08lx", gpr, val);
}
printk ("\n");
}
}
/*
* This is the mechanism for creating a new kernel thread.
*
* NOTE! Only a kernel-only process (ie the swapper or direct descendants who
* haven't done an "execve()") should use this: it will work within a system
* call from a "real" process, but the process memory space will not be free'd
* until both the parent and the child have exited.
*/
int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
{
register mm_segment_t fs = get_fs ();
register unsigned long syscall asm (SYSCALL_NUM);
register unsigned long arg0 asm (SYSCALL_ARG0);
register unsigned long ret asm (SYSCALL_RET);
set_fs (KERNEL_DS);
/* Clone this thread. */
arg0 = flags | CLONE_VM;
syscall = __NR_clone;
asm volatile ("trap " SYSCALL_SHORT_TRAP
: "=r" (ret), "=r" (syscall)
: "1" (syscall), "r" (arg0)
: SYSCALL_SHORT_CLOBBERS);
if (ret == 0) {
/* In child thread, call FN and exit. */
arg0 = (*fn) (arg);
syscall = __NR_exit;
asm volatile ("trap " SYSCALL_SHORT_TRAP
: "=r" (ret), "=r" (syscall)
: "1" (syscall), "r" (arg0)
: SYSCALL_SHORT_CLOBBERS);
}
/* In parent. */
set_fs (fs);
return ret;
}
void flush_thread (void)
{
set_fs (USER_DS);
}
int copy_thread (int nr, unsigned long clone_flags,
unsigned long stack_start, unsigned long stack_size,
struct task_struct *p, struct pt_regs *regs)
{
/* Start pushing stuff from the top of the child's kernel stack. */
unsigned long ksp = (unsigned long)p->thread_info + THREAD_SIZE;
/* We push two `state save' stack fames (see entry.S) on the new
kernel stack:
1) The innermost one is what switch_thread would have
pushed, and is used when we context switch to the child
thread for the first time. It's set up to return to
ret_from_fork in entry.S.
2) The outermost one (nearest the top) is what a syscall
trap would have pushed, and is set up to return to the
same location as the parent thread, but with a return
value of 0. */
struct pt_regs *child_switch_regs, *child_trap_regs;
/* Trap frame. */
ksp -= STATE_SAVE_SIZE;
child_trap_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET);
/* Switch frame. */
ksp -= STATE_SAVE_SIZE;
child_switch_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET);
/* First copy parent's register state to child. */
*child_switch_regs = *regs;
*child_trap_regs = *regs;
/* switch_thread returns to the restored value of the lp
register (r31), so we make that the place where we want to
jump when the child thread begins running. */
child_switch_regs->gpr[GPR_LP] = (v850_reg_t)ret_from_fork;
/* Thread state for the child (everything else is on the stack). */
p->thread.ksp = ksp;
return 0;
}
/*
* fill in the user structure for a core dump..
*/
void dump_thread (struct pt_regs *regs, struct user *dump)
{
#if 0 /* Later. XXX */
dump->magic = CMAGIC;
dump->start_code = 0;
dump->start_stack = regs->gpr[GPR_SP];
dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
dump->u_dsize = ((unsigned long) (current->mm->brk +
(PAGE_SIZE-1))) >> PAGE_SHIFT;
dump->u_dsize -= dump->u_tsize;
dump->u_ssize = 0;
if (dump->start_stack < TASK_SIZE)
dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
dump->regs = *regs;
dump->u_fpvalid = 0;
#endif
}
/*
* sys_execve() executes a new program.
*/
int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs)
{
char *filename = getname (name);
int error = PTR_ERR (filename);
if (! IS_ERR (filename)) {
error = do_execve (filename, argv, envp, regs);
putname (filename);
}
return error;
}
/* This is the common part of the various fork-like system calls (which
are in entry.S). */
int fork_common (int flags, unsigned long new_sp, struct pt_regs *regs)
{
struct task_struct *p = do_fork (flags, new_sp, regs, 0, 0);
return IS_ERR (p) ? PTR_ERR (p) : p->pid;
}
/*
* These bracket the sleeping functions..
*/
extern void scheduling_functions_start_here (void);
extern void scheduling_functions_end_here (void);
#define first_sched ((unsigned long) scheduling_functions_start_here)
#define last_sched ((unsigned long) scheduling_functions_end_here)
unsigned long get_wchan (struct task_struct *p)
{
#if 0 /* Barf. Figure out the stack-layout later. XXX */
unsigned long fp, pc;
int count = 0;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
pc = thread_saved_pc (&p->thread);
/* This quite disgusting function walks up the stack, following
saved return address, until it something that's out of bounds
(as defined by `first_sched' and `last_sched'). It then
returns the last PC that was in-bounds. */
do {
if (fp < stack_page + sizeof (struct task_struct) ||
fp >= 8184+stack_page)
return 0;
pc = ((unsigned long *)fp)[1];
/* FIXME: This depends on the order of these functions. */
if (pc < first_sched || pc >= last_sched)
return pc;
fp = *(unsigned long *) fp;
} while (count++ < 16);
#endif
return 0;
}
void show_trace_task (struct task_struct *t)
{
/* blarg XXX */
printk ("show_trace_task: KSP = 0x%lx, USP = 0x%lx, UPC = 0x%lx\n",
t->thread.ksp, KSTK_ESP (t), KSTK_EIP (t));
}
/*
* arch/v850/kernel/procfs.c -- Introspection functions for /proc filesystem
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include "mach.h"
static int cpuinfo_print (struct seq_file *m, void *v)
{
extern unsigned long loops_per_jiffy;
seq_printf (m, "CPU-Family: v850\nCPU-Arch: %s\n", CPU_ARCH);
#ifdef CPU_MODEL_LONG
seq_printf (m, "CPU-Model: %s (%s)\n", CPU_MODEL, CPU_MODEL_LONG);
#else
seq_printf (m, "CPU-Model: %s\n", CPU_MODEL);
#endif
#ifdef CPU_CLOCK_FREQ
seq_printf (m, "CPU-Clock: %ld (%ld MHz)\n",
(long)CPU_CLOCK_FREQ,
(long)CPU_CLOCK_FREQ / 1000000);
#endif
seq_printf (m, "BogoMips: %lu.%02lu\n",
loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ)) % 100);
#ifdef PLATFORM_LONG
seq_printf (m, "Platform: %s (%s)\n", PLATFORM, PLATFORM_LONG);
#elif defined (PLATFORM)
seq_printf (m, "Platform: %s\n", PLATFORM);
#endif
return 0;
}
static void *cpuinfo_start (struct seq_file *m, loff_t *pos)
{
return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL;
}
static void *cpuinfo_next (struct seq_file *m, void *v, loff_t *pos)
{
++*pos;
return cpuinfo_start (m, pos);
}
static void cpuinfo_stop (struct seq_file *m, void *v)
{
}
struct seq_operations cpuinfo_op = {
start: cpuinfo_start,
next: cpuinfo_next,
stop: cpuinfo_stop,
show: cpuinfo_print
};
/*
* arch/v850/kernel/ptrace.c -- `ptrace' system call
*
* Copyright (C) 2002 NEC Corporation
* Copyright (C) 2002 Miles Bader <miles@gnu.org>
*
* Derived from arch/mips/kernel/ptrace.c:
*
* Copyright (C) 1992 Ross Biro
* Copyright (C) Linus Torvalds
* Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
* Copyright (C) 1996 David S. Miller
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999 MIPS Technologies, Inc.
*
* 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 for more details.
*/
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/ptrace.h>
#include <asm/errno.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
int rval;
lock_kernel();
#if 0
printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
(int) request, (int) pid, (unsigned long) addr,
(unsigned long) data);
#endif
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
if (current->ptrace & PT_PTRACED) {
rval = -EPERM;
goto out;
}
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
rval = 0;
goto out;
}
rval = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out;
rval = -EPERM;
if (pid == 1) /* you may not mess with init */
goto out;
if (request == PTRACE_ATTACH) {
rval = ptrace_attach(child);
goto out_tsk;
}
rval = -ESRCH;
if (!(child->ptrace & PT_PTRACED))
goto out_tsk;
if (child->state != TASK_STOPPED) {
if (request != PTRACE_KILL)
goto out_tsk;
}
if (child->parent != current)
goto out_tsk;
switch (request) {
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA:{
unsigned long tmp;
int copied;
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
rval = -EIO;
if (copied != sizeof(tmp))
break;
rval = put_user(tmp,(unsigned long *) data);
goto out;
}
/* Read the word at location addr in the USER area. */
case PTRACE_PEEKUSR:
if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
struct pt_regs *regs = task_regs (child);
unsigned long val =
*(unsigned long *)((char *)regs + addr);
rval = put_user (val, (unsigned long *)data);
} else {
rval = 0;
rval = -EIO;
}
goto out;
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
rval = 0;
if (access_process_vm(child, addr, &data, sizeof(data), 1)
== sizeof(data))
break;
rval = -EIO;
goto out;
case PTRACE_POKEUSR:
if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
struct pt_regs *regs = task_regs (child);
unsigned long *loc =
(unsigned long *)((char *)regs + addr);
*loc = data;
} else {
rval = 0;
rval = -EIO;
}
goto out;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: /* rvaltart after signal. */
rval = -EIO;
if ((unsigned long) data > _NSIG)
break;
if (request == PTRACE_SYSCALL)
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
wake_up_process(child);
rval = 0;
break;
/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL:
rval = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
break;
case PTRACE_DETACH: /* detach a process that was attached. */
rval = ptrace_detach(child, data);
break;
default:
rval = -EIO;
goto out;
}
out_tsk:
put_task_struct(child);
out:
unlock_kernel();
return rval;
}
asmlinkage void syscall_trace(void)
{
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return;
if (!(current->ptrace & PT_PTRACED))
return;
/* The 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0);
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
* for normal use. strace only continues with a signal if the
* stopping signal is not SIGTRAP. -brl
*/
if (current->exit_code) {
send_sig(current->exit_code, current, 1);
current->exit_code = 0;
}
}
void ptrace_disable (struct task_struct *child)
{
/* nothing to do */
}
This diff is collapsed.
This diff is collapsed.
/*
* include/asm-v850/rte_multi.c -- Support for Multi debugger monitor ROM
* on Midas lab RTE-CB series of evaluation boards
*
* Copyright (C) 2001,02 NEC Corporation
* Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
*
* 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 for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
#include <linux/init.h>
#include <asm/machdep.h>
/* A table of which interrupt vectors to install, since blindly
installing all of them makes the debugger stop working. This is a
list of offsets in the interrupt vector area; each entry means to
copy that particular 16-byte vector. An entry less than zero ends
the table. */
static long multi_intv_install_table[] = {
0x40, 0x50, /* trap vectors */
/* Note -- illegal insn trap is used by the debugger. */
0xD0, 0xE0, 0xF0, /* GINT1 - GINT3 */
0x240, 0x250, 0x260, 0x270, /* timer D interrupts */
0x2D0, 0x2E0, 0x2F0, /* UART channel 0 */
0x310, 0x320, 0x330, /* UART channel 1 */
0x350, 0x360, 0x370, /* UART channel 2 */
-1
};
/* Early initialization for kernel using Multi debugger ROM monitor. */
void __init multi_init (void)
{
/* We're using the Multi debugger monitor, so we have to install
the interrupt vectors. The monitor doesn't allow them to be
initially downloaded into their final destination because
it's in the monitor's scratch-RAM area. Unfortunately, Multi
also doesn't deal correctly with ELF sections where the LMA
and VMA differ -- it just ignores the LMA -- so we can't use
that feature to work around the problem. What we do instead
is just put the interrupt vectors into a normal section, and
do the necessary copying and relocation here. Since the
interrupt vector basically only contains `jr' instructions
and no-ops, it's not that hard. */
extern unsigned long _intv_load_start, _intv_start;
register unsigned long *src = &_intv_load_start;
register unsigned long *dst = (unsigned long *)INTV_BASE;
register unsigned long jr_fixup = (char *)&_intv_start - (char *)dst;
register long *ii;
/* Copy interupt vectors as instructed by multi_intv_install_table. */
for (ii = multi_intv_install_table; *ii >= 0; ii++) {
/* Copy 16-byte interrupt vector at offset *ii. */
int boffs;
for (boffs = 0; boffs < 0x10; boffs += sizeof *src) {
/* Copy a single word, fixing up the jump offs
if it's a `jr' instruction. */
int woffs = (*ii + boffs) / sizeof *src;
unsigned long word = src[woffs];
if ((word & 0xFC0) == 0x780) {
/* A `jr' insn, fix up its offset (and yes, the
wierd half-word swapping is intentional). */
unsigned short hi = word & 0xFFFF;
unsigned short lo = word >> 16;
unsigned long udisp22
= lo + ((hi & 0x3F) << 16);
long disp22 = (long)(udisp22 << 10) >> 10;
disp22 += jr_fixup;
hi = ((disp22 >> 16) & 0x3F) | 0x780;
lo = disp22 & 0xFFFF;
word = hi + (lo << 16);
}
dst[woffs] = word;
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#
# arch/v850/lib/Makefile
#
L_TARGET = lib.a
obj-y = ashrdi3.o ashldi3.o lshrdi3.o muldi3.o negdi2.o \
checksum.o memcpy.o memset.o
include $(TOPDIR)/Rules.make
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* include/asm-v850e/bugs.h
*
* Copyright (C) 1994 Linus Torvalds
*/
/*
* This is included by init/main.c to check for architecture-dependent bugs.
*
* Needs:
* void check_bugs(void);
*/
static void check_bugs(void)
{
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment