add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
#
# Makefile
#
extra-y := head.o vmlinux.lds
obj-y += exceptions.o \
hw_exception_handler.o init_task.o intc.o irq.o of_device.o \
of_platform.o process.o prom.o prom_parse.o ptrace.o \
setup.o signal.o sys_microblaze.o timer.o traps.o
obj-y += cpu/
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_SELFMOD) += selfmod.o
obj-$(CONFIG_HEART_BEAT) += heartbeat.o
obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o
obj-$(CONFIG_MMU) += misc.o
obj-y += entry$(MMU).o

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/init.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/ptrace.h>
#include <linux/hardirq.h>
#include <linux/thread_info.h>
#include <linux/kbuild.h>
int main(int argc, char *argv[])
{
/* struct pt_regs */
DEFINE(PT_SIZE, sizeof(struct pt_regs));
DEFINE(PT_MSR, offsetof(struct pt_regs, msr));
DEFINE(PT_EAR, offsetof(struct pt_regs, ear));
DEFINE(PT_ESR, offsetof(struct pt_regs, esr));
DEFINE(PT_FSR, offsetof(struct pt_regs, fsr));
DEFINE(PT_PC, offsetof(struct pt_regs, pc));
DEFINE(PT_R0, offsetof(struct pt_regs, r0));
DEFINE(PT_R1, offsetof(struct pt_regs, r1));
DEFINE(PT_R2, offsetof(struct pt_regs, r2));
DEFINE(PT_R3, offsetof(struct pt_regs, r3));
DEFINE(PT_R4, offsetof(struct pt_regs, r4));
DEFINE(PT_R5, offsetof(struct pt_regs, r5));
DEFINE(PT_R6, offsetof(struct pt_regs, r6));
DEFINE(PT_R7, offsetof(struct pt_regs, r7));
DEFINE(PT_R8, offsetof(struct pt_regs, r8));
DEFINE(PT_R9, offsetof(struct pt_regs, r9));
DEFINE(PT_R10, offsetof(struct pt_regs, r10));
DEFINE(PT_R11, offsetof(struct pt_regs, r11));
DEFINE(PT_R12, offsetof(struct pt_regs, r12));
DEFINE(PT_R13, offsetof(struct pt_regs, r13));
DEFINE(PT_R14, offsetof(struct pt_regs, r14));
DEFINE(PT_R15, offsetof(struct pt_regs, r15));
DEFINE(PT_R16, offsetof(struct pt_regs, r16));
DEFINE(PT_R17, offsetof(struct pt_regs, r17));
DEFINE(PT_R18, offsetof(struct pt_regs, r18));
DEFINE(PT_R19, offsetof(struct pt_regs, r19));
DEFINE(PT_R20, offsetof(struct pt_regs, r20));
DEFINE(PT_R21, offsetof(struct pt_regs, r21));
DEFINE(PT_R22, offsetof(struct pt_regs, r22));
DEFINE(PT_R23, offsetof(struct pt_regs, r23));
DEFINE(PT_R24, offsetof(struct pt_regs, r24));
DEFINE(PT_R25, offsetof(struct pt_regs, r25));
DEFINE(PT_R26, offsetof(struct pt_regs, r26));
DEFINE(PT_R27, offsetof(struct pt_regs, r27));
DEFINE(PT_R28, offsetof(struct pt_regs, r28));
DEFINE(PT_R29, offsetof(struct pt_regs, r29));
DEFINE(PT_R30, offsetof(struct pt_regs, r30));
DEFINE(PT_R31, offsetof(struct pt_regs, r31));
DEFINE(PT_MODE, offsetof(struct pt_regs, pt_mode));
BLANK();
/* Magic offsets for PTRACE PEEK/POKE etc */
DEFINE(PT_TEXT_ADDR, sizeof(struct pt_regs) + 1);
DEFINE(PT_TEXT_LEN, sizeof(struct pt_regs) + 2);
DEFINE(PT_DATA_ADDR, sizeof(struct pt_regs) + 3);
BLANK();
/* struct task_struct */
DEFINE(TS_THREAD_INFO, offsetof(struct task_struct, stack));
#ifdef CONFIG_MMU
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_MM, offsetof(struct task_struct, mm));
DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
DEFINE(TASK_PID, offsetof(struct task_struct, pid));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
BLANK();
DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
BLANK();
#endif
/* struct thread_info */
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
DEFINE(TI_CPU_CONTEXT, offsetof(struct thread_info, cpu_context));
BLANK();
/* struct cpu_context */
DEFINE(CC_R1, offsetof(struct cpu_context, r1)); /* r1 */
DEFINE(CC_R2, offsetof(struct cpu_context, r2));
/* dedicated registers */
DEFINE(CC_R13, offsetof(struct cpu_context, r13));
DEFINE(CC_R14, offsetof(struct cpu_context, r14));
DEFINE(CC_R15, offsetof(struct cpu_context, r15));
DEFINE(CC_R16, offsetof(struct cpu_context, r16));
DEFINE(CC_R17, offsetof(struct cpu_context, r17));
DEFINE(CC_R18, offsetof(struct cpu_context, r18));
/* non-volatile registers */
DEFINE(CC_R19, offsetof(struct cpu_context, r19));
DEFINE(CC_R20, offsetof(struct cpu_context, r20));
DEFINE(CC_R21, offsetof(struct cpu_context, r21));
DEFINE(CC_R22, offsetof(struct cpu_context, r22));
DEFINE(CC_R23, offsetof(struct cpu_context, r23));
DEFINE(CC_R24, offsetof(struct cpu_context, r24));
DEFINE(CC_R25, offsetof(struct cpu_context, r25));
DEFINE(CC_R26, offsetof(struct cpu_context, r26));
DEFINE(CC_R27, offsetof(struct cpu_context, r27));
DEFINE(CC_R28, offsetof(struct cpu_context, r28));
DEFINE(CC_R29, offsetof(struct cpu_context, r29));
DEFINE(CC_R30, offsetof(struct cpu_context, r30));
/* special purpose registers */
DEFINE(CC_MSR, offsetof(struct cpu_context, msr));
DEFINE(CC_EAR, offsetof(struct cpu_context, ear));
DEFINE(CC_ESR, offsetof(struct cpu_context, esr));
DEFINE(CC_FSR, offsetof(struct cpu_context, fsr));
BLANK();
return 0;
}

View File

@@ -0,0 +1,8 @@
#
# Build the appropriate CPU version support
#
EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \
-DCPU_REV=$(CPU_REV)
obj-y += cache.o cpuinfo.o cpuinfo-pvr-full.o cpuinfo-static.o mb.o pvr.o

View File

@@ -0,0 +1,255 @@
/*
* Cache control for MicroBlaze cache memories
*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2007 John Williams <john.williams@petalogix.com>
*
* 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 <asm/cacheflush.h>
#include <linux/cache.h>
#include <asm/cpuinfo.h>
/* Exported functions */
void _enable_icache(void)
{
if (cpuinfo.use_icache) {
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
__asm__ __volatile__ (" \
msrset r0, %0; \
nop; " \
: \
: "i" (MSR_ICE) \
: "memory");
#else
__asm__ __volatile__ (" \
mfs r12, rmsr; \
nop; \
ori r12, r12, %0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_ICE) \
: "memory", "r12");
#endif
}
}
void _disable_icache(void)
{
if (cpuinfo.use_icache) {
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
__asm__ __volatile__ (" \
msrclr r0, %0; \
nop; " \
: \
: "i" (MSR_ICE) \
: "memory");
#else
__asm__ __volatile__ (" \
mfs r12, rmsr; \
nop; \
andi r12, r12, ~%0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_ICE) \
: "memory", "r12");
#endif
}
}
void _invalidate_icache(unsigned int addr)
{
if (cpuinfo.use_icache) {
__asm__ __volatile__ (" \
wic %0, r0" \
: \
: "r" (addr));
}
}
void _enable_dcache(void)
{
if (cpuinfo.use_dcache) {
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
__asm__ __volatile__ (" \
msrset r0, %0; \
nop; " \
: \
: "i" (MSR_DCE) \
: "memory");
#else
__asm__ __volatile__ (" \
mfs r12, rmsr; \
nop; \
ori r12, r12, %0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_DCE) \
: "memory", "r12");
#endif
}
}
void _disable_dcache(void)
{
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
__asm__ __volatile__ (" \
msrclr r0, %0; \
nop; " \
: \
: "i" (MSR_DCE) \
: "memory");
#else
__asm__ __volatile__ (" \
mfs r12, rmsr; \
nop; \
andi r12, r12, ~%0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_DCE) \
: "memory", "r12");
#endif
}
void _invalidate_dcache(unsigned int addr)
{
__asm__ __volatile__ (" \
wdc %0, r0" \
: \
: "r" (addr));
}
void __invalidate_icache_all(void)
{
unsigned int i;
unsigned flags;
if (cpuinfo.use_icache) {
local_irq_save(flags);
__disable_icache();
/* Just loop through cache size and invalidate, no need to add
CACHE_BASE address */
for (i = 0; i < cpuinfo.icache_size;
i += cpuinfo.icache_line)
__invalidate_icache(i);
__enable_icache();
local_irq_restore(flags);
}
}
void __invalidate_icache_range(unsigned long start, unsigned long end)
{
unsigned int i;
unsigned flags;
unsigned int align;
if (cpuinfo.use_icache) {
/*
* No need to cover entire cache range,
* just cover cache footprint
*/
end = min(start + cpuinfo.icache_size, end);
align = ~(cpuinfo.icache_line - 1);
start &= align; /* Make sure we are aligned */
/* Push end up to the next cache line */
end = ((end & align) + cpuinfo.icache_line);
local_irq_save(flags);
__disable_icache();
for (i = start; i < end; i += cpuinfo.icache_line)
__invalidate_icache(i);
__enable_icache();
local_irq_restore(flags);
}
}
void __invalidate_icache_page(struct vm_area_struct *vma, struct page *page)
{
__invalidate_icache_all();
}
void __invalidate_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long adr,
int len)
{
__invalidate_icache_all();
}
void __invalidate_cache_sigtramp(unsigned long addr)
{
__invalidate_icache_range(addr, addr + 8);
}
void __invalidate_dcache_all(void)
{
unsigned int i;
unsigned flags;
if (cpuinfo.use_dcache) {
local_irq_save(flags);
__disable_dcache();
/*
* Just loop through cache size and invalidate,
* no need to add CACHE_BASE address
*/
for (i = 0; i < cpuinfo.dcache_size;
i += cpuinfo.dcache_line)
__invalidate_dcache(i);
__enable_dcache();
local_irq_restore(flags);
}
}
void __invalidate_dcache_range(unsigned long start, unsigned long end)
{
unsigned int i;
unsigned flags;
unsigned int align;
if (cpuinfo.use_dcache) {
/*
* No need to cover entire cache range,
* just cover cache footprint
*/
end = min(start + cpuinfo.dcache_size, end);
align = ~(cpuinfo.dcache_line - 1);
start &= align; /* Make sure we are aligned */
/* Push end up to the next cache line */
end = ((end & align) + cpuinfo.dcache_line);
local_irq_save(flags);
__disable_dcache();
for (i = start; i < end; i += cpuinfo.dcache_line)
__invalidate_dcache(i);
__enable_dcache();
local_irq_restore(flags);
}
}
void __invalidate_dcache_page(struct vm_area_struct *vma, struct page *page)
{
__invalidate_dcache_all();
}
void __invalidate_dcache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long adr,
int len)
{
__invalidate_dcache_all();
}

View File

@@ -0,0 +1,106 @@
/*
* Support for MicroBlaze PVR (processor version register)
*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2007 John Williams <john.williams@petalogix.com>
*
* 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/init.h>
#include <linux/string.h>
#include <asm/pvr.h>
#include <asm/cpuinfo.h>
/*
* Helper macro to map between fields in our struct cpuinfo, and
* the PVR macros in pvr.h.
*/
#define CI(c, p) { ci->c = PVR_##p(pvr); }
#define err_printk(x) \
early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n");
void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
{
struct pvr_s pvr;
int temp; /* for saving temp value */
get_pvr(&pvr);
CI(ver_code, VERSION);
if (!ci->ver_code) {
printk(KERN_ERR "ERROR: MB has broken PVR regs "
"-> use DTS setting\n");
return;
}
temp = PVR_USE_BARREL(pvr) | PVR_USE_MSR_INSTR(pvr) |\
PVR_USE_PCMP_INSTR(pvr) | PVR_USE_DIV(pvr);
if (ci->use_instr != temp)
err_printk("BARREL, MSR, PCMP or DIV");
ci->use_instr = temp;
temp = PVR_USE_HW_MUL(pvr) | PVR_USE_MUL64(pvr);
if (ci->use_mult != temp)
err_printk("HW_MUL");
ci->use_mult = temp;
temp = PVR_USE_FPU(pvr) | PVR_USE_FPU2(pvr);
if (ci->use_fpu != temp)
err_printk("HW_FPU");
ci->use_fpu = temp;
ci->use_exc = PVR_OPCODE_0x0_ILLEGAL(pvr) |\
PVR_UNALIGNED_EXCEPTION(pvr) |\
PVR_ILL_OPCODE_EXCEPTION(pvr) |\
PVR_IOPB_BUS_EXCEPTION(pvr) |\
PVR_DOPB_BUS_EXCEPTION(pvr) |\
PVR_DIV_ZERO_EXCEPTION(pvr) |\
PVR_FPU_EXCEPTION(pvr) |\
PVR_FSL_EXCEPTION(pvr);
CI(pvr_user1, USER1);
CI(pvr_user2, USER2);
CI(mmu, USE_MMU);
CI(use_icache, USE_ICACHE);
CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
CI(icache_write, ICACHE_ALLOW_WR);
CI(icache_line, ICACHE_LINE_LEN);
CI(icache_size, ICACHE_BYTE_SIZE);
CI(icache_base, ICACHE_BASEADDR);
CI(icache_high, ICACHE_HIGHADDR);
CI(use_dcache, USE_DCACHE);
CI(dcache_tagbits, DCACHE_ADDR_TAG_BITS);
CI(dcache_write, DCACHE_ALLOW_WR);
CI(dcache_line, DCACHE_LINE_LEN);
CI(dcache_size, DCACHE_BYTE_SIZE);
CI(dcache_base, DCACHE_BASEADDR);
CI(dcache_high, DCACHE_HIGHADDR);
CI(use_dopb, D_OPB);
CI(use_iopb, I_OPB);
CI(use_dlmb, D_LMB);
CI(use_ilmb, I_LMB);
CI(num_fsl, FSL_LINKS);
CI(irq_edge, INTERRUPT_IS_EDGE);
CI(irq_positive, EDGE_IS_POSITIVE);
CI(area_optimised, AREA_OPTIMISED);
CI(hw_debug, DEBUG_ENABLED);
CI(num_pc_brk, NUMBER_OF_PC_BRK);
CI(num_rd_brk, NUMBER_OF_RD_ADDR_BRK);
CI(num_wr_brk, NUMBER_OF_WR_ADDR_BRK);
CI(fpga_family_code, TARGET_FAMILY);
/* take timebase-frequency from DTS */
ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2007 John Williams <john.williams@petalogix.com>
*
* 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/init.h>
#include <linux/string.h>
#include <asm/cpuinfo.h>
#include <asm/pvr.h>
static const char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY;
static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER;
#define err_printk(x) \
early_printk("ERROR: Microblaze " x "-different for kernel and DTS\n");
void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
{
int i = 0;
ci->use_instr =
(fcpu(cpu, "xlnx,use-barrel") ? PVR0_USE_BARREL_MASK : 0) |
(fcpu(cpu, "xlnx,use-msr-instr") ? PVR2_USE_MSR_INSTR : 0) |
(fcpu(cpu, "xlnx,use-pcmp-instr") ? PVR2_USE_PCMP_INSTR : 0) |
(fcpu(cpu, "xlnx,use-div") ? PVR0_USE_DIV_MASK : 0);
if (CONFIG_XILINX_MICROBLAZE0_USE_BARREL)
i |= PVR0_USE_BARREL_MASK;
if (CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR)
i |= PVR2_USE_MSR_INSTR;
if (CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR)
i |= PVR2_USE_PCMP_INSTR;
if (CONFIG_XILINX_MICROBLAZE0_USE_DIV)
i |= PVR0_USE_DIV_MASK;
if (ci->use_instr != i)
err_printk("BARREL, MSR, PCMP or DIV");
ci->use_mult = fcpu(cpu, "xlnx,use-hw-mul");
if (ci->use_mult != CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL)
err_printk("HW_MUL");
ci->use_mult =
(ci->use_mult > 1 ?
(PVR2_USE_MUL64_MASK | PVR0_USE_HW_MUL_MASK) :
(ci->use_mult == 1 ? PVR0_USE_HW_MUL_MASK : 0));
ci->use_fpu = fcpu(cpu, "xlnx,use-fpu");
if (ci->use_fpu != CONFIG_XILINX_MICROBLAZE0_USE_FPU)
err_printk("HW_FPU");
ci->use_fpu = (ci->use_fpu > 1 ?
(PVR2_USE_FPU2_MASK | PVR0_USE_FPU_MASK) :
(ci->use_fpu == 1 ? PVR0_USE_FPU_MASK : 0));
ci->use_exc =
(fcpu(cpu, "xlnx,unaligned-exceptions") ?
PVR2_UNALIGNED_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,ill-opcode-exception") ?
PVR2_ILL_OPCODE_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,iopb-bus-exception") ?
PVR2_IOPB_BUS_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,dopb-bus-exception") ?
PVR2_DOPB_BUS_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,div-zero-exception") ?
PVR2_DIV_ZERO_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,fpu-exception") ? PVR2_FPU_EXC_MASK : 0) |
(fcpu(cpu, "xlnx,fsl-exception") ? PVR2_USE_EXTEND_FSL : 0);
ci->use_icache = fcpu(cpu, "xlnx,use-icache");
ci->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits");
ci->icache_write = fcpu(cpu, "xlnx,allow-icache-wr");
ci->icache_line = fcpu(cpu, "xlnx,icache-line-len") << 2;
if (!ci->icache_line) {
if (fcpu(cpu, "xlnx,icache-use-fsl"))
ci->icache_line = 4 << 2;
else
ci->icache_line = 1 << 2;
}
ci->icache_size = fcpu(cpu, "i-cache-size");
ci->icache_base = fcpu(cpu, "i-cache-baseaddr");
ci->icache_high = fcpu(cpu, "i-cache-highaddr");
ci->use_dcache = fcpu(cpu, "xlnx,use-dcache");
ci->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag");
ci->dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr");
ci->dcache_line = fcpu(cpu, "xlnx,dcache-line-len") << 2;
if (!ci->dcache_line) {
if (fcpu(cpu, "xlnx,dcache-use-fsl"))
ci->dcache_line = 4 << 2;
else
ci->dcache_line = 1 << 2;
}
ci->dcache_size = fcpu(cpu, "d-cache-size");
ci->dcache_base = fcpu(cpu, "d-cache-baseaddr");
ci->dcache_high = fcpu(cpu, "d-cache-highaddr");
ci->use_dopb = fcpu(cpu, "xlnx,d-opb");
ci->use_iopb = fcpu(cpu, "xlnx,i-opb");
ci->use_dlmb = fcpu(cpu, "xlnx,d-lmb");
ci->use_ilmb = fcpu(cpu, "xlnx,i-lmb");
ci->num_fsl = fcpu(cpu, "xlnx,fsl-links");
ci->irq_edge = fcpu(cpu, "xlnx,interrupt-is-edge");
ci->irq_positive = fcpu(cpu, "xlnx,edge-is-positive");
ci->area_optimised = 0;
ci->hw_debug = fcpu(cpu, "xlnx,debug-enabled");
ci->num_pc_brk = fcpu(cpu, "xlnx,number-of-pc-brk");
ci->num_rd_brk = fcpu(cpu, "xlnx,number-of-rd-addr-brk");
ci->num_wr_brk = fcpu(cpu, "xlnx,number-of-wr-addr-brk");
ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
ci->pvr_user1 = fcpu(cpu, "xlnx,pvr-user1");
ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");
ci->mmu = fcpu(cpu, "xlnx,use-mmu");
ci->ver_code = 0;
ci->fpga_family_code = 0;
/* Do various fixups based on CPU version and FPGA family strings */
/* Resolved the CPU version code */
for (i = 0; cpu_ver_lookup[i].s != NULL; i++) {
if (strcmp(cpu_ver_lookup[i].s, cpu_ver_string) == 0)
ci->ver_code = cpu_ver_lookup[i].k;
}
/* Resolved the fpga family code */
for (i = 0; family_string_lookup[i].s != NULL; i++) {
if (strcmp(family_string_lookup[i].s, family_string) == 0)
ci->fpga_family_code = family_string_lookup[i].k;
}
/* FIXME - mb3 and spartan2 do not exist in PVR */
/* This is mb3 and on a non Spartan2 */
if (ci->ver_code == 0x20 && ci->fpga_family_code != 0xf0)
/* Hardware Multiplier in use */
ci->use_mult = 1;
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2007 John Williams <john.williams@petalogix.com>
*
* 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/init.h>
#include <linux/slab.h>
#include <asm/cpuinfo.h>
#include <asm/pvr.h>
const struct cpu_ver_key cpu_ver_lookup[] = {
/* These key value are as per MBV field in PVR0 */
{"5.00.a", 0x01},
{"5.00.b", 0x02},
{"5.00.c", 0x03},
{"6.00.a", 0x04},
{"6.00.b", 0x06},
{"7.00.a", 0x05},
{"7.00.b", 0x07},
{"7.10.a", 0x08},
{"7.10.b", 0x09},
{"7.10.c", 0x0a},
{"7.10.d", 0x0b},
{"7.20.a", 0x0c},
{"7.20.b", 0x0d},
{"7.20.c", 0x0e},
/* FIXME There is no keycode defined in MBV for these versions */
{"2.10.a", 0x10},
{"3.00.a", 0x20},
{"4.00.a", 0x30},
{"4.00.b", 0x40},
{NULL, 0},
};
/*
* FIXME Not sure if the actual key is defined by Xilinx in the PVR
*/
const struct family_string_key family_string_lookup[] = {
{"virtex2", 0x4},
{"virtex2pro", 0x5},
{"spartan3", 0x6},
{"virtex4", 0x7},
{"virtex5", 0x8},
{"spartan3e", 0x9},
{"spartan3a", 0xa},
{"spartan3an", 0xb},
{"spartan3adsp", 0xc},
{"spartan6", 0xd},
{"virtex6", 0xe},
/* FIXME There is no key code defined for spartan2 */
{"spartan2", 0xf0},
{NULL, 0},
};
struct cpuinfo cpuinfo;
void __init setup_cpuinfo(void)
{
struct device_node *cpu = NULL;
cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu");
if (!cpu)
printk(KERN_ERR "You don't have cpu!!!\n");
printk(KERN_INFO "%s: initialising\n", __func__);
switch (cpu_has_pvr()) {
case 0:
printk(KERN_WARNING
"%s: No PVR support. Using static CPU info from FDT\n",
__func__);
set_cpuinfo_static(&cpuinfo, cpu);
break;
/* FIXME I found weird behavior with MB 7.00.a/b 7.10.a
* please do not use FULL PVR with MMU */
case 1:
printk(KERN_INFO "%s: Using full CPU PVR support\n",
__func__);
set_cpuinfo_static(&cpuinfo, cpu);
set_cpuinfo_pvr_full(&cpuinfo, cpu);
break;
default:
printk(KERN_WARNING "%s: Unsupported PVR setting\n", __func__);
set_cpuinfo_static(&cpuinfo, cpu);
}
}

View File

@@ -0,0 +1,148 @@
/*
* CPU-version specific code
*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2006-2009 PetaLogix
*
* 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/init.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/cpu.h>
#include <linux/initrd.h>
#include <linux/bug.h>
#include <asm/cpuinfo.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <asm/page.h>
#include <linux/param.h>
#include <asm/pvr.h>
#include <asm/sections.h>
#include <asm/setup.h>
static int show_cpuinfo(struct seq_file *m, void *v)
{
int count = 0;
char *fpga_family = "Unknown";
char *cpu_ver = "Unknown";
int i;
/* Denormalised to get the fpga family string */
for (i = 0; family_string_lookup[i].s != NULL; i++) {
if (cpuinfo.fpga_family_code == family_string_lookup[i].k) {
fpga_family = (char *)family_string_lookup[i].s;
break;
}
}
/* Denormalised to get the hw version string */
for (i = 0; cpu_ver_lookup[i].s != NULL; i++) {
if (cpuinfo.ver_code == cpu_ver_lookup[i].k) {
cpu_ver = (char *)cpu_ver_lookup[i].s;
break;
}
}
count = seq_printf(m,
"CPU-Family: MicroBlaze\n"
"FPGA-Arch: %s\n"
"CPU-Ver: %s\n"
"CPU-MHz: %d.%02d\n"
"BogoMips: %lu.%02lu\n",
fpga_family,
cpu_ver,
cpuinfo.cpu_clock_freq /
1000000,
cpuinfo.cpu_clock_freq %
1000000,
loops_per_jiffy / (500000 / HZ),
(loops_per_jiffy / (5000 / HZ)) % 100);
count += seq_printf(m,
"HW:\n Shift:\t\t%s\n"
" MSR:\t\t%s\n"
" PCMP:\t\t%s\n"
" DIV:\t\t%s\n",
(cpuinfo.use_instr & PVR0_USE_BARREL_MASK) ? "yes" : "no",
(cpuinfo.use_instr & PVR2_USE_MSR_INSTR) ? "yes" : "no",
(cpuinfo.use_instr & PVR2_USE_PCMP_INSTR) ? "yes" : "no",
(cpuinfo.use_instr & PVR0_USE_DIV_MASK) ? "yes" : "no");
count += seq_printf(m,
" MMU:\t\t%x\n",
cpuinfo.mmu);
count += seq_printf(m,
" MUL:\t\t%s\n"
" FPU:\t\t%s\n",
(cpuinfo.use_mult & PVR2_USE_MUL64_MASK) ? "v2" :
(cpuinfo.use_mult & PVR0_USE_HW_MUL_MASK) ? "v1" : "no",
(cpuinfo.use_fpu & PVR2_USE_FPU2_MASK) ? "v2" :
(cpuinfo.use_fpu & PVR0_USE_FPU_MASK) ? "v1" : "no");
count += seq_printf(m,
" Exc:\t\t%s%s%s%s%s%s%s%s\n",
(cpuinfo.use_exc & PVR2_OPCODE_0x0_ILL_MASK) ? "op0x0 " : "",
(cpuinfo.use_exc & PVR2_UNALIGNED_EXC_MASK) ? "unal " : "",
(cpuinfo.use_exc & PVR2_ILL_OPCODE_EXC_MASK) ? "ill " : "",
(cpuinfo.use_exc & PVR2_IOPB_BUS_EXC_MASK) ? "iopb " : "",
(cpuinfo.use_exc & PVR2_DOPB_BUS_EXC_MASK) ? "dopb " : "",
(cpuinfo.use_exc & PVR2_DIV_ZERO_EXC_MASK) ? "zero " : "",
(cpuinfo.use_exc & PVR2_FPU_EXC_MASK) ? "fpu " : "",
(cpuinfo.use_exc & PVR2_USE_FSL_EXC) ? "fsl " : "");
if (cpuinfo.use_icache)
count += seq_printf(m,
"Icache:\t\t%ukB\n",
cpuinfo.icache_size >> 10);
else
count += seq_printf(m, "Icache:\t\tno\n");
if (cpuinfo.use_dcache)
count += seq_printf(m,
"Dcache:\t\t%ukB\n",
cpuinfo.dcache_size >> 10);
else
count += seq_printf(m, "Dcache:\t\tno\n");
count += seq_printf(m,
"HW-Debug:\t%s\n",
cpuinfo.hw_debug ? "yes" : "no");
count += seq_printf(m,
"PVR-USR1:\t%02x\n"
"PVR-USR2:\t%08x\n",
cpuinfo.pvr_user1,
cpuinfo.pvr_user2);
return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
{
int i = *pos;
return i < NR_CPUS ? (void *) (i + 1) : NULL;
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
++*pos;
return c_start(m, pos);
}
static void c_stop(struct seq_file *m, void *v)
{
}
const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = show_cpuinfo,
};

View File

@@ -0,0 +1,81 @@
/*
* Support for MicroBlaze PVR (processor version register)
*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2007 John Williams <john.williams@petalogix.com>
*
* 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/compiler.h>
#include <asm/system.h>
#include <asm/exceptions.h>
#include <asm/pvr.h>
/*
* Until we get an assembler that knows about the pvr registers,
* this horrible cruft will have to do.
* That hardcoded opcode is mfs r3, rpvrNN
*/
#define get_single_pvr(pvrid, val) \
{ \
register unsigned tmp __asm__("r3"); \
tmp = 0x0; /* Prevent warning about unused */ \
__asm__ __volatile__ ( \
".byte 0x94,0x60,0xa0, " #pvrid "\n\t" \
: "=r" (tmp) : : "memory"); \
val = tmp; \
}
/*
* Does the CPU support the PVR register?
* return value:
* 0: no PVR
* 1: simple PVR
* 2: full PVR
*
* This must work on all CPU versions, including those before the
* PVR was even an option.
*/
int cpu_has_pvr(void)
{
unsigned flags;
unsigned pvr0;
local_save_flags(flags);
/* PVR bit in MSR tells us if there is any support */
if (!(flags & PVR_MSR_BIT))
return 0;
get_single_pvr(0x00, pvr0);
pr_debug("%s: pvr0 is 0x%08x\n", __func__, pvr0);
if (pvr0 & PVR0_PVR_FULL_MASK)
return 1;
/* for partial PVR use static cpuinfo */
return 2;
}
void get_pvr(struct pvr_s *p)
{
get_single_pvr(0, p->pvr[0]);
get_single_pvr(1, p->pvr[1]);
get_single_pvr(2, p->pvr[2]);
get_single_pvr(3, p->pvr[3]);
get_single_pvr(4, p->pvr[4]);
get_single_pvr(5, p->pvr[5]);
get_single_pvr(6, p->pvr[6]);
get_single_pvr(7, p->pvr[7]);
get_single_pvr(8, p->pvr[8]);
get_single_pvr(9, p->pvr[9]);
get_single_pvr(10, p->pvr[10]);
get_single_pvr(11, p->pvr[11]);
}

View File

@@ -0,0 +1,110 @@
/*
* Early printk support for Microblaze.
*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2003-2006 Yasushi SHOJI <yashi@atmark-techno.com>
*
* 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/console.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/tty.h>
#include <linux/io.h>
#include <asm/processor.h>
#include <linux/fcntl.h>
#include <asm/setup.h>
#include <asm/prom.h>
static u32 early_console_initialized;
static u32 base_addr;
static void early_printk_putc(char c)
{
/*
* Limit how many times we'll spin waiting for TX FIFO status.
* This will prevent lockups if the base address is incorrectly
* set, or any other issue on the UARTLITE.
* This limit is pretty arbitrary, unless we are at about 10 baud
* we'll never timeout on a working UART.
*/
unsigned retries = 10000;
/* read status bit - 0x8 offset */
while (--retries && (in_be32(base_addr + 8) & (1 << 3)))
;
/* Only attempt the iowrite if we didn't timeout */
/* write to TX_FIFO - 0x4 offset */
if (retries)
out_be32(base_addr + 4, c & 0xff);
}
static void early_printk_write(struct console *unused,
const char *s, unsigned n)
{
while (*s && n-- > 0) {
early_printk_putc(*s);
if (*s == '\n')
early_printk_putc('\r');
s++;
}
}
static struct console early_serial_console = {
.name = "earlyser",
.write = early_printk_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};
static struct console *early_console = &early_serial_console;
void early_printk(const char *fmt, ...)
{
char buf[512];
int n;
va_list ap;
if (early_console_initialized) {
va_start(ap, fmt);
n = vscnprintf(buf, 512, fmt, ap);
early_console->write(early_console, buf, n);
va_end(ap);
}
}
int __init setup_early_printk(char *opt)
{
if (early_console_initialized)
return 1;
base_addr = early_uartlite_console();
if (base_addr) {
early_console_initialized = 1;
#ifdef CONFIG_MMU
early_console_reg_tlb_alloc(base_addr);
#endif
early_printk("early_printk_console is enabled at 0x%08x\n",
base_addr);
/* register_console(early_console); */
return 0;
} else
return 1;
}
void __init disable_early_printk(void)
{
if (!early_console_initialized || !early_console)
return;
printk(KERN_WARNING "disabling early console\n");
unregister_console(early_console);
early_console_initialized = 0;
}

View File

@@ -0,0 +1,588 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/linkage.h>
#include <asm/thread_info.h>
#include <linux/errno.h>
#include <asm/entry.h>
#include <asm/asm-offsets.h>
#include <asm/registers.h>
#include <asm/unistd.h>
#include <asm/percpu.h>
#include <asm/signal.h>
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
.macro disable_irq
msrclr r0, MSR_IE
.endm
.macro enable_irq
msrset r0, MSR_IE
.endm
.macro clear_bip
msrclr r0, MSR_BIP
.endm
#else
.macro disable_irq
mfs r11, rmsr
andi r11, r11, ~MSR_IE
mts rmsr, r11
.endm
.macro enable_irq
mfs r11, rmsr
ori r11, r11, MSR_IE
mts rmsr, r11
.endm
.macro clear_bip
mfs r11, rmsr
andi r11, r11, ~MSR_BIP
mts rmsr, r11
.endm
#endif
ENTRY(_interrupt)
swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
lwi r11, r0, PER_CPU(KM) /* load mode indicator */
beqid r11, 1f
nop
brid 2f /* jump over */
addik r1, r1, (-PT_SIZE) /* room for pt_regs (delay slot) */
1: /* switch to kernel stack */
lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
lwi r1, r1, TS_THREAD_INFO /* get the thread info */
/* calculate kernel stack pointer */
addik r1, r1, THREAD_SIZE - PT_SIZE
2:
swi r11, r1, PT_MODE /* store the mode */
lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
swi r2, r1, PT_R2
swi r3, r1, PT_R3
swi r4, r1, PT_R4
swi r5, r1, PT_R5
swi r6, r1, PT_R6
swi r7, r1, PT_R7
swi r8, r1, PT_R8
swi r9, r1, PT_R9
swi r10, r1, PT_R10
swi r11, r1, PT_R11
swi r12, r1, PT_R12
swi r13, r1, PT_R13
swi r14, r1, PT_R14
swi r14, r1, PT_PC
swi r15, r1, PT_R15
swi r16, r1, PT_R16
swi r17, r1, PT_R17
swi r18, r1, PT_R18
swi r19, r1, PT_R19
swi r20, r1, PT_R20
swi r21, r1, PT_R21
swi r22, r1, PT_R22
swi r23, r1, PT_R23
swi r24, r1, PT_R24
swi r25, r1, PT_R25
swi r26, r1, PT_R26
swi r27, r1, PT_R27
swi r28, r1, PT_R28
swi r29, r1, PT_R29
swi r30, r1, PT_R30
swi r31, r1, PT_R31
/* special purpose registers */
mfs r11, rmsr
swi r11, r1, PT_MSR
mfs r11, rear
swi r11, r1, PT_EAR
mfs r11, resr
swi r11, r1, PT_ESR
mfs r11, rfsr
swi r11, r1, PT_FSR
/* reload original stack pointer and save it */
lwi r11, r0, PER_CPU(ENTRY_SP)
swi r11, r1, PT_R1
/* update mode indicator we are in kernel mode */
addik r11, r0, 1
swi r11, r0, PER_CPU(KM)
/* restore r31 */
lwi r31, r0, PER_CPU(CURRENT_SAVE)
/* prepare the link register, the argument and jump */
la r15, r0, ret_from_intr - 8
addk r6, r0, r15
braid do_IRQ
add r5, r0, r1
ret_from_intr:
lwi r11, r1, PT_MODE
bneid r11, 3f
lwi r6, r31, TS_THREAD_INFO /* get thread info */
lwi r19, r6, TI_FLAGS /* get flags in thread info */
/* do an extra work if any bits are set */
andi r11, r19, _TIF_NEED_RESCHED
beqi r11, 1f
bralid r15, schedule
nop
1: andi r11, r19, _TIF_SIGPENDING
beqid r11, no_intr_reshed
addk r5, r1, r0
addk r7, r0, r0
bralid r15, do_signal
addk r6, r0, r0
no_intr_reshed:
/* save mode indicator */
lwi r11, r1, PT_MODE
3:
swi r11, r0, PER_CPU(KM)
/* save r31 */
swi r31, r0, PER_CPU(CURRENT_SAVE)
restore_context:
/* special purpose registers */
lwi r11, r1, PT_FSR
mts rfsr, r11
lwi r11, r1, PT_ESR
mts resr, r11
lwi r11, r1, PT_EAR
mts rear, r11
lwi r11, r1, PT_MSR
mts rmsr, r11
lwi r31, r1, PT_R31
lwi r30, r1, PT_R30
lwi r29, r1, PT_R29
lwi r28, r1, PT_R28
lwi r27, r1, PT_R27
lwi r26, r1, PT_R26
lwi r25, r1, PT_R25
lwi r24, r1, PT_R24
lwi r23, r1, PT_R23
lwi r22, r1, PT_R22
lwi r21, r1, PT_R21
lwi r20, r1, PT_R20
lwi r19, r1, PT_R19
lwi r18, r1, PT_R18
lwi r17, r1, PT_R17
lwi r16, r1, PT_R16
lwi r15, r1, PT_R15
lwi r14, r1, PT_PC
lwi r13, r1, PT_R13
lwi r12, r1, PT_R12
lwi r11, r1, PT_R11
lwi r10, r1, PT_R10
lwi r9, r1, PT_R9
lwi r8, r1, PT_R8
lwi r7, r1, PT_R7
lwi r6, r1, PT_R6
lwi r5, r1, PT_R5
lwi r4, r1, PT_R4
lwi r3, r1, PT_R3
lwi r2, r1, PT_R2
lwi r1, r1, PT_R1
rtid r14, 0
nop
ENTRY(_reset)
brai 0;
ENTRY(_user_exception)
swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
lwi r11, r0, PER_CPU(KM) /* load mode indicator */
beqid r11, 1f /* Already in kernel mode? */
nop
brid 2f /* jump over */
addik r1, r1, (-PT_SIZE) /* Room for pt_regs (delay slot) */
1: /* Switch to kernel stack */
lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
lwi r1, r1, TS_THREAD_INFO /* get the thread info */
/* calculate kernel stack pointer */
addik r1, r1, THREAD_SIZE - PT_SIZE
swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
lwi r11, r0, PER_CPU(KM) /* load mode indicator */
2:
swi r11, r1, PT_MODE /* store the mode */
lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
/* save them on stack */
swi r2, r1, PT_R2
swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
swi r5, r1, PT_R5
swi r6, r1, PT_R6
swi r7, r1, PT_R7
swi r8, r1, PT_R8
swi r9, r1, PT_R9
swi r10, r1, PT_R10
swi r11, r1, PT_R11
/* r12: _always_ in clobber list; see unistd.h */
swi r12, r1, PT_R12
swi r13, r1, PT_R13
/* r14: _always_ in clobber list; see unistd.h */
swi r14, r1, PT_R14
/* but we want to return to the next inst. */
addik r14, r14, 0x4
swi r14, r1, PT_PC /* increment by 4 and store in pc */
swi r15, r1, PT_R15
swi r16, r1, PT_R16
swi r17, r1, PT_R17
swi r18, r1, PT_R18
swi r19, r1, PT_R19
swi r20, r1, PT_R20
swi r21, r1, PT_R21
swi r22, r1, PT_R22
swi r23, r1, PT_R23
swi r24, r1, PT_R24
swi r25, r1, PT_R25
swi r26, r1, PT_R26
swi r27, r1, PT_R27
swi r28, r1, PT_R28
swi r29, r1, PT_R29
swi r30, r1, PT_R30
swi r31, r1, PT_R31
disable_irq
nop /* make sure IE bit is in effect */
clear_bip /* once IE is in effect it is safe to clear BIP */
nop
/* special purpose registers */
mfs r11, rmsr
swi r11, r1, PT_MSR
mfs r11, rear
swi r11, r1, PT_EAR
mfs r11, resr
swi r11, r1, PT_ESR
mfs r11, rfsr
swi r11, r1, PT_FSR
/* reload original stack pointer and save it */
lwi r11, r0, PER_CPU(ENTRY_SP)
swi r11, r1, PT_R1
/* update mode indicator we are in kernel mode */
addik r11, r0, 1
swi r11, r0, PER_CPU(KM)
/* restore r31 */
lwi r31, r0, PER_CPU(CURRENT_SAVE)
/* re-enable interrupts now we are in kernel mode */
enable_irq
/* See if the system call number is valid. */
addi r11, r12, -__NR_syscalls
bgei r11, 1f /* return to user if not valid */
/* Figure out which function to use for this system call. */
/* Note Microblaze barrel shift is optional, so don't rely on it */
add r12, r12, r12 /* convert num -> ptr */
add r12, r12, r12
lwi r12, r12, sys_call_table /* Get function pointer */
la r15, r0, ret_to_user-8 /* set return address */
bra r12 /* Make the system call. */
bri 0 /* won't reach here */
1:
brid ret_to_user /* jump to syscall epilogue */
addi r3, r0, -ENOSYS /* set errno in delay slot */
/*
* Debug traps are like a system call, but entered via brki r14, 0x60
* All we need to do is send the SIGTRAP signal to current, ptrace and do_signal
* will handle the rest
*/
ENTRY(_debug_exception)
swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
lwi r1, r1, TS_THREAD_INFO /* get the thread info */
addik r1, r1, THREAD_SIZE - PT_SIZE /* get the kernel stack */
swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
lwi r11, r0, PER_CPU(KM) /* load mode indicator */
//save_context:
swi r11, r1, PT_MODE /* store the mode */
lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
/* save them on stack */
swi r2, r1, PT_R2
swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
swi r5, r1, PT_R5
swi r6, r1, PT_R6
swi r7, r1, PT_R7
swi r8, r1, PT_R8
swi r9, r1, PT_R9
swi r10, r1, PT_R10
swi r11, r1, PT_R11
/* r12: _always_ in clobber list; see unistd.h */
swi r12, r1, PT_R12
swi r13, r1, PT_R13
/* r14: _always_ in clobber list; see unistd.h */
swi r14, r1, PT_R14
swi r14, r1, PT_PC /* Will return to interrupted instruction */
swi r15, r1, PT_R15
swi r16, r1, PT_R16
swi r17, r1, PT_R17
swi r18, r1, PT_R18
swi r19, r1, PT_R19
swi r20, r1, PT_R20
swi r21, r1, PT_R21
swi r22, r1, PT_R22
swi r23, r1, PT_R23
swi r24, r1, PT_R24
swi r25, r1, PT_R25
swi r26, r1, PT_R26
swi r27, r1, PT_R27
swi r28, r1, PT_R28
swi r29, r1, PT_R29
swi r30, r1, PT_R30
swi r31, r1, PT_R31
disable_irq
nop /* make sure IE bit is in effect */
clear_bip /* once IE is in effect it is safe to clear BIP */
nop
/* special purpose registers */
mfs r11, rmsr
swi r11, r1, PT_MSR
mfs r11, rear
swi r11, r1, PT_EAR
mfs r11, resr
swi r11, r1, PT_ESR
mfs r11, rfsr
swi r11, r1, PT_FSR
/* reload original stack pointer and save it */
lwi r11, r0, PER_CPU(ENTRY_SP)
swi r11, r1, PT_R1
/* update mode indicator we are in kernel mode */
addik r11, r0, 1
swi r11, r0, PER_CPU(KM)
/* restore r31 */
lwi r31, r0, PER_CPU(CURRENT_SAVE)
/* re-enable interrupts now we are in kernel mode */
enable_irq
addi r5, r0, SIGTRAP /* sending the trap signal */
add r6, r0, r31 /* to current */
bralid r15, send_sig
add r7, r0, r0 /* 3rd param zero */
/* Restore r3/r4 to work around how ret_to_user works */
lwi r3, r1, PT_R3
lwi r4, r1, PT_R4
bri ret_to_user
ENTRY(_break)
bri 0
/* struct task_struct *_switch_to(struct thread_info *prev,
struct thread_info *next); */
ENTRY(_switch_to)
/* prepare return value */
addk r3, r0, r31
/* save registers in cpu_context */
/* use r11 and r12, volatile registers, as temp register */
addik r11, r5, TI_CPU_CONTEXT
swi r1, r11, CC_R1
swi r2, r11, CC_R2
/* skip volatile registers.
* they are saved on stack when we jumped to _switch_to() */
/* dedicated registers */
swi r13, r11, CC_R13
swi r14, r11, CC_R14
swi r15, r11, CC_R15
swi r16, r11, CC_R16
swi r17, r11, CC_R17
swi r18, r11, CC_R18
/* save non-volatile registers */
swi r19, r11, CC_R19
swi r20, r11, CC_R20
swi r21, r11, CC_R21
swi r22, r11, CC_R22
swi r23, r11, CC_R23
swi r24, r11, CC_R24
swi r25, r11, CC_R25
swi r26, r11, CC_R26
swi r27, r11, CC_R27
swi r28, r11, CC_R28
swi r29, r11, CC_R29
swi r30, r11, CC_R30
/* special purpose registers */
mfs r12, rmsr
swi r12, r11, CC_MSR
mfs r12, rear
swi r12, r11, CC_EAR
mfs r12, resr
swi r12, r11, CC_ESR
mfs r12, rfsr
swi r12, r11, CC_FSR
/* update r31, the current */
lwi r31, r6, TI_TASK
swi r31, r0, PER_CPU(CURRENT_SAVE)
/* get new process' cpu context and restore */
addik r11, r6, TI_CPU_CONTEXT
/* special purpose registers */
lwi r12, r11, CC_FSR
mts rfsr, r12
lwi r12, r11, CC_ESR
mts resr, r12
lwi r12, r11, CC_EAR
mts rear, r12
lwi r12, r11, CC_MSR
mts rmsr, r12
/* non-volatile registers */
lwi r30, r11, CC_R30
lwi r29, r11, CC_R29
lwi r28, r11, CC_R28
lwi r27, r11, CC_R27
lwi r26, r11, CC_R26
lwi r25, r11, CC_R25
lwi r24, r11, CC_R24
lwi r23, r11, CC_R23
lwi r22, r11, CC_R22
lwi r21, r11, CC_R21
lwi r20, r11, CC_R20
lwi r19, r11, CC_R19
/* dedicated registers */
lwi r18, r11, CC_R18
lwi r17, r11, CC_R17
lwi r16, r11, CC_R16
lwi r15, r11, CC_R15
lwi r14, r11, CC_R14
lwi r13, r11, CC_R13
/* skip volatile registers */
lwi r2, r11, CC_R2
lwi r1, r11, CC_R1
rtsd r15, 8
nop
ENTRY(ret_from_fork)
addk r5, r0, r3
addk r6, r0, r1
brlid r15, schedule_tail
nop
swi r31, r1, PT_R31 /* save r31 in user context. */
/* will soon be restored to r31 in ret_to_user */
addk r3, r0, r0
brid ret_to_user
nop
work_pending:
andi r11, r19, _TIF_NEED_RESCHED
beqi r11, 1f
bralid r15, schedule
nop
1: andi r11, r19, _TIF_SIGPENDING
beqi r11, no_work_pending
addk r5, r1, r0
addik r7, r0, 1
bralid r15, do_signal
addk r6, r0, r0
bri no_work_pending
ENTRY(ret_to_user)
disable_irq
swi r4, r1, PT_R4 /* return val */
swi r3, r1, PT_R3 /* return val */
lwi r6, r31, TS_THREAD_INFO /* get thread info */
lwi r19, r6, TI_FLAGS /* get flags in thread info */
bnei r19, work_pending /* do an extra work if any bits are set */
no_work_pending:
disable_irq
/* save r31 */
swi r31, r0, PER_CPU(CURRENT_SAVE)
/* save mode indicator */
lwi r18, r1, PT_MODE
swi r18, r0, PER_CPU(KM)
//restore_context:
/* special purpose registers */
lwi r18, r1, PT_FSR
mts rfsr, r18
lwi r18, r1, PT_ESR
mts resr, r18
lwi r18, r1, PT_EAR
mts rear, r18
lwi r18, r1, PT_MSR
mts rmsr, r18
lwi r31, r1, PT_R31
lwi r30, r1, PT_R30
lwi r29, r1, PT_R29
lwi r28, r1, PT_R28
lwi r27, r1, PT_R27
lwi r26, r1, PT_R26
lwi r25, r1, PT_R25
lwi r24, r1, PT_R24
lwi r23, r1, PT_R23
lwi r22, r1, PT_R22
lwi r21, r1, PT_R21
lwi r20, r1, PT_R20
lwi r19, r1, PT_R19
lwi r18, r1, PT_R18
lwi r17, r1, PT_R17
lwi r16, r1, PT_R16
lwi r15, r1, PT_R15
lwi r14, r1, PT_PC
lwi r13, r1, PT_R13
lwi r12, r1, PT_R12
lwi r11, r1, PT_R11
lwi r10, r1, PT_R10
lwi r9, r1, PT_R9
lwi r8, r1, PT_R8
lwi r7, r1, PT_R7
lwi r6, r1, PT_R6
lwi r5, r1, PT_R5
lwi r4, r1, PT_R4 /* return val */
lwi r3, r1, PT_R3 /* return val */
lwi r2, r1, PT_R2
lwi r1, r1, PT_R1
rtid r14, 0
nop
sys_vfork:
brid microblaze_vfork
addk r5, r1, r0
sys_clone:
brid microblaze_clone
addk r7, r1, r0
sys_execve:
brid microblaze_execve
addk r8, r1, r0
sys_rt_sigreturn_wrapper:
brid sys_rt_sigreturn
addk r5, r1, r0
sys_rt_sigsuspend_wrapper:
brid sys_rt_sigsuspend
addk r7, r1, r0
/* Interrupt vector table */
.section .init.ivt, "ax"
.org 0x0
brai _reset
brai _user_exception
brai _interrupt
brai _break
brai _hw_exception_handler
.org 0x60
brai _debug_exception
.section .rodata,"a"
#include "syscall_table.S"
syscall_table_size=(.-sys_call_table)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,162 @@
/*
* HW exception handling
*
* Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2008 PetaLogix
*
* 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.
*/
/*
* This file handles the architecture-dependent parts of hardware exceptions
*/
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kallsyms.h>
#include <linux/module.h>
#include <asm/exceptions.h>
#include <asm/entry.h> /* For KM CPU var */
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <asm/current.h>
#define MICROBLAZE_ILL_OPCODE_EXCEPTION 0x02
#define MICROBLAZE_IBUS_EXCEPTION 0x03
#define MICROBLAZE_DBUS_EXCEPTION 0x04
#define MICROBLAZE_DIV_ZERO_EXCEPTION 0x05
#define MICROBLAZE_FPU_EXCEPTION 0x06
#define MICROBLAZE_PRIVILEGED_EXCEPTION 0x07
static DEFINE_SPINLOCK(die_lock);
void die(const char *str, struct pt_regs *fp, long err)
{
console_verbose();
spin_lock_irq(&die_lock);
printk(KERN_WARNING "Oops: %s, sig: %ld\n", str, err);
show_regs(fp);
spin_unlock_irq(&die_lock);
/* do_exit() should take care of panic'ing from an interrupt
* context so we don't handle it here
*/
do_exit(err);
}
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
{
siginfo_t info;
if (kernel_mode(regs)) {
debugger(regs);
die("Exception in kernel mode", regs, signr);
}
info.si_signo = signr;
info.si_errno = 0;
info.si_code = code;
info.si_addr = (void __user *) addr;
force_sig_info(signr, &info, current);
}
asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
int fsr, int addr)
{
#ifdef CONFIG_MMU
int code;
addr = regs->pc;
#endif
#if 0
printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x " \
"ESR=%08x\n",
type, user_mode(regs) ? "user" : "kernel", fsr,
(unsigned int) regs->pc, (unsigned int) regs->esr);
#endif
switch (type & 0x1F) {
case MICROBLAZE_ILL_OPCODE_EXCEPTION:
if (user_mode(regs)) {
pr_debug(KERN_WARNING "Illegal opcode exception " \
"in user mode.\n");
_exception(SIGILL, regs, ILL_ILLOPC, addr);
return;
}
printk(KERN_WARNING "Illegal opcode exception " \
"in kernel mode.\n");
die("opcode exception", regs, SIGBUS);
break;
case MICROBLAZE_IBUS_EXCEPTION:
if (user_mode(regs)) {
pr_debug(KERN_WARNING "Instruction bus error " \
"exception in user mode.\n");
_exception(SIGBUS, regs, BUS_ADRERR, addr);
return;
}
printk(KERN_WARNING "Instruction bus error exception " \
"in kernel mode.\n");
die("bus exception", regs, SIGBUS);
break;
case MICROBLAZE_DBUS_EXCEPTION:
if (user_mode(regs)) {
pr_debug(KERN_WARNING "Data bus error exception " \
"in user mode.\n");
_exception(SIGBUS, regs, BUS_ADRERR, addr);
return;
}
printk(KERN_WARNING "Data bus error exception " \
"in kernel mode.\n");
die("bus exception", regs, SIGBUS);
break;
case MICROBLAZE_DIV_ZERO_EXCEPTION:
if (user_mode(regs)) {
pr_debug(KERN_WARNING "Divide by zero exception " \
"in user mode\n");
_exception(SIGILL, regs, FPE_INTDIV, addr);
return;
}
printk(KERN_WARNING "Divide by zero exception " \
"in kernel mode.\n");
die("Divide by exception", regs, SIGBUS);
break;
case MICROBLAZE_FPU_EXCEPTION:
pr_debug(KERN_WARNING "FPU exception\n");
/* IEEE FP exception */
/* I removed fsr variable and use code var for storing fsr */
if (fsr & FSR_IO)
fsr = FPE_FLTINV;
else if (fsr & FSR_OF)
fsr = FPE_FLTOVF;
else if (fsr & FSR_UF)
fsr = FPE_FLTUND;
else if (fsr & FSR_DZ)
fsr = FPE_FLTDIV;
else if (fsr & FSR_DO)
fsr = FPE_FLTRES;
_exception(SIGFPE, regs, fsr, addr);
break;
#ifdef CONFIG_MMU
case MICROBLAZE_PRIVILEGED_EXCEPTION:
pr_debug(KERN_WARNING "Privileged exception\n");
/* "brk r0,r0" - used as debug breakpoint */
if (get_user(code, (unsigned long *)regs->pc) == 0
&& code == 0x980c0000) {
_exception(SIGTRAP, regs, TRAP_BRKPT, addr);
} else {
_exception(SIGILL, regs, ILL_PRVOPC, addr);
}
break;
#endif
default:
/* FIXME what to do in unexpected exception */
printk(KERN_WARNING "Unexpected exception %02x "
"PC=%08x in %s mode\n", type, (unsigned int) addr,
kernel_mode(regs) ? "kernel" : "user");
}
return;
}

View File

@@ -0,0 +1,265 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, Inc.
*
* MMU code derived from arch/ppc/kernel/head_4xx.S:
* Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
* Initial PowerPC version.
* Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
* Rewritten for PReP
* Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
* Low-level exception handers, MMU support, and rewrite.
* Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
* PowerPC 8xx modifications.
* Copyright (c) 1998-1999 TiVo, Inc.
* PowerPC 403GCX modifications.
* Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
* PowerPC 403GCX/405GP modifications.
* Copyright 2000 MontaVista Software Inc.
* PPC405 modifications
* PowerPC 403GCX/405GP modifications.
* Author: MontaVista Software, Inc.
* frank_rowand@mvista.com or source@mvista.com
* debbie_chu@mvista.com
*
* 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/linkage.h>
#include <asm/thread_info.h>
#include <asm/page.h>
#include <asm/prom.h> /* for OF_DT_HEADER */
#ifdef CONFIG_MMU
#include <asm/setup.h> /* COMMAND_LINE_SIZE */
#include <asm/mmu.h>
#include <asm/processor.h>
.data
.global empty_zero_page
.align 12
empty_zero_page:
.space 4096
.global swapper_pg_dir
swapper_pg_dir:
.space 4096
#endif /* CONFIG_MMU */
.text
ENTRY(_start)
mfs r1, rmsr
andi r1, r1, ~2
mts rmsr, r1
/*
* Here is checking mechanism which check if Microblaze has msr instructions
* We load msr and compare it with previous r1 value - if is the same,
* msr instructions works if not - cpu don't have them.
*/
/* r8=0 - I have msr instr, 1 - I don't have them */
rsubi r0, r0, 1 /* set the carry bit */
msrclr r0, 0x4 /* try to clear it */
/* read the carry bit, r8 will be '0' if msrclr exists */
addik r8, r0, 0
/* r7 may point to an FDT, or there may be one linked in.
if it's in r7, we've got to save it away ASAP.
We ensure r7 points to a valid FDT, just in case the bootloader
is broken or non-existent */
beqi r7, no_fdt_arg /* NULL pointer? don't copy */
lw r11, r0, r7 /* Does r7 point to a */
rsubi r11, r11, OF_DT_HEADER /* valid FDT? */
beqi r11, _prepare_copy_fdt
or r7, r0, r0 /* clear R7 when not valid DTB */
bnei r11, no_fdt_arg /* No - get out of here */
_prepare_copy_fdt:
or r11, r0, r0 /* incremment */
ori r4, r0, TOPHYS(_fdt_start)
ori r3, r0, (0x4000 - 4)
_copy_fdt:
lw r12, r7, r11 /* r12 = r7 + r11 */
sw r12, r4, r11 /* addr[r4 + r11] = r12 */
addik r11, r11, 4 /* increment counting */
bgtid r3, _copy_fdt /* loop for all entries */
addik r3, r3, -4 /* descrement loop */
no_fdt_arg:
#ifdef CONFIG_MMU
#ifndef CONFIG_CMDLINE_BOOL
/*
* handling command line
* copy command line to __init_end. There is space for storing command line.
*/
or r6, r0, r0 /* incremment */
ori r4, r0, __init_end /* load address of command line */
tophys(r4,r4) /* convert to phys address */
ori r3, r0, COMMAND_LINE_SIZE - 1 /* number of loops */
_copy_command_line:
lbu r7, r5, r6 /* r7=r5+r6 - r5 contain pointer to command line */
sb r7, r4, r6 /* addr[r4+r6]= r7*/
addik r6, r6, 1 /* increment counting */
bgtid r3, _copy_command_line /* loop for all entries */
addik r3, r3, -1 /* descrement loop */
addik r5, r4, 0 /* add new space for command line */
tovirt(r5,r5)
#endif /* CONFIG_CMDLINE_BOOL */
#ifdef NOT_COMPILE
/* save bram context */
or r6, r0, r0 /* incremment */
ori r4, r0, TOPHYS(_bram_load_start) /* save bram context */
ori r3, r0, (LMB_SIZE - 4)
_copy_bram:
lw r7, r0, r6 /* r7 = r0 + r6 */
sw r7, r4, r6 /* addr[r4 + r6] = r7*/
addik r6, r6, 4 /* increment counting */
bgtid r3, _copy_bram /* loop for all entries */
addik r3, r3, -4 /* descrement loop */
#endif
/* We have to turn on the MMU right away. */
/*
* Set up the initial MMU state so we can do the first level of
* kernel initialization. This maps the first 16 MBytes of memory 1:1
* virtual to physical.
*/
nop
addik r3, r0, 63 /* Invalidate all TLB entries */
_invalidate:
mts rtlbx, r3
mts rtlbhi, r0 /* flush: ensure V is clear */
bgtid r3, _invalidate /* loop for all entries */
addik r3, r3, -1
/* sync */
/*
* We should still be executing code at physical address area
* RAM_BASEADDR at this point. However, kernel code is at
* a virtual address. So, set up a TLB mapping to cover this once
* translation is enabled.
*/
addik r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
tophys(r4,r3) /* Load the kernel physical address */
mts rpid,r0 /* Load the kernel PID */
nop
bri 4
/*
* Configure and load two entries into TLB slots 0 and 1.
* In case we are pinning TLBs, these are reserved in by the
* other TLB functions. If not reserving, then it doesn't
* matter where they are loaded.
*/
andi r4,r4,0xfffffc00 /* Mask off the real page number */
ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
andi r3,r3,0xfffffc00 /* Mask off the effective page number */
ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
mts rtlbx,r0 /* TLB slow 0 */
mts rtlblo,r4 /* Load the data portion of the entry */
mts rtlbhi,r3 /* Load the tag portion of the entry */
addik r4, r4, 0x01000000 /* Map next 16 M entries */
addik r3, r3, 0x01000000
ori r6,r0,1 /* TLB slot 1 */
mts rtlbx,r6
mts rtlblo,r4 /* Load the data portion of the entry */
mts rtlbhi,r3 /* Load the tag portion of the entry */
/*
* Load a TLB entry for LMB, since we need access to
* the exception vectors, using a 4k real==virtual mapping.
*/
ori r6,r0,3 /* TLB slot 3 */
mts rtlbx,r6
ori r4,r0,(TLB_WR | TLB_EX)
ori r3,r0,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
mts rtlblo,r4 /* Load the data portion of the entry */
mts rtlbhi,r3 /* Load the tag portion of the entry */
/*
* We now have the lower 16 Meg of RAM mapped into TLB entries, and the
* caches ready to work.
*/
turn_on_mmu:
ori r15,r0,start_here
ori r4,r0,MSR_KERNEL_VMS
mts rmsr,r4
nop
rted r15,0 /* enables MMU */
nop
start_here:
#endif /* CONFIG_MMU */
/* Initialize small data anchors */
la r13, r0, _KERNEL_SDA_BASE_
la r2, r0, _KERNEL_SDA2_BASE_
/* Initialize stack pointer */
la r1, r0, init_thread_union + THREAD_SIZE - 4
/* Initialize r31 with current task address */
la r31, r0, init_task
/*
* Call platform dependent initialize function.
* Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
* the function.
*/
la r9, r0, machine_early_init
brald r15, r9
nop
#ifndef CONFIG_MMU
la r15, r0, machine_halt
braid start_kernel
nop
#else
/*
* Initialize the MMU.
*/
bralid r15, mmu_init
nop
/* Go back to running unmapped so we can load up new values
* and change to using our exception vectors.
* On the MicroBlaze, all we invalidate the used TLB entries to clear
* the old 16M byte TLB mappings.
*/
ori r15,r0,TOPHYS(kernel_load_context)
ori r4,r0,MSR_KERNEL
mts rmsr,r4
nop
bri 4
rted r15,0
nop
/* Load up the kernel context */
kernel_load_context:
# Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away.
ori r5,r0,3
mts rtlbx,r5
nop
mts rtlbhi,r0
nop
addi r15, r0, machine_halt
ori r17, r0, start_kernel
ori r4, r0, MSR_KERNEL_VMS
mts rmsr, r4
nop
rted r17, 0 /* enable MMU and jump to start_kernel */
nop
#endif /* CONFIG_MMU */

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/sched.h>
#include <linux/io.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/prom.h>
static unsigned int base_addr;
void heartbeat(void)
{
static unsigned int cnt, period, dist;
if (base_addr) {
if (cnt == 0 || cnt == dist)
out_be32(base_addr, 1);
else if (cnt == 7 || cnt == dist + 7)
out_be32(base_addr, 0);
if (++cnt > period) {
cnt = 0;
/*
* The hyperbolic function below modifies the heartbeat
* period length in dependency of the current (5min)
* load. It goes through the points f(0)=126, f(1)=86,
* f(5)=51, f(inf)->30.
*/
period = ((672 << FSHIFT) / (5 * avenrun[0] +
(7 << FSHIFT))) + 30;
dist = period / 4;
}
}
}
void setup_heartbeat(void)
{
struct device_node *gpio = NULL;
int j;
char *gpio_list[] = {
"xlnx,xps-gpio-1.00.a",
"xlnx,opb-gpio-1.00.a",
NULL
};
for (j = 0; gpio_list[j] != NULL; j++) {
gpio = of_find_compatible_node(NULL, NULL, gpio_list[j]);
if (gpio)
break;
}
base_addr = *(int *) of_get_property(gpio, "reg", NULL);
base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE);
printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr);
if (*(int *) of_get_property(gpio, "xlnx,is-bidir", NULL))
out_be32(base_addr + 4, 0); /* GPIO is configured as output */
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/module.h>
#include <linux/sched.h>
#include <linux/init_task.h>
#include <linux/fs.h>
#include <linux/mqueue.h>
#include <asm/pgtable.h>
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
union thread_union init_thread_union __init_task_data =
{ INIT_THREAD_INFO(init_task) };
struct task_struct init_task = INIT_TASK(init_task);
EXPORT_SYMBOL(init_task);

View File

@@ -0,0 +1,174 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/init.h>
#include <linux/irq.h>
#include <asm/page.h>
#include <linux/io.h>
#include <linux/bug.h>
#include <asm/prom.h>
#include <asm/irq.h>
#ifdef CONFIG_SELFMOD_INTC
#include <asm/selfmod.h>
#define INTC_BASE BARRIER_BASE_ADDR
#else
static unsigned int intc_baseaddr;
#define INTC_BASE intc_baseaddr
#endif
unsigned int nr_irq;
/* No one else should require these constants, so define them locally here. */
#define ISR 0x00 /* Interrupt Status Register */
#define IPR 0x04 /* Interrupt Pending Register */
#define IER 0x08 /* Interrupt Enable Register */
#define IAR 0x0c /* Interrupt Acknowledge Register */
#define SIE 0x10 /* Set Interrupt Enable bits */
#define CIE 0x14 /* Clear Interrupt Enable bits */
#define IVR 0x18 /* Interrupt Vector Register */
#define MER 0x1c /* Master Enable Register */
#define MER_ME (1<<0)
#define MER_HIE (1<<1)
static void intc_enable_or_unmask(unsigned int irq)
{
pr_debug("enable_or_unmask: %d\n", irq);
out_be32(INTC_BASE + SIE, 1 << irq);
}
static void intc_disable_or_mask(unsigned int irq)
{
pr_debug("disable: %d\n", irq);
out_be32(INTC_BASE + CIE, 1 << irq);
}
static void intc_ack(unsigned int irq)
{
pr_debug("ack: %d\n", irq);
out_be32(INTC_BASE + IAR, 1 << irq);
}
static void intc_mask_ack(unsigned int irq)
{
unsigned long mask = 1 << irq;
pr_debug("disable_and_ack: %d\n", irq);
out_be32(INTC_BASE + CIE, mask);
out_be32(INTC_BASE + IAR, mask);
}
static void intc_end(unsigned int irq)
{
unsigned long mask = 1 << irq;
pr_debug("end: %d\n", irq);
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
out_be32(INTC_BASE + SIE, mask);
/* ack level sensitive intr */
if (irq_desc[irq].status & IRQ_LEVEL)
out_be32(INTC_BASE + IAR, mask);
}
}
static struct irq_chip intc_dev = {
.name = "Xilinx INTC",
.unmask = intc_enable_or_unmask,
.mask = intc_disable_or_mask,
.ack = intc_ack,
.mask_ack = intc_mask_ack,
.end = intc_end,
};
unsigned int get_irq(struct pt_regs *regs)
{
int irq;
/*
* NOTE: This function is the one that needs to be improved in
* order to handle multiple interrupt controllers. It currently
* is hardcoded to check for interrupts only on the first INTC.
*/
irq = in_be32(INTC_BASE + IVR);
pr_debug("get_irq: %d\n", irq);
return irq;
}
void __init init_IRQ(void)
{
u32 i, j, intr_type;
struct device_node *intc = NULL;
#ifdef CONFIG_SELFMOD_INTC
unsigned int intc_baseaddr = 0;
static int arr_func[] = {
(int)&get_irq,
(int)&intc_enable_or_unmask,
(int)&intc_disable_or_mask,
(int)&intc_mask_ack,
(int)&intc_ack,
(int)&intc_end,
0
};
#endif
static char *intc_list[] = {
"xlnx,xps-intc-1.00.a",
"xlnx,opb-intc-1.00.c",
"xlnx,opb-intc-1.00.b",
"xlnx,opb-intc-1.00.a",
NULL
};
for (j = 0; intc_list[j] != NULL; j++) {
intc = of_find_compatible_node(NULL, NULL, intc_list[j]);
if (intc)
break;
}
BUG_ON(!intc);
intc_baseaddr = *(int *) of_get_property(intc, "reg", NULL);
intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE);
nr_irq = *(int *) of_get_property(intc, "xlnx,num-intr-inputs", NULL);
intr_type =
*(int *) of_get_property(intc, "xlnx,kind-of-intr", NULL);
if (intr_type >= (1 << (nr_irq + 1)))
printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n");
#ifdef CONFIG_SELFMOD_INTC
selfmod_function((int *) arr_func, intc_baseaddr);
#endif
printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
intc_list[j], intc_baseaddr, nr_irq, intr_type);
/*
* Disable all external interrupts until they are
* explicity requested.
*/
out_be32(intc_baseaddr + IER, 0);
/* Acknowledge any pending interrupts just in case. */
out_be32(intc_baseaddr + IAR, 0xffffffff);
/* Turn on the Master Enable. */
out_be32(intc_baseaddr + MER, MER_HIE | MER_ME);
for (i = 0; i < nr_irq; ++i) {
if (intr_type & (0x00000001 << i)) {
set_irq_chip_and_handler_name(i, &intc_dev,
handle_edge_irq, intc_dev.name);
irq_desc[i].status &= ~IRQ_LEVEL;
} else {
set_irq_chip_and_handler_name(i, &intc_dev,
handle_level_irq, intc_dev.name);
irq_desc[i].status |= IRQ_LEVEL;
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/init.h>
#include <linux/kernel.h>
#include <linux/hardirq.h>
#include <linux/interrupt.h>
#include <linux/irqflags.h>
#include <linux/seq_file.h>
#include <linux/kernel_stat.h>
#include <linux/irq.h>
#include <asm/prom.h>
unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
{
struct of_irq oirq;
if (of_irq_map_one(dev, index, &oirq))
return NO_IRQ;
return oirq.specifier[0];
}
EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
static u32 concurrent_irq;
void do_IRQ(struct pt_regs *regs)
{
unsigned int irq;
struct pt_regs *old_regs = set_irq_regs(regs);
irq_enter();
irq = get_irq(regs);
next_irq:
BUG_ON(irq == -1U);
generic_handle_irq(irq);
irq = get_irq(regs);
if (irq != -1U) {
pr_debug("next irq: %d\n", irq);
++concurrent_irq;
goto next_irq;
}
irq_exit();
set_irq_regs(old_regs);
}
int show_interrupts(struct seq_file *p, void *v)
{
int i = *(loff_t *) v, j;
struct irqaction *action;
unsigned long flags;
if (i == 0) {
seq_printf(p, " ");
for_each_online_cpu(j)
seq_printf(p, "CPU%-8d", j);
seq_putc(p, '\n');
}
if (i < nr_irq) {
spin_lock_irqsave(&irq_desc[i].lock, flags);
action = irq_desc[i].action;
if (!action)
goto skip;
seq_printf(p, "%3d: ", i);
#ifndef CONFIG_SMP
seq_printf(p, "%10u ", kstat_irqs(i));
#else
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
seq_printf(p, " %8s", irq_desc[i].status &
IRQ_LEVEL ? "level" : "edge");
seq_printf(p, " %8s", irq_desc[i].chip->name);
seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next)
seq_printf(p, ", %s", action->name);
seq_putc(p, '\n');
skip:
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
}
return 0;
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2008-2009 PetaLogix
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/string.h>
#include <linux/cryptohash.h>
#include <linux/delay.h>
#include <linux/in6.h>
#include <linux/syscalls.h>
#include <asm/checksum.h>
#include <linux/io.h>
#include <asm/page.h>
#include <asm/system.h>
#include <linux/uaccess.h>
/*
* libgcc functions - functions that are used internally by the
* compiler... (prototypes are not correct though, but that
* doesn't really matter since they're not versioned).
*/
extern void __ashldi3(void);
EXPORT_SYMBOL(__ashldi3);
extern void __ashrdi3(void);
EXPORT_SYMBOL(__ashrdi3);
extern void __divsi3(void);
EXPORT_SYMBOL(__divsi3);
extern void __lshrdi3(void);
EXPORT_SYMBOL(__lshrdi3);
extern void __modsi3(void);
EXPORT_SYMBOL(__modsi3);
extern void __mulsi3(void);
EXPORT_SYMBOL(__mulsi3);
extern void __muldi3(void);
EXPORT_SYMBOL(__muldi3);
extern void __ucmpdi2(void);
EXPORT_SYMBOL(__ucmpdi2);
extern void __udivsi3(void);
EXPORT_SYMBOL(__udivsi3);
extern void __umodsi3(void);
EXPORT_SYMBOL(__umodsi3);
extern char *_ebss;
EXPORT_SYMBOL_GPL(_ebss);

View File

@@ -0,0 +1,120 @@
/*
* Miscellaneous low-level MMU functions.
*
* Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2008-2009 PetaLogix
* Copyright (C) 2007 Xilinx, Inc. All rights reserved.
*
* Derived from arch/ppc/kernel/misc.S
*
* 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/linkage.h>
#include <linux/sys.h>
#include <asm/unistd.h>
#include <linux/errno.h>
#include <asm/mmu.h>
#include <asm/page.h>
.text
/*
* Flush MMU TLB
*
* We avoid flushing the pinned 0, 1 and possibly 2 entries.
*/
.globl _tlbia;
.align 4;
_tlbia:
addik r12, r0, 63 /* flush all entries (63 - 3) */
/* isync */
_tlbia_1:
mts rtlbx, r12
nop
mts rtlbhi, r0 /* flush: ensure V is clear */
nop
addik r11, r12, -2
bneid r11, _tlbia_1 /* loop for all entries */
addik r12, r12, -1
/* sync */
rtsd r15, 8
nop
/*
* Flush MMU TLB for a particular address (in r5)
*/
.globl _tlbie;
.align 4;
_tlbie:
mts rtlbsx, r5 /* look up the address in TLB */
nop
mfs r12, rtlbx /* Retrieve index */
nop
blti r12, _tlbie_1 /* Check if found */
mts rtlbhi, r0 /* flush: ensure V is clear */
nop
_tlbie_1:
rtsd r15, 8
nop
/*
* Allocate TLB entry for early console
*/
.globl early_console_reg_tlb_alloc;
.align 4;
early_console_reg_tlb_alloc:
/*
* Load a TLB entry for the UART, so that microblaze_progress() can use
* the UARTs nice and early. We use a 4k real==virtual mapping.
*/
ori r4, r0, 63
mts rtlbx, r4 /* TLB slot 2 */
or r4,r5,r0
andi r4,r4,0xfffff000
ori r4,r4,(TLB_WR|TLB_I|TLB_M|TLB_G)
andi r5,r5,0xfffff000
ori r5,r5,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
mts rtlblo,r4 /* Load the data portion of the entry */
nop
mts rtlbhi,r5 /* Load the tag portion of the entry */
nop
rtsd r15, 8
nop
/*
* Copy a whole page (4096 bytes).
*/
#define COPY_16_BYTES \
lwi r7, r6, 0; \
lwi r8, r6, 4; \
lwi r9, r6, 8; \
lwi r10, r6, 12; \
swi r7, r5, 0; \
swi r8, r5, 4; \
swi r9, r5, 8; \
swi r10, r5, 12
/* FIXME DCACHE_LINE_BYTES (CONFIG_XILINX_MICROBLAZE0_DCACHE_LINE_LEN * 4)*/
#define DCACHE_LINE_BYTES (4 * 4)
.globl copy_page;
.align 4;
copy_page:
ori r11, r0, (PAGE_SIZE/DCACHE_LINE_BYTES) - 1
_copy_page_loop:
COPY_16_BYTES
#if DCACHE_LINE_BYTES >= 32
COPY_16_BYTES
#endif
addik r6, r6, DCACHE_LINE_BYTES
addik r5, r5, DCACHE_LINE_BYTES
bneid r11, _copy_page_loop
addik r11, r11, -1
rtsd r15, 8
nop

View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleloader.h>
#include <linux/kernel.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <asm/pgtable.h>
void *module_alloc(unsigned long size)
{
void *ret;
ret = (size == 0) ? NULL : vmalloc(size);
pr_debug("module_alloc (%08lx@%08lx)\n", size, (unsigned long int)ret);
return ret;
}
void module_free(struct module *module, void *region)
{
pr_debug("module_free(%s,%08lx)\n", module->name,
(unsigned long)region);
vfree(region);
}
int module_frob_arch_sections(Elf_Ehdr *hdr,
Elf_Shdr *sechdrs,
char *secstrings,
struct module *mod)
{
return 0;
}
int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relsec, struct module *module)
{
printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
module->name);
return -ENOEXEC;
}
int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relsec, struct module *module)
{
unsigned int i;
Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
Elf32_Sym *sym;
unsigned long int *location;
unsigned long int value;
#if __GNUC__ < 4
unsigned long int old_value;
#endif
pr_debug("Applying add relocation section %u to %u\n",
relsec, sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr +
rela[i].r_offset;
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr +
ELF32_R_SYM(rela[i].r_info);
value = sym->st_value + rela[i].r_addend;
switch (ELF32_R_TYPE(rela[i].r_info)) {
/*
* Be careful! mb-gcc / mb-ld splits the relocs between the
* text and the reloc table. In general this means we must
* read the current contents of (*location), add any offset
* then store the result back in
*/
case R_MICROBLAZE_32:
#if __GNUC__ < 4
old_value = *location;
*location = value + old_value;
pr_debug("R_MICROBLAZE_32 (%08lx->%08lx)\n",
old_value, value);
#else
*location = value;
#endif
break;
case R_MICROBLAZE_64:
#if __GNUC__ < 4
/* Split relocs only required/used pre gcc4.1.1 */
old_value = ((location[0] & 0x0000FFFF) << 16) |
(location[1] & 0x0000FFFF);
value += old_value;
#endif
location[0] = (location[0] & 0xFFFF0000) |
(value >> 16);
location[1] = (location[1] & 0xFFFF0000) |
(value & 0xFFFF);
#if __GNUC__ < 4
pr_debug("R_MICROBLAZE_64 (%08lx->%08lx)\n",
old_value, value);
#endif
break;
case R_MICROBLAZE_64_PCREL:
#if __GNUC__ < 4
old_value = (location[0] & 0xFFFF) << 16 |
(location[1] & 0xFFFF);
value -= old_value;
#endif
value -= (unsigned long int)(location) + 4;
location[0] = (location[0] & 0xFFFF0000) |
(value >> 16);
location[1] = (location[1] & 0xFFFF0000) |
(value & 0xFFFF);
pr_debug("R_MICROBLAZE_64_PCREL (%08lx)\n",
value);
break;
case R_MICROBLAZE_32_PCREL_LO:
pr_debug("R_MICROBLAZE_32_PCREL_LO\n");
break;
case R_MICROBLAZE_64_NONE:
pr_debug("R_MICROBLAZE_NONE\n");
break;
case R_MICROBLAZE_NONE:
pr_debug("R_MICROBLAZE_NONE\n");
break;
default:
printk(KERN_ERR "module %s: "
"Unknown relocation: %u\n",
module->name,
ELF32_R_TYPE(rela[i].r_info));
return -ENOEXEC;
}
}
return 0;
}
int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
struct module *module)
{
return 0;
}
void module_arch_cleanup(struct module *mod)
{
}

View File

@@ -0,0 +1,113 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/errno.h>
void of_device_make_bus_id(struct of_device *dev)
{
static atomic_t bus_no_reg_magic;
struct device_node *node = dev->node;
const u32 *reg;
u64 addr;
int magic;
/*
* For MMIO, get the physical address
*/
reg = of_get_property(node, "reg", NULL);
if (reg) {
addr = of_translate_address(node, reg);
if (addr != OF_BAD_ADDR) {
dev_set_name(&dev->dev, "%llx.%s",
(unsigned long long)addr, node->name);
return;
}
}
/*
* No BusID, use the node name and add a globally incremented
* counter (and pray...)
*/
magic = atomic_add_return(1, &bus_no_reg_magic);
dev_set_name(&dev->dev, "%s.%d", node->name, magic - 1);
}
EXPORT_SYMBOL(of_device_make_bus_id);
struct of_device *of_device_alloc(struct device_node *np,
const char *bus_id,
struct device *parent)
{
struct of_device *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
dev->node = of_node_get(np);
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.parent = parent;
dev->dev.release = of_release_dev;
dev->dev.archdata.of_node = np;
if (bus_id)
dev_set_name(&dev->dev, bus_id);
else
of_device_make_bus_id(dev);
return dev;
}
EXPORT_SYMBOL(of_device_alloc);
int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct of_device *ofdev;
const char *compat;
int seen = 0, cplen, sl;
if (!dev)
return -ENODEV;
ofdev = to_of_device(dev);
if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name))
return -ENOMEM;
if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
return -ENOMEM;
/* Since the compatible field can contain pretty much anything
* it's not really legal to split it out with commas. We split it
* up using a number of environment variables instead. */
compat = of_get_property(ofdev->node, "compatible", &cplen);
while (compat && *compat && cplen > 0) {
if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
return -ENOMEM;
sl = strlen(compat) + 1;
compat += sl;
cplen -= sl;
seen++;
}
if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
return -ENOMEM;
/* modalias is trickier, we add it in 2 steps */
if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
sizeof(env->buf) - env->buflen);
if (sl >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
env->buflen += sl;
return 0;
}
EXPORT_SYMBOL(of_device_uevent);

View File

@@ -0,0 +1,201 @@
/*
* Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
* and Arnd Bergmann, IBM Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#undef DEBUG
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/errno.h>
#include <linux/topology.h>
#include <asm/atomic.h>
struct bus_type of_platform_bus_type = {
.uevent = of_device_uevent,
};
EXPORT_SYMBOL(of_platform_bus_type);
static int __init of_bus_driver_init(void)
{
return of_bus_type_init(&of_platform_bus_type, "of_platform");
}
postcore_initcall(of_bus_driver_init);
struct of_device *of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent)
{
struct of_device *dev;
dev = of_device_alloc(np, bus_id, parent);
if (!dev)
return NULL;
dev->dma_mask = 0xffffffffUL;
dev->dev.bus = &of_platform_bus_type;
/* We do not fill the DMA ops for platform devices by default.
* This is currently the responsibility of the platform code
* to do such, possibly using a device notifier
*/
if (of_device_register(dev) != 0) {
of_device_free(dev);
return NULL;
}
return dev;
}
EXPORT_SYMBOL(of_platform_device_create);
/**
* of_platform_bus_create - Create an OF device for a bus node and all its
* children. Optionally recursively instanciate matching busses.
* @bus: device node of the bus to instanciate
* @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
* disallow recursive creation of child busses
*/
static int of_platform_bus_create(const struct device_node *bus,
const struct of_device_id *matches,
struct device *parent)
{
struct device_node *child;
struct of_device *dev;
int rc = 0;
for_each_child_of_node(bus, child) {
pr_debug(" create child: %s\n", child->full_name);
dev = of_platform_device_create(child, NULL, parent);
if (dev == NULL)
rc = -ENOMEM;
else if (!of_match_node(matches, child))
continue;
if (rc == 0) {
pr_debug(" and sub busses\n");
rc = of_platform_bus_create(child, matches, &dev->dev);
}
if (rc) {
of_node_put(child);
break;
}
}
return rc;
}
/**
* of_platform_bus_probe - Probe the device-tree for platform busses
* @root: parent of the first level to probe or NULL for the root of the tree
* @matches: match table, NULL to use the default
* @parent: parent to hook devices from, NULL for toplevel
*
* Note that children of the provided root are not instanciated as devices
* unless the specified root itself matches the bus list and is not NULL.
*/
int of_platform_bus_probe(struct device_node *root,
const struct of_device_id *matches,
struct device *parent)
{
struct device_node *child;
struct of_device *dev;
int rc = 0;
if (matches == NULL)
matches = of_default_bus_ids;
if (matches == OF_NO_DEEP_PROBE)
return -EINVAL;
if (root == NULL)
root = of_find_node_by_path("/");
else
of_node_get(root);
pr_debug("of_platform_bus_probe()\n");
pr_debug(" starting at: %s\n", root->full_name);
/* Do a self check of bus type, if there's a match, create
* children
*/
if (of_match_node(matches, root)) {
pr_debug(" root match, create all sub devices\n");
dev = of_platform_device_create(root, NULL, parent);
if (dev == NULL) {
rc = -ENOMEM;
goto bail;
}
pr_debug(" create all sub busses\n");
rc = of_platform_bus_create(root, matches, &dev->dev);
goto bail;
}
for_each_child_of_node(root, child) {
if (!of_match_node(matches, child))
continue;
pr_debug(" match: %s\n", child->full_name);
dev = of_platform_device_create(child, NULL, parent);
if (dev == NULL)
rc = -ENOMEM;
else
rc = of_platform_bus_create(child, matches, &dev->dev);
if (rc) {
of_node_put(child);
break;
}
}
bail:
of_node_put(root);
return rc;
}
EXPORT_SYMBOL(of_platform_bus_probe);
static int of_dev_node_match(struct device *dev, void *data)
{
return to_of_device(dev)->node == data;
}
struct of_device *of_find_device_by_node(struct device_node *np)
{
struct device *dev;
dev = bus_find_device(&of_platform_bus_type,
NULL, np, of_dev_node_match);
if (dev)
return to_of_device(dev);
return NULL;
}
EXPORT_SYMBOL(of_find_device_by_node);
static int of_dev_phandle_match(struct device *dev, void *data)
{
phandle *ph = data;
return to_of_device(dev)->node->linux_phandle == *ph;
}
struct of_device *of_find_device_by_phandle(phandle ph)
{
struct device *dev;
dev = bus_find_device(&of_platform_bus_type,
NULL, &ph, of_dev_phandle_match);
if (dev)
return to_of_device(dev);
return NULL;
}
EXPORT_SYMBOL(of_find_device_by_phandle);

View File

@@ -0,0 +1,252 @@
/*
* Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2008-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/module.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/tick.h>
#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/pgalloc.h>
void show_regs(struct pt_regs *regs)
{
printk(KERN_INFO " Registers dump: mode=%X\r\n", regs->pt_mode);
printk(KERN_INFO " r1=%08lX, r2=%08lX, r3=%08lX, r4=%08lX\n",
regs->r1, regs->r2, regs->r3, regs->r4);
printk(KERN_INFO " r5=%08lX, r6=%08lX, r7=%08lX, r8=%08lX\n",
regs->r5, regs->r6, regs->r7, regs->r8);
printk(KERN_INFO " r9=%08lX, r10=%08lX, r11=%08lX, r12=%08lX\n",
regs->r9, regs->r10, regs->r11, regs->r12);
printk(KERN_INFO " r13=%08lX, r14=%08lX, r15=%08lX, r16=%08lX\n",
regs->r13, regs->r14, regs->r15, regs->r16);
printk(KERN_INFO " r17=%08lX, r18=%08lX, r19=%08lX, r20=%08lX\n",
regs->r17, regs->r18, regs->r19, regs->r20);
printk(KERN_INFO " r21=%08lX, r22=%08lX, r23=%08lX, r24=%08lX\n",
regs->r21, regs->r22, regs->r23, regs->r24);
printk(KERN_INFO " r25=%08lX, r26=%08lX, r27=%08lX, r28=%08lX\n",
regs->r25, regs->r26, regs->r27, regs->r28);
printk(KERN_INFO " r29=%08lX, r30=%08lX, r31=%08lX, rPC=%08lX\n",
regs->r29, regs->r30, regs->r31, regs->pc);
printk(KERN_INFO " msr=%08lX, ear=%08lX, esr=%08lX, fsr=%08lX\n",
regs->msr, regs->ear, regs->esr, regs->fsr);
}
void (*pm_idle)(void);
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
static int hlt_counter = 1;
void disable_hlt(void)
{
hlt_counter++;
}
EXPORT_SYMBOL(disable_hlt);
void enable_hlt(void)
{
hlt_counter--;
}
EXPORT_SYMBOL(enable_hlt);
static int __init nohlt_setup(char *__unused)
{
hlt_counter = 1;
return 1;
}
__setup("nohlt", nohlt_setup);
static int __init hlt_setup(char *__unused)
{
hlt_counter = 0;
return 1;
}
__setup("hlt", hlt_setup);
void default_idle(void)
{
if (!hlt_counter) {
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb__after_clear_bit();
local_irq_disable();
while (!need_resched())
cpu_sleep();
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
} else
while (!need_resched())
cpu_relax();
}
void cpu_idle(void)
{
set_thread_flag(TIF_POLLING_NRFLAG);
/* endless idle loop with no priority at all */
while (1) {
void (*idle)(void) = pm_idle;
if (!idle)
idle = default_idle;
tick_nohz_stop_sched_tick(1);
while (!need_resched())
idle();
tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
check_pgt_cache();
}
}
void flush_thread(void)
{
}
int copy_thread(unsigned long clone_flags, unsigned long usp,
unsigned long unused,
struct task_struct *p, struct pt_regs *regs)
{
struct pt_regs *childregs = task_pt_regs(p);
struct thread_info *ti = task_thread_info(p);
*childregs = *regs;
if (user_mode(regs))
childregs->r1 = usp;
else
childregs->r1 = ((unsigned long) ti) + THREAD_SIZE;
#ifndef CONFIG_MMU
memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
ti->cpu_context.r1 = (unsigned long)childregs;
ti->cpu_context.msr = (unsigned long)childregs->msr;
#else
/* if creating a kernel thread then update the current reg (we don't
* want to use the parent's value when restoring by POP_STATE) */
if (kernel_mode(regs))
/* save new current on stack to use POP_STATE */
childregs->CURRENT_TASK = (unsigned long)p;
/* if returning to user then use the parent's value of this register */
/* if we're creating a new kernel thread then just zeroing all
* the registers. That's OK for a brand new thread.*/
/* Pls. note that some of them will be restored in POP_STATE */
if (kernel_mode(regs))
memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
/* if this thread is created for fork/vfork/clone, then we want to
* restore all the parent's context */
/* in addition to the registers which will be restored by POP_STATE */
else {
ti->cpu_context = *(struct cpu_context *)regs;
childregs->msr |= MSR_UMS;
}
/* FIXME STATE_SAVE_PT_OFFSET; */
ti->cpu_context.r1 = (unsigned long)childregs - STATE_SAVE_ARG_SPACE;
/* we should consider the fact that childregs is a copy of the parent
* regs which were saved immediately after entering the kernel state
* before enabling VM. This MSR will be restored in switch_to and
* RETURN() and we want to have the right machine state there
* specifically this state must have INTs disabled before and enabled
* after performing rtbd
* compose the right MSR for RETURN(). It will work for switch_to also
* excepting for VM and UMS
* don't touch UMS , CARRY and cache bits
* right now MSR is a copy of parent one */
childregs->msr |= MSR_BIP;
childregs->msr &= ~MSR_EIP;
childregs->msr |= MSR_IE;
childregs->msr &= ~MSR_VM;
childregs->msr |= MSR_VMS;
childregs->msr |= MSR_EE; /* exceptions will be enabled*/
ti->cpu_context.msr = (childregs->msr|MSR_VM);
ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */
#endif
ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8;
if (clone_flags & CLONE_SETTLS)
;
return 0;
}
#ifndef CONFIG_MMU
/*
* Return saved PC of a blocked thread.
*/
unsigned long thread_saved_pc(struct task_struct *tsk)
{
struct cpu_context *ctx =
&(((struct thread_info *)(tsk->stack))->cpu_context);
/* Check whether the thread is blocked in resume() */
if (in_sched_functions(ctx->r15))
return (unsigned long)ctx->r15;
else
return ctx->r14;
}
#endif
static void kernel_thread_helper(int (*fn)(void *), void *arg)
{
fn(arg);
do_exit(-1);
}
int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
/* store them in non-volatile registers */
regs.r5 = (unsigned long)fn;
regs.r6 = (unsigned long)arg;
local_save_flags(regs.msr);
regs.pc = (unsigned long)kernel_thread_helper;
regs.pt_mode = 1;
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
&regs, 0, NULL, NULL);
}
EXPORT_SYMBOL_GPL(kernel_thread);
unsigned long get_wchan(struct task_struct *p)
{
/* TBD (used by procfs) */
return 0;
}
/* Set up a thread for executing a new program */
void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
{
set_fs(USER_DS);
regs->pc = pc;
regs->r1 = usp;
regs->pt_mode = 0;
#ifdef CONFIG_MMU
regs->msr |= MSR_UMS;
#endif
}
#ifdef CONFIG_MMU
#include <linux/elfcore.h>
/*
* Set up a thread for executing a new program
*/
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
{
return 0; /* MicroBlaze has no separate FPU registers */
}
#endif /* CONFIG_MMU */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,242 @@
/*
* `ptrace' system call
*
* Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2004-2007 John Williams <john.williams@petalogix.com>
*
* derived from arch/v850/kernel/ptrace.c
*
* Copyright (C) 2002,03 NEC Electronics Corporation
* Copyright (C) 2002,03 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/ptrace.h>
#include <linux/signal.h>
#include <linux/elf.h>
#include <linux/audit.h>
#include <linux/seccomp.h>
#include <linux/tracehook.h>
#include <linux/errno.h>
#include <asm/processor.h>
#include <linux/uaccess.h>
#include <asm/asm-offsets.h>
/* Returns the address where the register at REG_OFFS in P is stashed away. */
static microblaze_reg_t *reg_save_addr(unsigned reg_offs,
struct task_struct *t)
{
struct pt_regs *regs;
/*
* Three basic cases:
*
* (1) A register normally saved before calling the scheduler, is
* available in the kernel entry pt_regs structure at the top
* of the kernel stack. The kernel trap/irq exit path takes
* care to save/restore almost all registers for ptrace'd
* processes.
*
* (2) A call-clobbered register, where the process P entered the
* kernel via [syscall] trap, is not stored anywhere; that's
* OK, because such registers are not expected to be preserved
* when the trap returns anyway (so we don't actually bother to
* test for this case).
*
* (3) A few registers not used at all by the kernel, and so
* normally never saved except by context-switches, are in the
* context switch state.
*/
/* Register saved during kernel entry (or not available). */
regs = task_pt_regs(t);
return (microblaze_reg_t *)((char *)regs + reg_offs);
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int rval;
unsigned long val = 0;
unsigned long copied;
switch (request) {
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA:
pr_debug("PEEKTEXT/PEEKDATA at %08lX\n", addr);
copied = access_process_vm(child, addr, &val, sizeof(val), 0);
rval = -EIO;
if (copied != sizeof(val))
break;
rval = put_user(val, (unsigned long *)data);
break;
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
pr_debug("POKETEXT/POKEDATA to %08lX\n", addr);
rval = 0;
if (access_process_vm(child, addr, &data, sizeof(data), 1)
== sizeof(data))
break;
rval = -EIO;
break;
/* Read/write the word at location ADDR in the registers. */
case PTRACE_PEEKUSR:
case PTRACE_POKEUSR:
pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr);
rval = 0;
if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
/*
* Special requests that don't actually correspond
* to offsets in struct pt_regs.
*/
if (addr == PT_TEXT_ADDR) {
val = child->mm->start_code;
} else if (addr == PT_DATA_ADDR) {
val = child->mm->start_data;
} else if (addr == PT_TEXT_LEN) {
val = child->mm->end_code
- child->mm->start_code;
} else {
rval = -EIO;
}
} else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
if (request == PTRACE_PEEKUSR)
val = *reg_addr;
else
*reg_addr = data;
} else
rval = -EIO;
if (rval == 0 && request == PTRACE_PEEKUSR)
rval = put_user(val, (unsigned long *)data);
break;
/* Continue and stop at next (return from) syscall */
case PTRACE_SYSCALL:
pr_debug("PTRACE_SYSCALL\n");
case PTRACE_SINGLESTEP:
pr_debug("PTRACE_SINGLESTEP\n");
/* Restart after a signal. */
case PTRACE_CONT:
pr_debug("PTRACE_CONT\n");
rval = -EIO;
if (!valid_signal(data))
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;
pr_debug("wakeup_process\n");
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:
pr_debug("PTRACE_KILL\n");
rval = 0;
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
break;
case PTRACE_DETACH: /* detach a process that was attached. */
pr_debug("PTRACE_DETACH\n");
rval = ptrace_detach(child, data);
break;
default:
/* rval = ptrace_request(child, request, addr, data); noMMU */
rval = -EIO;
}
return rval;
}
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
{
long ret = 0;
secure_computing(regs->r12);
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
tracehook_report_syscall_entry(regs))
/*
* Tracing decided this syscall should not happen.
* We'll return a bogus call number to get an ENOSYS
* error, but leave the original number in regs->regs[0].
*/
ret = -1L;
if (unlikely(current->audit_context))
audit_syscall_entry(EM_XILINX_MICROBLAZE, regs->r12,
regs->r5, regs->r6,
regs->r7, regs->r8);
return ret ?: regs->r12;
}
asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
{
int step;
if (unlikely(current->audit_context))
audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3);
step = test_thread_flag(TIF_SINGLESTEP);
if (step || test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall_exit(regs, step);
}
#if 0
static 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 */
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0));
/*
* 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;
}
}
#endif
void ptrace_disable(struct task_struct *child)
{
/* nothing to do */
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2009 PetaLogix
*
* 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/interrupt.h>
#include <asm/selfmod.h>
#undef DEBUG
#if __GNUC__ > 3
#error GCC 4 unsupported SELFMOD. Please disable SELFMOD from menuconfig.
#endif
#define OPCODE_IMM 0xB0000000
#define OPCODE_LWI 0xE8000000
#define OPCODE_LWI_MASK 0xEC000000
#define OPCODE_RTSD 0xB60F0008 /* return from func: rtsd r15, 8 */
#define OPCODE_ADDIK 0x30000000
#define OPCODE_ADDIK_MASK 0xFC000000
#define IMM_BASE (OPCODE_IMM | (BARRIER_BASE_ADDR >> 16))
#define LWI_BASE (OPCODE_LWI | (BARRIER_BASE_ADDR & 0x0000ff00))
#define LWI_BASE_MASK (OPCODE_LWI_MASK | (BARRIER_BASE_ADDR & 0x0000ff00))
#define ADDIK_BASE (OPCODE_ADDIK | (BARRIER_BASE_ADDR & 0x0000ff00))
#define ADDIK_BASE_MASK (OPCODE_ADDIK_MASK | (BARRIER_BASE_ADDR & 0x0000ff00))
#define MODIFY_INSTR { \
pr_debug("%s: curr instr, (%d):0x%x, next(%d):0x%x\n", \
__func__, i, addr[i], i + 1, addr[i + 1]); \
addr[i] = OPCODE_IMM + (base >> 16); \
/* keep instruction opcode and add only last 16bits */ \
addr[i + 1] = (addr[i + 1] & 0xffff00ff) + (base & 0xffff); \
__invalidate_icache(addr[i]); \
__invalidate_icache(addr[i + 1]); \
pr_debug("%s: hack instr, (%d):0x%x, next(%d):0x%x\n", \
__func__, i, addr[i], i + 1, addr[i + 1]); }
/* NOTE
* self-modified part of code for improvement of interrupt controller
* save instruction in interrupt rutine
*/
void selfmod_function(const int *arr_fce, const unsigned int base)
{
unsigned int flags, i, j, *addr = NULL;
local_irq_save(flags);
__disable_icache();
/* zero terminated array */
for (j = 0; arr_fce[j] != 0; j++) {
/* get start address of function */
addr = (unsigned int *) arr_fce[j];
pr_debug("%s: func(%d) at 0x%x\n",
__func__, j, (unsigned int) addr);
for (i = 0; ; i++) {
pr_debug("%s: instruction code at %d: 0x%x\n",
__func__, i, addr[i]);
if (addr[i] == IMM_BASE) {
/* detecting of lwi (0xE8) or swi (0xF8) instr
* I can detect both opcode with one mask */
if ((addr[i + 1] & LWI_BASE_MASK) == LWI_BASE) {
MODIFY_INSTR;
} else /* detection addik for ack */
if ((addr[i + 1] & ADDIK_BASE_MASK) ==
ADDIK_BASE) {
MODIFY_INSTR;
}
} else if (addr[i] == OPCODE_RTSD) {
/* return from function means end of function */
pr_debug("%s: end of array %d\n", __func__, i);
break;
}
}
}
local_irq_restore(flags);
} /* end of self-modified code */

View File

@@ -0,0 +1,217 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/init.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/cpu.h>
#include <linux/initrd.h>
#include <linux/console.h>
#include <linux/debugfs.h>
#include <asm/setup.h>
#include <asm/sections.h>
#include <asm/page.h>
#include <linux/io.h>
#include <linux/bug.h>
#include <linux/param.h>
#include <linux/cache.h>
#include <asm/cacheflush.h>
#include <asm/entry.h>
#include <asm/cpuinfo.h>
#include <asm/system.h>
#include <asm/prom.h>
#include <asm/pgtable.h>
DEFINE_PER_CPU(unsigned int, KSP); /* Saved kernel stack pointer */
DEFINE_PER_CPU(unsigned int, KM); /* Kernel/user mode */
DEFINE_PER_CPU(unsigned int, ENTRY_SP); /* Saved SP on kernel entry */
DEFINE_PER_CPU(unsigned int, R11_SAVE); /* Temp variable for entry */
DEFINE_PER_CPU(unsigned int, CURRENT_SAVE); /* Saved current pointer */
unsigned int boot_cpuid;
char cmd_line[COMMAND_LINE_SIZE];
void __init setup_arch(char **cmdline_p)
{
*cmdline_p = cmd_line;
console_verbose();
unflatten_device_tree();
/* NOTE I think that this function is not necessary to call */
/* irq_early_init(); */
setup_cpuinfo();
__invalidate_icache_all();
__enable_icache();
__invalidate_dcache_all();
__enable_dcache();
panic_timeout = 120;
setup_memory();
#if defined(CONFIG_SELFMOD_INTC) || defined(CONFIG_SELFMOD_TIMER)
printk(KERN_NOTICE "Self modified code enable\n");
#endif
#ifdef CONFIG_VT
#if defined(CONFIG_XILINX_CONSOLE)
conswitchp = &xil_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
#endif
}
#ifdef CONFIG_MTD_UCLINUX
/* Handle both romfs and cramfs types, without generating unnecessary
code (ie no point checking for CRAMFS if it's not even enabled) */
inline unsigned get_romfs_len(unsigned *addr)
{
#ifdef CONFIG_ROMFS_FS
if (memcmp(&addr[0], "-rom1fs-", 8) == 0) /* romfs */
return be32_to_cpu(addr[2]);
#endif
#ifdef CONFIG_CRAMFS
if (addr[0] == le32_to_cpu(0x28cd3d45)) /* cramfs */
return le32_to_cpu(addr[1]);
#endif
return 0;
}
#endif /* CONFIG_MTD_UCLINUX_EBSS */
void __init machine_early_init(const char *cmdline, unsigned int ram,
unsigned int fdt, unsigned int msr)
{
unsigned long *src, *dst = (unsigned long *)0x0;
/* If CONFIG_MTD_UCLINUX is defined, assume ROMFS is at the
* end of kernel. There are two position which we want to check.
* The first is __init_end and the second __bss_start.
*/
#ifdef CONFIG_MTD_UCLINUX
int romfs_size;
unsigned int romfs_base;
char *old_klimit = klimit;
romfs_base = (ram ? ram : (unsigned int)&__init_end);
romfs_size = PAGE_ALIGN(get_romfs_len((unsigned *)romfs_base));
if (!romfs_size) {
romfs_base = (unsigned int)&__bss_start;
romfs_size = PAGE_ALIGN(get_romfs_len((unsigned *)romfs_base));
}
/* Move ROMFS out of BSS before clearing it */
if (romfs_size > 0) {
memmove(&_ebss, (int *)romfs_base, romfs_size);
klimit += romfs_size;
}
#endif
/* clearing bss section */
memset(__bss_start, 0, __bss_stop-__bss_start);
memset(_ssbss, 0, _esbss-_ssbss);
/* Copy command line passed from bootloader */
#ifndef CONFIG_CMDLINE_BOOL
if (cmdline && cmdline[0] != '\0')
strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE);
#endif
/* initialize device tree for usage in early_printk */
early_init_devtree((void *)_fdt_start);
#ifdef CONFIG_EARLY_PRINTK
setup_early_printk(NULL);
#endif
early_printk("Ramdisk addr 0x%08x, ", ram);
if (fdt)
early_printk("FDT at 0x%08x\n", fdt);
else
early_printk("Compiled-in FDT at 0x%08x\n",
(unsigned int)_fdt_start);
#ifdef CONFIG_MTD_UCLINUX
early_printk("Found romfs @ 0x%08x (0x%08x)\n",
romfs_base, romfs_size);
early_printk("#### klimit %p ####\n", old_klimit);
BUG_ON(romfs_size < 0); /* What else can we do? */
early_printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n",
romfs_size, romfs_base, (unsigned)&_ebss);
early_printk("New klimit: 0x%08x\n", (unsigned)klimit);
#endif
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
if (msr)
early_printk("!!!Your kernel has setup MSR instruction but "
"CPU don't have it %d\n", msr);
#else
if (!msr)
early_printk("!!!Your kernel not setup MSR instruction but "
"CPU have it %d\n", msr);
#endif
for (src = __ivt_start; src < __ivt_end; src++, dst++)
*dst = *src;
/* Initialize global data */
per_cpu(KM, 0) = 0x1; /* We start in kernel mode */
per_cpu(CURRENT_SAVE, 0) = (unsigned long)current;
}
#ifdef CONFIG_DEBUG_FS
struct dentry *of_debugfs_root;
static int microblaze_debugfs_init(void)
{
of_debugfs_root = debugfs_create_dir("microblaze", NULL);
return of_debugfs_root == NULL;
}
arch_initcall(microblaze_debugfs_init);
#endif
void machine_restart(char *cmd)
{
printk(KERN_NOTICE "Machine restart...\n");
dump_stack();
while (1)
;
}
void machine_shutdown(void)
{
printk(KERN_NOTICE "Machine shutdown...\n");
while (1)
;
}
void machine_halt(void)
{
printk(KERN_NOTICE "Machine halt...\n");
while (1)
;
}
void machine_power_off(void)
{
printk(KERN_NOTICE "Machine power off...\n");
while (1)
;
}

View File

@@ -0,0 +1,375 @@
/*
* Signal handling
*
* Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2008-2009 PetaLogix
* Copyright (C) 2003,2004 John Williams <jwilliams@itee.uq.edu.au>
* Copyright (C) 2001 NEC Corporation
* Copyright (C) 2001 Miles Bader <miles@gnu.org>
* Copyright (C) 1999,2000 Niibe Yutaka & Kaz Kojima
* Copyright (C) 1991,1992 Linus Torvalds
*
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
*
* This file was was derived from the sh version, arch/sh/kernel/signal.c
*
* 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/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/personality.h>
#include <linux/percpu.h>
#include <linux/linkage.h>
#include <asm/entry.h>
#include <asm/ucontext.h>
#include <linux/uaccess.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <linux/syscalls.h>
#include <asm/cacheflush.h>
#include <asm/syscalls.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
asmlinkage long
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
struct pt_regs *regs)
{
return do_sigaltstack(uss, uoss, regs->r1);
}
/*
* Do a signal return; undo the signal stack.
*/
struct sigframe {
struct sigcontext sc;
unsigned long extramask[_NSIG_WORDS-1];
unsigned long tramp[2]; /* signal trampoline */
};
struct rt_sigframe {
struct siginfo info;
struct ucontext uc;
unsigned long tramp[2]; /* signal trampoline */
};
static int restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc, int *rval_p)
{
unsigned int err = 0;
#define COPY(x) {err |= __get_user(regs->x, &sc->regs.x); }
COPY(r0);
COPY(r1);
COPY(r2); COPY(r3); COPY(r4); COPY(r5);
COPY(r6); COPY(r7); COPY(r8); COPY(r9);
COPY(r10); COPY(r11); COPY(r12); COPY(r13);
COPY(r14); COPY(r15); COPY(r16); COPY(r17);
COPY(r18); COPY(r19); COPY(r20); COPY(r21);
COPY(r22); COPY(r23); COPY(r24); COPY(r25);
COPY(r26); COPY(r27); COPY(r28); COPY(r29);
COPY(r30); COPY(r31);
COPY(pc); COPY(ear); COPY(esr); COPY(fsr);
#undef COPY
*rval_p = regs->r3;
return err;
}
asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame =
(struct rt_sigframe __user *)(regs->r1 + STATE_SAVE_ARG_SPACE);
sigset_t set;
int rval;
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->r1))
goto badframe;
return rval;
badframe:
force_sig(SIGSEGV, current);
return 0;
}
/*
* Set up a signal frame.
*/
static int
setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
unsigned long mask)
{
int err = 0;
#define COPY(x) {err |= __put_user(regs->x, &sc->regs.x); }
COPY(r0);
COPY(r1);
COPY(r2); COPY(r3); COPY(r4); COPY(r5);
COPY(r6); COPY(r7); COPY(r8); COPY(r9);
COPY(r10); COPY(r11); COPY(r12); COPY(r13);
COPY(r14); COPY(r15); COPY(r16); COPY(r17);
COPY(r18); COPY(r19); COPY(r20); COPY(r21);
COPY(r22); COPY(r23); COPY(r24); COPY(r25);
COPY(r26); COPY(r27); COPY(r28); COPY(r29);
COPY(r30); COPY(r31);
COPY(pc); COPY(ear); COPY(esr); COPY(fsr);
#undef COPY
err |= __put_user(mask, &sc->oldmask);
return err;
}
/*
* Determine which stack to use..
*/
static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
{
/* Default to using normal stack */
unsigned long sp = regs->r1;
if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
return (void __user *)((sp - frame_size) & -8UL);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
int err = 0;
int signal;
frame = get_sigframe(ka, regs, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
signal = current_thread_info()->exec_domain
&& current_thread_info()->exec_domain->signal_invmap
&& sig < 32
? current_thread_info()->exec_domain->signal_invmap[sig]
: sig;
if (info)
err |= copy_siginfo_to_user(&frame->info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user((void *)current->sas_ss_sp,
&frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->r1),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
/* minus 8 is offset to cater for "rtsd r15,8" */
/* addi r12, r0, __NR_sigreturn */
err |= __put_user(0x31800000 | __NR_rt_sigreturn ,
frame->tramp + 0);
/* brki r14, 0x8 */
err |= __put_user(0xb9cc0008, frame->tramp + 1);
/* Return from sighandler will jump to the tramp.
Negative 8 offset because return is rtsd r15, 8 */
regs->r15 = ((unsigned long)frame->tramp)-8;
__invalidate_cache_sigtramp((unsigned long)frame->tramp);
if (err)
goto give_sigsegv;
/* Set up registers for signal handler */
regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE;
/* Signal handler args: */
regs->r5 = signal; /* arg 0: signum */
regs->r6 = (unsigned long) &frame->info; /* arg 1: siginfo */
regs->r7 = (unsigned long) &frame->uc; /* arg2: ucontext */
/* Offset to handle microblaze rtid r14, 0 */
regs->pc = (unsigned long)ka->sa.sa_handler;
set_fs(USER_DS);
#ifdef DEBUG_SIG
printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
current->comm, current->pid, frame, regs->pc);
#endif
return;
give_sigsegv:
if (sig == SIGSEGV)
ka->sa.sa_handler = SIG_DFL;
force_sig(SIGSEGV, current);
}
/* Handle restarting system calls */
static inline void
handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
{
switch (regs->r3) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
if (!has_handler)
goto do_restart;
regs->r3 = -EINTR;
break;
case -ERESTARTSYS:
if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
regs->r3 = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
do_restart:
/* offset of 4 bytes to re-execute trap (brki) instruction */
#ifndef CONFIG_MMU
regs->pc -= 4;
#else
/* offset of 8 bytes required = 4 for rtbd
offset, plus 4 for size of
"brki r14,8"
instruction. */
regs->pc -= 8;
#endif
break;
}
}
/*
* OK, we're invoking a handler
*/
static int
handle_signal(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame(sig, ka, info, oldset, regs);
else
setup_rt_frame(sig, ka, NULL, oldset, regs);
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,
&current->blocked, &ka->sa.sa_mask);
sigaddset(&current->blocked, sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
}
return 1;
}
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*
* Note that we go through the signals twice: once to check the signals that
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
#ifdef DEBUG_SIG
printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall);
printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1,
regs->r12, current_thread_info()->flags);
#endif
/*
* We want the common case to go fast, which
* is why we may in certain cases get here from
* kernel mode. Just return without doing anything
* if so.
*/
if (kernel_mode(regs))
return 1;
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
if (in_syscall)
handle_restart(regs, &ka, 1);
if (handle_signal(signr, &ka, &info, oldset, regs)) {
/*
* A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
* clear the TS_RESTORE_SIGMASK flag.
*/
current_thread_info()->status &=
~TS_RESTORE_SIGMASK;
}
return 1;
}
if (in_syscall)
handle_restart(regs, NULL, 0);
/*
* If there's no signal to deliver, we just put the saved sigmask
* back.
*/
if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
/* Did we come from a system call? */
return 0;
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2007 John Williams <john.williams@petalogix.com>
*
* Copyright (C) 2006 Atmark Techno, Inc.
* Yasushi SHOJI <yashi@atmark-techno.com>
* Tetsuya OHKAWA <tetsuya@atmark-techno.com>
*
* 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/errno.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/syscalls.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/sys.h>
#include <linux/ipc.h>
#include <linux/file.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>
#include <asm/syscalls.h>
asmlinkage long microblaze_vfork(struct pt_regs *regs)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r1,
regs, 0, NULL, NULL);
}
asmlinkage long microblaze_clone(int flags, unsigned long stack, struct pt_regs *regs)
{
if (!stack)
stack = regs->r1;
return do_fork(flags, stack, regs, 0, NULL, NULL);
}
asmlinkage long microblaze_execve(char __user *filenamei, char __user *__user *argv,
char __user *__user *envp, struct pt_regs *regs)
{
int error;
char *filename;
filename = getname(filenamei);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = do_execve(filename, argv, envp, regs);
putname(filename);
out:
return error;
}
asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, off_t pgoff)
{
if (pgoff & ~PAGE_MASK)
return -EINVAL;
return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT);
}
/*
* Do a system call from kernel instead of calling sys_execve so we
* end up with proper pt_regs.
*/
int kernel_execve(const char *filename, char *const argv[], char *const envp[])
{
register const char *__a __asm__("r5") = filename;
register const void *__b __asm__("r6") = argv;
register const void *__c __asm__("r7") = envp;
register unsigned long __syscall __asm__("r12") = __NR_execve;
register unsigned long __ret __asm__("r3");
__asm__ __volatile__ ("brki r14, 0x8"
: "=r" (__ret), "=r" (__syscall)
: "1" (__syscall), "r" (__a), "r" (__b), "r" (__c)
: "r4", "r8", "r9",
"r10", "r11", "r14", "cc", "memory");
return __ret;
}

View File

@@ -0,0 +1,373 @@
ENTRY(sys_call_table)
.long sys_restart_syscall /* 0 - old "setup()" system call,
* used for restarting */
.long sys_exit
#ifdef CONFIG_MMU
.long sys_fork_wrapper
#else
.long sys_ni_syscall
#endif
.long sys_read
.long sys_write
.long sys_open /* 5 */
.long sys_close
.long sys_waitpid
.long sys_creat
.long sys_link
.long sys_unlink /* 10 */
.long sys_execve
.long sys_chdir
.long sys_time
.long sys_mknod
.long sys_chmod /* 15 */
.long sys_lchown
.long sys_ni_syscall /* old break syscall holder */
.long sys_ni_syscall /* old stat */
.long sys_lseek
.long sys_getpid /* 20 */
.long sys_mount
.long sys_oldumount
.long sys_setuid
.long sys_getuid
.long sys_stime /* 25 */
.long sys_ptrace
.long sys_alarm
.long sys_ni_syscall /* oldfstat */
.long sys_pause
.long sys_utime /* 30 */
.long sys_ni_syscall /* old stty syscall holder */
.long sys_ni_syscall /* old gtty syscall holder */
.long sys_access
.long sys_nice
.long sys_ni_syscall /* 35 - old ftime syscall holder */
.long sys_sync
.long sys_kill
.long sys_rename
.long sys_mkdir
.long sys_rmdir /* 40 */
.long sys_dup
.long sys_pipe
.long sys_times
.long sys_ni_syscall /* old prof syscall holder */
.long sys_brk /* 45 */
.long sys_setgid
.long sys_getgid
.long sys_signal
.long sys_geteuid
.long sys_getegid /* 50 */
.long sys_acct
.long sys_umount /* recycled never used phys() */
.long sys_ni_syscall /* old lock syscall holder */
.long sys_ioctl
.long sys_fcntl /* 55 */
.long sys_ni_syscall /* old mpx syscall holder */
.long sys_setpgid
.long sys_ni_syscall /* old ulimit syscall holder */
.long sys_ni_syscall /* olduname */
.long sys_umask /* 60 */
.long sys_chroot
.long sys_ustat
.long sys_dup2
.long sys_getppid
.long sys_getpgrp /* 65 */
.long sys_setsid
.long sys_ni_syscall /* sys_sigaction */
.long sys_sgetmask
.long sys_ssetmask
.long sys_setreuid /* 70 */
.long sys_setregid
.long sys_ni_syscall /* sys_sigsuspend_wrapper */
.long sys_sigpending
.long sys_sethostname
.long sys_setrlimit /* 75 */
.long sys_ni_syscall /* old_getrlimit */
.long sys_getrusage
.long sys_gettimeofday
.long sys_settimeofday
.long sys_getgroups /* 80 */
.long sys_setgroups
.long sys_ni_syscall /* old_select */
.long sys_symlink
.long sys_ni_syscall /* oldlstat */
.long sys_readlink /* 85 */
.long sys_uselib
.long sys_swapon
.long sys_reboot
.long sys_ni_syscall /* old_readdir */
.long sys_mmap /* 90 */ /* old_mmap */
.long sys_munmap
.long sys_truncate
.long sys_ftruncate
.long sys_fchmod
.long sys_fchown /* 95 */
.long sys_getpriority
.long sys_setpriority
.long sys_ni_syscall /* old profil syscall holder */
.long sys_statfs
.long sys_fstatfs /* 100 */
.long sys_ni_syscall /* ioperm */
.long sys_socketcall
.long sys_syslog /* operation with system console */
.long sys_setitimer
.long sys_getitimer /* 105 */
.long sys_newstat
.long sys_newlstat
.long sys_newfstat
.long sys_ni_syscall /* uname */
.long sys_ni_syscall /* 110 */ /* iopl */
.long sys_vhangup
.long sys_ni_syscall /* old "idle" system call */
.long sys_ni_syscall /* old sys_vm86old */
.long sys_wait4
.long sys_swapoff /* 115 */
.long sys_sysinfo
.long sys_ni_syscall /* old sys_ipc */
.long sys_fsync
.long sys_ni_syscall /* sys_sigreturn_wrapper */
.long sys_clone /* 120 */
.long sys_setdomainname
.long sys_newuname
.long sys_ni_syscall /* modify_ldt */
.long sys_adjtimex
.long sys_mprotect /* 125: sys_mprotect */
.long sys_sigprocmask
.long sys_ni_syscall /* old "create_module" */
.long sys_init_module
.long sys_delete_module
.long sys_ni_syscall /* 130: old "get_kernel_syms" */
.long sys_quotactl
.long sys_getpgid
.long sys_fchdir
.long sys_bdflush
.long sys_sysfs /* 135 */
.long sys_personality
.long sys_ni_syscall /* reserved for afs_syscall */
.long sys_setfsuid
.long sys_setfsgid
.long sys_llseek /* 140 */
.long sys_getdents
.long sys_select
.long sys_flock
.long sys_msync
.long sys_readv /* 145 */
.long sys_writev
.long sys_getsid
.long sys_fdatasync
.long sys_sysctl
.long sys_mlock /* 150: sys_mlock */
.long sys_munlock
.long sys_mlockall
.long sys_munlockall
.long sys_sched_setparam
.long sys_sched_getparam /* 155 */
.long sys_sched_setscheduler
.long sys_sched_getscheduler
.long sys_sched_yield
.long sys_sched_get_priority_max
.long sys_sched_get_priority_min /* 160 */
.long sys_sched_rr_get_interval
.long sys_nanosleep
.long sys_mremap
.long sys_setresuid
.long sys_getresuid /* 165 */
.long sys_ni_syscall /* sys_vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
.long sys_nfsservctl
.long sys_setresgid /* 170 */
.long sys_getresgid
.long sys_prctl
.long sys_rt_sigreturn_wrapper
.long sys_rt_sigaction
.long sys_rt_sigprocmask /* 175 */
.long sys_rt_sigpending
.long sys_rt_sigtimedwait
.long sys_rt_sigqueueinfo
.long sys_rt_sigsuspend_wrapper
.long sys_pread64 /* 180 */
.long sys_pwrite64
.long sys_chown
.long sys_getcwd
.long sys_capget
.long sys_capset /* 185 */
.long sys_ni_syscall /* sigaltstack */
.long sys_sendfile
.long sys_ni_syscall /* reserved for streams1 */
.long sys_ni_syscall /* reserved for streams2 */
.long sys_vfork /* 190 */
.long sys_getrlimit
.long sys_mmap_pgoff /* mmap2 */
.long sys_truncate64
.long sys_ftruncate64
.long sys_stat64 /* 195 */
.long sys_lstat64
.long sys_fstat64
.long sys_lchown
.long sys_getuid
.long sys_getgid /* 200 */
.long sys_geteuid
.long sys_getegid
.long sys_setreuid
.long sys_setregid
.long sys_getgroups /* 205 */
.long sys_setgroups
.long sys_fchown
.long sys_setresuid
.long sys_getresuid
.long sys_setresgid /* 210 */
.long sys_getresgid
.long sys_chown
.long sys_setuid
.long sys_setgid
.long sys_setfsuid /* 215 */
.long sys_setfsgid
.long sys_pivot_root
.long sys_mincore
.long sys_madvise
.long sys_getdents64 /* 220 */
.long sys_fcntl64
.long sys_ni_syscall /* reserved for TUX */
.long sys_ni_syscall
.long sys_gettid
.long sys_readahead /* 225 */
.long sys_setxattr
.long sys_lsetxattr
.long sys_fsetxattr
.long sys_getxattr
.long sys_lgetxattr /* 230 */
.long sys_fgetxattr
.long sys_listxattr
.long sys_llistxattr
.long sys_flistxattr
.long sys_removexattr /* 235 */
.long sys_lremovexattr
.long sys_fremovexattr
.long sys_tkill
.long sys_sendfile64
.long sys_futex /* 240 */
.long sys_sched_setaffinity
.long sys_sched_getaffinity
.long sys_ni_syscall /* set_thread_area */
.long sys_ni_syscall /* get_thread_area */
.long sys_io_setup /* 245 */
.long sys_io_destroy
.long sys_io_getevents
.long sys_io_submit
.long sys_io_cancel
.long sys_fadvise64 /* 250 */
.long sys_ni_syscall
.long sys_exit_group
.long sys_lookup_dcookie
.long sys_epoll_create
.long sys_epoll_ctl /* 255 */
.long sys_epoll_wait
.long sys_remap_file_pages
.long sys_set_tid_address
.long sys_timer_create
.long sys_timer_settime /* 260 */
.long sys_timer_gettime
.long sys_timer_getoverrun
.long sys_timer_delete
.long sys_clock_settime
.long sys_clock_gettime /* 265 */
.long sys_clock_getres
.long sys_clock_nanosleep
.long sys_statfs64
.long sys_fstatfs64
.long sys_tgkill /* 270 */
.long sys_utimes
.long sys_fadvise64_64
.long sys_ni_syscall /* sys_vserver */
.long sys_mbind
.long sys_get_mempolicy
.long sys_set_mempolicy
.long sys_mq_open
.long sys_mq_unlink
.long sys_mq_timedsend
.long sys_mq_timedreceive /* 280 */
.long sys_mq_notify
.long sys_mq_getsetattr
.long sys_kexec_load
.long sys_waitid
.long sys_ni_syscall /* 285 */ /* available */
.long sys_add_key
.long sys_request_key
.long sys_keyctl
.long sys_ioprio_set
.long sys_ioprio_get /* 290 */
.long sys_inotify_init
.long sys_inotify_add_watch
.long sys_inotify_rm_watch
.long sys_ni_syscall /* sys_migrate_pages */
.long sys_openat /* 295 */
.long sys_mkdirat
.long sys_mknodat
.long sys_fchownat
.long sys_ni_syscall
.long sys_fstatat64 /* 300 */
.long sys_unlinkat
.long sys_renameat
.long sys_linkat
.long sys_symlinkat
.long sys_readlinkat /* 305 */
.long sys_fchmodat
.long sys_faccessat
.long sys_ni_syscall /* pselect6 */
.long sys_ppoll
.long sys_unshare /* 310 */
.long sys_set_robust_list
.long sys_get_robust_list
.long sys_splice
.long sys_sync_file_range
.long sys_tee /* 315 */
.long sys_vmsplice
.long sys_move_pages
.long sys_getcpu
.long sys_epoll_pwait
.long sys_utimensat /* 320 */
.long sys_signalfd
.long sys_timerfd_create
.long sys_eventfd
.long sys_fallocate
.long sys_semtimedop /* 325 */
.long sys_timerfd_settime
.long sys_timerfd_gettime
.long sys_semctl
.long sys_semget
.long sys_semop /* 330 */
.long sys_msgctl
.long sys_msgget
.long sys_msgrcv
.long sys_msgsnd
.long sys_shmat /* 335 */
.long sys_shmctl
.long sys_shmdt
.long sys_shmget
.long sys_signalfd4 /* new syscall */
.long sys_eventfd2 /* 340 */
.long sys_epoll_create1
.long sys_dup3
.long sys_pipe2
.long sys_inotify_init1
.long sys_socket /* 345 */
.long sys_socketpair
.long sys_bind
.long sys_listen
.long sys_accept
.long sys_connect /* 350 */
.long sys_getsockname
.long sys_getpeername
.long sys_sendto
.long sys_send
.long sys_recvfrom /* 355 */
.long sys_recv
.long sys_setsockopt
.long sys_getsockopt
.long sys_shutdown
.long sys_sendmsg /* 360 */
.long sys_recvmsg
.long sys_ni_syscall
.long sys_ni_syscall
.long sys_ni_syscall
.long sys_rt_tgsigqueueinfo /* 365 */
.long sys_perf_event_open

View File

@@ -0,0 +1,264 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/init.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/interrupt.h>
#include <linux/profile.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>
#include <linux/bug.h>
#include <asm/cpuinfo.h>
#include <asm/setup.h>
#include <asm/prom.h>
#include <asm/irq.h>
#include <asm/system.h>
#ifdef CONFIG_SELFMOD_TIMER
#include <asm/selfmod.h>
#define TIMER_BASE BARRIER_BASE_ADDR
#else
static unsigned int timer_baseaddr;
#define TIMER_BASE timer_baseaddr
#endif
#define TCSR0 (0x00)
#define TLR0 (0x04)
#define TCR0 (0x08)
#define TCSR1 (0x10)
#define TLR1 (0x14)
#define TCR1 (0x18)
#define TCSR_MDT (1<<0)
#define TCSR_UDT (1<<1)
#define TCSR_GENT (1<<2)
#define TCSR_CAPT (1<<3)
#define TCSR_ARHT (1<<4)
#define TCSR_LOAD (1<<5)
#define TCSR_ENIT (1<<6)
#define TCSR_ENT (1<<7)
#define TCSR_TINT (1<<8)
#define TCSR_PWMA (1<<9)
#define TCSR_ENALL (1<<10)
static inline void microblaze_timer0_stop(void)
{
out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0) & ~TCSR_ENT);
}
static inline void microblaze_timer0_start_periodic(unsigned long load_val)
{
if (!load_val)
load_val = 1;
out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */
/* load the initial value */
out_be32(TIMER_BASE + TCSR0, TCSR_LOAD);
/* see timer data sheet for detail
* !ENALL - don't enable 'em all
* !PWMA - disable pwm
* TINT - clear interrupt status
* ENT- enable timer itself
* EINT - enable interrupt
* !LOAD - clear the bit to let go
* ARHT - auto reload
* !CAPT - no external trigger
* !GENT - no external signal
* UDT - set the timer as down counter
* !MDT0 - generate mode
*/
out_be32(TIMER_BASE + TCSR0,
TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
}
static inline void microblaze_timer0_start_oneshot(unsigned long load_val)
{
if (!load_val)
load_val = 1;
out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */
/* load the initial value */
out_be32(TIMER_BASE + TCSR0, TCSR_LOAD);
out_be32(TIMER_BASE + TCSR0,
TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
}
static int microblaze_timer_set_next_event(unsigned long delta,
struct clock_event_device *dev)
{
pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
microblaze_timer0_start_oneshot(delta);
return 0;
}
static void microblaze_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
printk(KERN_INFO "%s: periodic\n", __func__);
microblaze_timer0_start_periodic(cpuinfo.freq_div_hz);
break;
case CLOCK_EVT_MODE_ONESHOT:
printk(KERN_INFO "%s: oneshot\n", __func__);
break;
case CLOCK_EVT_MODE_UNUSED:
printk(KERN_INFO "%s: unused\n", __func__);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
printk(KERN_INFO "%s: shutdown\n", __func__);
microblaze_timer0_stop();
break;
case CLOCK_EVT_MODE_RESUME:
printk(KERN_INFO "%s: resume\n", __func__);
break;
}
}
static struct clock_event_device clockevent_microblaze_timer = {
.name = "microblaze_clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.shift = 24,
.rating = 300,
.set_next_event = microblaze_timer_set_next_event,
.set_mode = microblaze_timer_set_mode,
};
static inline void timer_ack(void)
{
out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0));
}
static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = &clockevent_microblaze_timer;
#ifdef CONFIG_HEART_BEAT
heartbeat();
#endif
timer_ack();
evt->event_handler(evt);
return IRQ_HANDLED;
}
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
.flags = IRQF_DISABLED | IRQF_TIMER,
.name = "timer",
.dev_id = &clockevent_microblaze_timer,
};
static __init void microblaze_clockevent_init(void)
{
clockevent_microblaze_timer.mult =
div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
clockevent_microblaze_timer.shift);
clockevent_microblaze_timer.max_delta_ns =
clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer);
clockevent_microblaze_timer.min_delta_ns =
clockevent_delta2ns(1, &clockevent_microblaze_timer);
clockevent_microblaze_timer.cpumask = cpumask_of(0);
clockevents_register_device(&clockevent_microblaze_timer);
}
static cycle_t microblaze_read(struct clocksource *cs)
{
/* reading actual value of timer 1 */
return (cycle_t) (in_be32(TIMER_BASE + TCR1));
}
static struct clocksource clocksource_microblaze = {
.name = "microblaze_clocksource",
.rating = 300,
.read = microblaze_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 24, /* I can shift it */
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static int __init microblaze_clocksource_init(void)
{
clocksource_microblaze.mult =
clocksource_hz2mult(cpuinfo.cpu_clock_freq,
clocksource_microblaze.shift);
if (clocksource_register(&clocksource_microblaze))
panic("failed to register clocksource");
/* stop timer1 */
out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT);
/* start timer1 - up counting without interrupt */
out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT);
return 0;
}
void __init time_init(void)
{
u32 irq, i = 0;
u32 timer_num = 1;
struct device_node *timer = NULL;
#ifdef CONFIG_SELFMOD_TIMER
unsigned int timer_baseaddr = 0;
int arr_func[] = {
(int)&microblaze_read,
(int)&timer_interrupt,
(int)&microblaze_clocksource_init,
(int)&microblaze_timer_set_mode,
(int)&microblaze_timer_set_next_event,
0
};
#endif
char *timer_list[] = {
"xlnx,xps-timer-1.00.a",
"xlnx,opb-timer-1.00.b",
"xlnx,opb-timer-1.00.a",
NULL
};
for (i = 0; timer_list[i] != NULL; i++) {
timer = of_find_compatible_node(NULL, NULL, timer_list[i]);
if (timer)
break;
}
BUG_ON(!timer);
timer_baseaddr = *(int *) of_get_property(timer, "reg", NULL);
timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE);
irq = *(int *) of_get_property(timer, "interrupts", NULL);
timer_num =
*(int *) of_get_property(timer, "xlnx,one-timer-only", NULL);
if (timer_num) {
printk(KERN_EMERG "Please enable two timers in HW\n");
BUG();
}
#ifdef CONFIG_SELFMOD_TIMER
selfmod_function((int *) arr_func, timer_baseaddr);
#endif
printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
timer_list[i], timer_baseaddr, irq);
cpuinfo.freq_div_hz = cpuinfo.cpu_clock_freq / HZ;
setup_irq(irq, &timer_irqaction);
#ifdef CONFIG_HEART_BEAT
setup_heartbeat();
#endif
microblaze_clocksource_init();
microblaze_clockevent_init();
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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/kallsyms.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/debug_locks.h>
#include <asm/exceptions.h>
#include <asm/system.h>
void trap_init(void)
{
__enable_hw_exceptions();
}
static int kstack_depth_to_print = 24;
static int __init kstack_setup(char *s)
{
kstack_depth_to_print = strict_strtoul(s, 0, NULL);
return 1;
}
__setup("kstack=", kstack_setup);
void show_trace(struct task_struct *task, unsigned long *stack)
{
unsigned long addr;
if (!stack)
stack = (unsigned long *)&stack;
printk(KERN_NOTICE "Call Trace: ");
#ifdef CONFIG_KALLSYMS
printk(KERN_NOTICE "\n");
#endif
while (!kstack_end(stack)) {
addr = *stack++;
/*
* If the address is either in the text segment of the
* kernel, or in the region which contains vmalloc'ed
* memory, it *may* be the address of a calling
* routine; if so, print it so that someone tracing
* down the cause of the crash will be able to figure
* out the call path that was taken.
*/
if (kernel_text_address(addr))
print_ip_sym(addr);
}
printk(KERN_NOTICE "\n");
if (!task)
task = current;
debug_show_held_locks(task);
}
void show_stack(struct task_struct *task, unsigned long *sp)
{
unsigned long *stack;
int i;
if (sp == NULL) {
if (task)
sp = (unsigned long *) ((struct thread_info *)
(task->stack))->cpu_context.r1;
else
sp = (unsigned long *)&sp;
}
stack = sp;
printk(KERN_INFO "\nStack:\n ");
for (i = 0; i < kstack_depth_to_print; i++) {
if (kstack_end(sp))
break;
if (i && ((i % 8) == 0))
printk("\n ");
printk("%08lx ", *sp++);
}
printk("\n");
show_trace(task, stack);
}
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
#ifdef CONFIG_MMU
void __bug(const char *file, int line, void *data)
{
if (data)
printk(KERN_CRIT "kernel BUG at %s:%d (data = %p)!\n",
file, line, data);
else
printk(KERN_CRIT "kernel BUG at %s:%d!\n", file, line);
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)
{
int i;
printk(KERN_CRIT "debug trap\n");
for (i = 0; i < 32; i++) {
/* printk("r%i:%08X\t",i,regs->gpr[i]); */
if ((i % 4) == 3)
printk(KERN_CRIT "\n");
}
printk(KERN_CRIT "pc:%08lX\tmsr:%08lX\n", regs->pc, regs->msr);
return -ENOSYS;
}
#endif

View File

@@ -0,0 +1,149 @@
/*
* Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2008-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, 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.
*/
OUTPUT_FORMAT("elf32-microblaze", "elf32-microblaze", "elf32-microblaze")
OUTPUT_ARCH(microblaze)
ENTRY(_start)
#include <asm/page.h>
#include <asm-generic/vmlinux.lds.h>
#include <asm/thread_info.h>
jiffies = jiffies_64 + 4;
SECTIONS {
. = CONFIG_KERNEL_START;
_start = CONFIG_KERNEL_BASE_ADDR;
.text : AT(ADDR(.text) - LOAD_OFFSET) {
_text = . ;
_stext = . ;
*(.text .text.*)
*(.fixup)
EXIT_TEXT
EXIT_CALL
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
. = ALIGN (4) ;
_etext = . ;
}
. = ALIGN (4) ;
__fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) {
_fdt_start = . ; /* place for fdt blob */
*(__fdt_blob) ; /* Any link-placed DTB */
. = _fdt_start + 0x4000; /* Pad up to 16kbyte */
_fdt_end = . ;
}
. = ALIGN(16);
RODATA
EXCEPTION_TABLE(16)
/*
* sdata2 section can go anywhere, but must be word aligned
* and SDA2_BASE must point to the middle of it
*/
.sdata2 : AT(ADDR(.sdata2) - LOAD_OFFSET) {
_ssrw = .;
. = ALIGN(4096); /* page aligned when MMU used - origin 0x8 */
*(.sdata2)
. = ALIGN(8);
_essrw = .;
_ssrw_size = _essrw - _ssrw;
_KERNEL_SDA2_BASE_ = _ssrw + (_ssrw_size / 2);
}
_sdata = . ;
RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE)
_edata = . ;
/* Reserve some low RAM for r0 based memory references */
. = ALIGN(0x4) ;
r0_ram = . ;
. = . + 4096; /* a page should be enough */
/* Under the microblaze ABI, .sdata and .sbss must be contiguous */
. = ALIGN(8);
.sdata : AT(ADDR(.sdata) - LOAD_OFFSET) {
_ssro = .;
*(.sdata)
}
.sbss : AT(ADDR(.sbss) - LOAD_OFFSET) {
_ssbss = .;
*(.sbss)
_esbss = .;
_essro = .;
_ssro_size = _essro - _ssro ;
_KERNEL_SDA_BASE_ = _ssro + (_ssro_size / 2) ;
}
__init_begin = .;
INIT_TEXT_SECTION(PAGE_SIZE)
.init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {
INIT_DATA
}
. = ALIGN(4);
.init.ivt : AT(ADDR(.init.ivt) - LOAD_OFFSET) {
__ivt_start = .;
*(.init.ivt)
__ivt_end = .;
}
.init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
INIT_SETUP(0)
}
.initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET ) {
INIT_CALLS
}
.con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
CON_INITCALL
}
SECURITY_INIT
__init_end_before_initramfs = .;
.init.ramfs ALIGN(4096) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
__initramfs_start = .;
*(.init.ramfs)
__initramfs_end = .;
. = ALIGN(4);
LONG(0);
/*
* FIXME this can break initramfs for MMU.
* Pad init.ramfs up to page boundary,
* so that __init_end == __bss_start. This will make image.elf
* consistent with the image.bin
*/
/* . = ALIGN(4096); */
}
__init_end = .;
.bss ALIGN (4096) : AT(ADDR(.bss) - LOAD_OFFSET) {
/* page aligned when MMU used */
__bss_start = . ;
*(.bss*)
*(COMMON)
. = ALIGN (4) ;
__bss_stop = . ;
_ebss = . ;
}
. = ALIGN(4096);
_end = .;
DISCARDS
}