diff options
Diffstat (limited to 'arch/h8300/kernel')
-rw-r--r-- | arch/h8300/kernel/Makefile | 11 | ||||
-rw-r--r-- | arch/h8300/kernel/asm-offsets.c | 65 | ||||
-rw-r--r-- | arch/h8300/kernel/gpio.c | 174 | ||||
-rw-r--r-- | arch/h8300/kernel/h8300_ksyms.c | 112 | ||||
-rw-r--r-- | arch/h8300/kernel/init_task.c | 43 | ||||
-rw-r--r-- | arch/h8300/kernel/ints.c | 255 | ||||
-rw-r--r-- | arch/h8300/kernel/module.c | 122 | ||||
-rw-r--r-- | arch/h8300/kernel/process.c | 288 | ||||
-rw-r--r-- | arch/h8300/kernel/ptrace.c | 277 | ||||
-rw-r--r-- | arch/h8300/kernel/semaphore.c | 133 | ||||
-rw-r--r-- | arch/h8300/kernel/setup.c | 248 | ||||
-rw-r--r-- | arch/h8300/kernel/signal.c | 552 | ||||
-rw-r--r-- | arch/h8300/kernel/sys_h8300.c | 282 | ||||
-rw-r--r-- | arch/h8300/kernel/syscalls.S | 340 | ||||
-rw-r--r-- | arch/h8300/kernel/time.c | 134 | ||||
-rw-r--r-- | arch/h8300/kernel/traps.c | 169 | ||||
-rw-r--r-- | arch/h8300/kernel/vmlinux.lds.S | 172 |
17 files changed, 3377 insertions, 0 deletions
diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile new file mode 100644 index 00000000000..71b6131e98b --- /dev/null +++ b/arch/h8300/kernel/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the linux kernel. +# + +extra-y := vmlinux.lds + +obj-y := process.o traps.o ptrace.o ints.o \ + sys_h8300.o time.o semaphore.o signal.o \ + setup.o gpio.o init_task.o syscalls.o + +obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o diff --git a/arch/h8300/kernel/asm-offsets.c b/arch/h8300/kernel/asm-offsets.c new file mode 100644 index 00000000000..b78b82ad28a --- /dev/null +++ b/arch/h8300/kernel/asm-offsets.c @@ -0,0 +1,65 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + */ + +#include <linux/stddef.h> +#include <linux/sched.h> +#include <linux/kernel_stat.h> +#include <linux/ptrace.h> +#include <linux/hardirq.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/ptrace.h> + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + /* offsets into the task struct */ + DEFINE(TASK_STATE, offsetof(struct task_struct, state)); + DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); + DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); + DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); + DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info)); + DEFINE(TASK_MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); + + /* offsets into the irq_cpustat_t struct */ + DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); + + /* offsets into the thread struct */ + DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); + DEFINE(THREAD_USP, offsetof(struct thread_struct, usp)); + DEFINE(THREAD_CCR, offsetof(struct thread_struct, ccr)); + + /* offsets into the pt_regs struct */ + DEFINE(LER0, offsetof(struct pt_regs, er0) - sizeof(long)); + DEFINE(LER1, offsetof(struct pt_regs, er1) - sizeof(long)); + DEFINE(LER2, offsetof(struct pt_regs, er2) - sizeof(long)); + DEFINE(LER3, offsetof(struct pt_regs, er3) - sizeof(long)); + DEFINE(LER4, offsetof(struct pt_regs, er4) - sizeof(long)); + DEFINE(LER5, offsetof(struct pt_regs, er5) - sizeof(long)); + DEFINE(LER6, offsetof(struct pt_regs, er6) - sizeof(long)); + DEFINE(LORIG, offsetof(struct pt_regs, orig_er0) - sizeof(long)); + DEFINE(LCCR, offsetof(struct pt_regs, ccr) - sizeof(long)); + DEFINE(LVEC, offsetof(struct pt_regs, vector) - sizeof(long)); +#if defined(__H8300S__) + DEFINE(LEXR, offsetof(struct pt_regs, exr) - sizeof(long)); +#endif + DEFINE(LRET, offsetof(struct pt_regs, pc) - sizeof(long)); + + DEFINE(PT_PTRACED, PT_PTRACED); + DEFINE(PT_DTRACE, PT_DTRACE); + + return 0; +} diff --git a/arch/h8300/kernel/gpio.c b/arch/h8300/kernel/gpio.c new file mode 100644 index 00000000000..795682b873e --- /dev/null +++ b/arch/h8300/kernel/gpio.c @@ -0,0 +1,174 @@ +/* + * linux/arch/h8300/kernel/gpio.c + * + * Yoshinori Sato <ysato@users.sourceforge.jp> + * + */ + +/* + * Internal I/O Port Management + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/proc_fs.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/fs.h> +#include <linux/init.h> + +#define _(addr) (volatile unsigned char *)(addr) +#if defined(CONFIG_H83007) || defined(CONFIG_H83068) +#include <asm/regs306x.h> +static volatile unsigned char *ddrs[] = { + _(P1DDR),_(P2DDR),_(P3DDR),_(P4DDR),_(P5DDR),_(P6DDR), + NULL, _(P8DDR),_(P9DDR),_(PADDR),_(PBDDR), +}; +#define MAX_PORT 11 +#endif + + #if defined(CONFIG_H83002) || defined(CONFIG_H8048) +/* Fix me!! */ +#include <asm/regs306x.h> +static volatile unsigned char *ddrs[] = { + _(P1DDR),_(P2DDR),_(P3DDR),_(P4DDR),_(P5DDR),_(P6DDR), + NULL, _(P8DDR),_(P9DDR),_(PADDR),_(PBDDR), +}; +#define MAX_PORT 11 +#endif + +#if defined(CONFIG_H8S2678) +#include <asm/regs267x.h> +static volatile unsigned char *ddrs[] = { + _(P1DDR),_(P2DDR),_(P3DDR),NULL ,_(P5DDR),_(P6DDR), + _(P7DDR),_(P8DDR),NULL, _(PADDR),_(PBDDR),_(PCDDR), + _(PDDDR),_(PEDDR),_(PFDDR),_(PGDDR),_(PHDDR), + _(PADDR),_(PBDDR),_(PCDDR),_(PDDDR),_(PEDDR),_(PFDDR), + _(PGDDR),_(PHDDR) +}; +#define MAX_PORT 17 +#endif +#undef _ + +#if !defined(P1DDR) +#error Unsuppoted CPU Selection +#endif + +static struct { + unsigned char used; + unsigned char ddr; +} gpio_regs[MAX_PORT]; + +extern char *_platform_gpio_table(int length); + +int h8300_reserved_gpio(int port, unsigned int bits) +{ + unsigned char *used; + + if (port < 0 || port >= MAX_PORT) + return -1; + used = &(gpio_regs[port].used); + if ((*used & bits) != 0) + return 0; + *used |= bits; + return 1; +} + +int h8300_free_gpio(int port, unsigned int bits) +{ + unsigned char *used; + + if (port < 0 || port >= MAX_PORT) + return -1; + used = &(gpio_regs[port].used); + if ((*used & bits) != bits) + return 0; + *used &= (~bits); + return 1; +} + +int h8300_set_gpio_dir(int port_bit,int dir) +{ + int port = (port_bit >> 8) & 0xff; + int bit = port_bit & 0xff; + + if (ddrs[port] == NULL) + return 0; + if (gpio_regs[port].used & bit) { + if (dir) + gpio_regs[port].ddr |= bit; + else + gpio_regs[port].ddr &= ~bit; + *ddrs[port] = gpio_regs[port].ddr; + return 1; + } else + return 0; +} + +int h8300_get_gpio_dir(int port_bit) +{ + int port = (port_bit >> 8) & 0xff; + int bit = port_bit & 0xff; + + if (ddrs[port] == NULL) + return 0; + if (gpio_regs[port].used & bit) { + return (gpio_regs[port].ddr & bit) != 0; + } else + return -1; +} + +#if defined(CONFIG_PROC_FS) +static char *port_status(int portno) +{ + static char result[10]; + const static char io[2]={'I','O'}; + char *rp; + int c; + unsigned char used,ddr; + + used = gpio_regs[portno].used; + ddr = gpio_regs[portno].ddr; + result[8]='\0'; + rp = result + 7; + for (c = 8; c > 0; c--,rp--,used >>= 1, ddr >>= 1) + if (used & 0x01) + *rp = io[ ddr & 0x01]; + else + *rp = '-'; + return result; +} + +static int gpio_proc_read(char *buf, char **start, off_t offset, + int len, int *unused_i, void *unused_v) +{ + int c,outlen; + const static char port_name[]="123456789ABCDEFGH"; + outlen = 0; + for (c = 0; c < MAX_PORT; c++) { + if (ddrs[c] == NULL) + continue ; + len = sprintf(buf,"P%c: %s\n",port_name[c],port_status(c)); + buf += len; + outlen += len; + } + return outlen; +} + +static __init int register_proc(void) +{ + struct proc_dir_entry *proc_gpio; + + proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL); + if (proc_gpio) + proc_gpio->read_proc = gpio_proc_read; + return proc_gpio != NULL; +} + +__initcall(register_proc); +#endif + +void __init h8300_gpio_init(void) +{ + memcpy(gpio_regs,_platform_gpio_table(sizeof(gpio_regs)),sizeof(gpio_regs)); +} diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c new file mode 100644 index 00000000000..5a630233112 --- /dev/null +++ b/arch/h8300/kernel/h8300_ksyms.c @@ -0,0 +1,112 @@ +#include <linux/module.h> +#include <linux/linkage.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/user.h> +#include <linux/elfcore.h> +#include <linux/in6.h> +#include <linux/interrupt.h> +#include <linux/config.h> + +#include <asm/setup.h> +#include <asm/pgalloc.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/semaphore.h> +#include <asm/checksum.h> +#include <asm/current.h> +#include <asm/gpio.h> + +//asmlinkage long long __ashrdi3 (long long, int); +//asmlinkage long long __lshrdi3 (long long, int); +extern char h8300_debug_device[]; + +extern void dump_thread(struct pt_regs *, struct user *); + +/* platform dependent support */ + +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); + +EXPORT_SYMBOL(ip_fast_csum); + +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); + +/* The following are special because they're not called + explicitly (the C compiler generates them). Fortunately, + their interface isn't gonna change any time soon now, so + it's OK to leave it out of version control. */ +//EXPORT_SYMBOL(__ashrdi3); +//EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memmove); + +EXPORT_SYMBOL(get_wchan); + +/* + * 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 __gcc_bcmp(void); +extern void __ashldi3(void); +extern void __ashrdi3(void); +extern void __cmpdi2(void); +extern void __divdi3(void); +extern void __divsi3(void); +extern void __lshrdi3(void); +extern void __moddi3(void); +extern void __modsi3(void); +extern void __muldi3(void); +extern void __mulsi3(void); +extern void __negdi2(void); +extern void __ucmpdi2(void); +extern void __udivdi3(void); +extern void __udivmoddi4(void); +extern void __udivsi3(void); +extern void __umoddi3(void); +extern void __umodsi3(void); + + /* gcc lib functions */ +EXPORT_SYMBOL(__gcc_bcmp); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__cmpdi2); +EXPORT_SYMBOL(__divdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__moddi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__mulsi3); +EXPORT_SYMBOL(__negdi2); +EXPORT_SYMBOL(__ucmpdi2); +EXPORT_SYMBOL(__udivdi3); +EXPORT_SYMBOL(__udivmoddi4); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umoddi3); +EXPORT_SYMBOL(__umodsi3); + +#ifdef MAGIC_ROM_PTR +EXPORT_SYMBOL(is_in_rom); +#endif + +EXPORT_SYMBOL(h8300_reserved_gpio); +EXPORT_SYMBOL(h8300_free_gpio); +EXPORT_SYMBOL(h8300_set_gpio_dir); diff --git a/arch/h8300/kernel/init_task.c b/arch/h8300/kernel/init_task.c new file mode 100644 index 00000000000..19272c2ac56 --- /dev/null +++ b/arch/h8300/kernel/init_task.c @@ -0,0 +1,43 @@ +/* + * linux/arch/h8300/kernel/init_task.c + */ +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/init_task.h> +#include <linux/fs.h> +#include <linux/mqueue.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +struct mm_struct init_mm = INIT_MM(init_mm); + +EXPORT_SYMBOL(init_mm); + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +__asm__(".align 4"); +struct task_struct init_task = INIT_TASK(init_task); + +EXPORT_SYMBOL(init_task); + +/* + * Initial thread structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + diff --git a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c new file mode 100644 index 00000000000..edb3c417001 --- /dev/null +++ b/arch/h8300/kernel/ints.c @@ -0,0 +1,255 @@ +/* + * linux/arch/h8300/platform/h8300h/ints.c + * + * Yoshinori Sato <ysato@users.sourceforge.jp> + * + * Based on linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.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. + * + * Copyright 1996 Roman Zippel + * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com> + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/kernel_stat.h> +#include <linux/seq_file.h> +#include <linux/init.h> +#include <linux/random.h> +#include <linux/bootmem.h> +#include <linux/hardirq.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/traps.h> +#include <asm/io.h> +#include <asm/setup.h> +#include <asm/errno.h> + +/* + * This structure has only 4 elements for speed reasons + */ +typedef struct irq_handler { + irqreturn_t (*handler)(int, void *, struct pt_regs *); + int flags; + int count; + void *dev_id; + const char *devname; +} irq_handler_t; + +static irq_handler_t *irq_list[NR_IRQS]; +static int use_kmalloc; + +extern unsigned long *interrupt_redirect_table; +extern const int h8300_saved_vectors[]; +extern const unsigned long h8300_trap_table[]; +int h8300_enable_irq_pin(unsigned int irq); +void h8300_disable_irq_pin(unsigned int irq); + +#define CPU_VECTOR ((unsigned long *)0x000000) +#define ADDR_MASK (0xffffff) + +#if defined(CONFIG_RAMKERNEL) +static unsigned long __init *get_vector_address(void) +{ + unsigned long *rom_vector = CPU_VECTOR; + unsigned long base,tmp; + int vec_no; + + base = rom_vector[EXT_IRQ0] & ADDR_MASK; + + /* check romvector format */ + for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) { + if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK)) + return NULL; + } + + /* ramvector base address */ + base -= EXT_IRQ0*4; + + /* writerble check */ + tmp = ~(*(volatile unsigned long *)base); + (*(volatile unsigned long *)base) = tmp; + if ((*(volatile unsigned long *)base) != tmp) + return NULL; + return (unsigned long *)base; +} +#endif + +void __init init_IRQ(void) +{ +#if defined(CONFIG_RAMKERNEL) + int i; + unsigned long *ramvec,*ramvec_p; + const unsigned long *trap_entry; + const int *saved_vector; + + ramvec = get_vector_address(); + if (ramvec == NULL) + panic("interrupt vector serup failed."); + else + printk(KERN_INFO "virtual vector at 0x%08lx\n",(unsigned long)ramvec); + + /* create redirect table */ + ramvec_p = ramvec; + trap_entry = h8300_trap_table; + saved_vector = h8300_saved_vectors; + for ( i = 0; i < NR_IRQS; i++) { + if (i == *saved_vector) { + ramvec_p++; + saved_vector++; + } else { + if ( i < NR_TRAPS ) { + if (*trap_entry) + *ramvec_p = VECTOR(*trap_entry); + ramvec_p++; + trap_entry++; + } else + *ramvec_p++ = REDIRECT(interrupt_entry); + } + } + interrupt_redirect_table = ramvec; +#ifdef DUMP_VECTOR + ramvec_p = ramvec; + for (i = 0; i < NR_IRQS; i++) { + if ((i % 8) == 0) + printk(KERN_DEBUG "\n%p: ",ramvec_p); + printk(KERN_DEBUG "%p ",*ramvec_p); + ramvec_p++; + } + printk(KERN_DEBUG "\n"); +#endif +#endif +} + +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + irq_handler_t *irq_handle; + if (irq < 0 || irq >= NR_IRQS) { + printk(KERN_ERR "Incorrect IRQ %d from %s\n", irq, devname); + return -EINVAL; + } + + if (irq_list[irq] || (h8300_enable_irq_pin(irq) == -EBUSY)) + return -EBUSY; + + if (use_kmalloc) + irq_handle = (irq_handler_t *)kmalloc(sizeof(irq_handler_t), GFP_ATOMIC); + else { + /* use bootmem allocater */ + irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t)); + irq_handle = (irq_handler_t *)((unsigned long)irq_handle | 0x80000000); + } + + if (irq_handle == NULL) + return -ENOMEM; + + irq_handle->handler = handler; + irq_handle->flags = flags; + irq_handle->count = 0; + irq_handle->dev_id = dev_id; + irq_handle->devname = devname; + irq_list[irq] = irq_handle; + + if (irq_handle->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + enable_irq(irq); + return 0; +} + +EXPORT_SYMBOL(request_irq); + +void free_irq(unsigned int irq, void *dev_id) +{ + if (irq >= NR_IRQS) + return; + + if (!irq_list[irq] || irq_list[irq]->dev_id != dev_id) + printk(KERN_WARNING "Removing probably wrong IRQ %d from %s\n", + irq, irq_list[irq]->devname); + disable_irq(irq); + h8300_disable_irq_pin(irq); + if (((unsigned long)irq_list[irq] & 0x80000000) == 0) { + kfree(irq_list[irq]); + irq_list[irq] = NULL; + } +} + +EXPORT_SYMBOL(free_irq); + +/* + * Do we need these probe functions on the m68k? + */ +unsigned long probe_irq_on (void) +{ + return 0; +} + +EXPORT_SYMBOL(probe_irq_on); + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + +EXPORT_SYMBOL(probe_irq_off); + +void enable_irq(unsigned int irq) +{ + if (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS)) + IER_REGS |= 1 << (irq - EXT_IRQ0); +} + +void disable_irq(unsigned int irq) +{ + if (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS)) + IER_REGS &= ~(1 << (irq - EXT_IRQ0)); +} + +asmlinkage void process_int(int irq, struct pt_regs *fp) +{ + irq_enter(); + h8300_clear_isr(irq); + if (irq >= NR_TRAPS && irq < NR_IRQS) { + if (irq_list[irq]) { + irq_list[irq]->handler(irq, irq_list[irq]->dev_id, fp); + irq_list[irq]->count++; + if (irq_list[irq]->flags & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + } + } else { + BUG(); + } + irq_exit(); +} + +int show_interrupts(struct seq_file *p, void *v) +{ + int i = *(loff_t *) v; + + if ((i < NR_IRQS) && (irq_list[i]!=NULL)) { + seq_printf(p, "%3d: %10u ",i,irq_list[i]->count); + seq_printf(p, "%s\n", irq_list[i]->devname); + } + + return 0; +} + +void init_irq_proc(void) +{ +} + +static int __init enable_kmalloc(void) +{ + use_kmalloc = 1; + return 0; +} +core_initcall(enable_kmalloc); diff --git a/arch/h8300/kernel/module.c b/arch/h8300/kernel/module.c new file mode 100644 index 00000000000..4fd7138a6e0 --- /dev/null +++ b/arch/h8300/kernel/module.c @@ -0,0 +1,122 @@ +#include <linux/moduleloader.h> +#include <linux/elf.h> +#include <linux/vmalloc.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt...) +#endif + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +/* We don't need anything special. */ +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 *me) +{ + printk(KERN_ERR "module %s: RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; + + DEBUGP("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { + /* This is where to make the change */ + uint32_t *loc = (uint32_t *)(sechdrs[sechdrs[relsec].sh_info].sh_addr + + rela[i].r_offset); + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + Elf32_Sym *sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rela[i].r_info); + uint32_t v = sym->st_value + rela[i].r_addend; + + switch (ELF32_R_TYPE(rela[i].r_info)) { + case R_H8_DIR24R8: + loc = (uint32_t *)((uint32_t)loc - 1); + *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v); + break; + case R_H8_DIR24A8: + if (ELF32_R_SYM(rela[i].r_info)) + *loc += v; + break; + case R_H8_DIR32: + case R_H8_DIR32A16: + *loc += v; + break; + case R_H8_PCREL16: + v -= (unsigned long)loc + 2; + if ((Elf32_Sword)v > 0x7fff || + (Elf32_Sword)v < -(Elf32_Sword)0x8000) + goto overflow; + else + *(unsigned short *)loc = v; + break; + case R_H8_PCREL8: + v -= (unsigned long)loc + 1; + if ((Elf32_Sword)v > 0x7f || + (Elf32_Sword)v < -(Elf32_Sword)0x80) + goto overflow; + else + *(unsigned char *)loc = v; + break; + default: + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + me->name, ELF32_R_TYPE(rela[i].r_info)); + return -ENOEXEC; + } + } + return 0; + overflow: + printk(KERN_ERR "module %s: relocation offset overflow: %08x\n", + me->name, rela[i].r_offset); + return -ENOEXEC; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c new file mode 100644 index 00000000000..134aec1c6d1 --- /dev/null +++ b/arch/h8300/kernel/process.c @@ -0,0 +1,288 @@ +/* + * linux/arch/h8300/kernel/process.c + * + * Yoshinori Sato <ysato@users.sourceforge.jp> + * + * Based on: + * + * linux/arch/m68knommu/kernel/process.c + * + * Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, + * Kenneth Albanowski <kjahds@kjahds.com>, + * The Silver Hammer Group, Ltd. + * + * linux/arch/m68k/kernel/process.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * 68060 fixes by Jesper Skov + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/user.h> +#include <linux/a.out.h> +#include <linux/interrupt.h> +#include <linux/reboot.h> + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/traps.h> +#include <asm/setup.h> +#include <asm/pgtable.h> + +asmlinkage void ret_from_fork(void); + +/* + * The idle loop on an H8/300.. + */ +#if !defined(CONFIG_H8300H_SIM) && !defined(CONFIG_H8S_SIM) +void default_idle(void) +{ + while(1) { + if (need_resched()) { + local_irq_enable(); + __asm__("sleep"); + local_irq_disable(); + } + schedule(); + } +} +#else +void default_idle(void) +{ + while(1) { + if (need_resched()) + schedule(); + } +} +#endif +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + idle(); +} + +void machine_restart(char * __unused) +{ + local_irq_disable(); + __asm__("jmp @@0"); +} + +EXPORT_SYMBOL(machine_restart); + +void machine_halt(void) +{ + local_irq_disable(); + __asm__("sleep"); + for (;;); +} + +EXPORT_SYMBOL(machine_halt); + +void machine_power_off(void) +{ + local_irq_disable(); + __asm__("sleep"); + for (;;); +} + +EXPORT_SYMBOL(machine_power_off); + +void show_regs(struct pt_regs * regs) +{ + printk("\nPC: %08lx Status: %02x", + regs->pc, regs->ccr); + printk("\nORIG_ER0: %08lx ER0: %08lx ER1: %08lx", + regs->orig_er0, regs->er0, regs->er1); + printk("\nER2: %08lx ER3: %08lx ER4: %08lx ER5: %08lx", + regs->er2, regs->er3, regs->er4, regs->er5); + printk("\nER6' %08lx ",regs->er6); + if (user_mode(regs)) + printk("USP: %08lx\n", rdusp()); + else + printk("\n"); +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval; + long clone_arg; + mm_segment_t fs; + + fs = get_fs(); + set_fs (KERNEL_DS); + clone_arg = flags | CLONE_VM; + __asm__("mov.l sp,er3\n\t" + "sub.l er2,er2\n\t" + "mov.l %2,er1\n\t" + "mov.l %1,er0\n\t" + "trapa #0\n\t" + "cmp.l sp,er3\n\t" + "beq 1f\n\t" + "mov.l %4,er0\n\t" + "mov.l %3,er1\n\t" + "jsr @er1\n\t" + "mov.l %5,er0\n\t" + "trapa #0\n" + "1:\n\t" + "mov.l er0,%0" + :"=r"(retval) + :"i"(__NR_clone),"g"(clone_arg),"g"(fn),"g"(arg),"i"(__NR_exit) + :"er0","er1","er2","er3"); + set_fs (fs); + return retval; +} + +void flush_thread(void) +{ +} + +/* + * "h8300_fork()".. By the time we get here, the + * non-volatile registers have also been saved on the + * stack. We do some ugly pointer stuff here.. (see + * also copy_thread) + */ + +asmlinkage int h8300_fork(struct pt_regs *regs) +{ + return -EINVAL; +} + +asmlinkage int h8300_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); +} + +asmlinkage int h8300_clone(struct pt_regs *regs) +{ + unsigned long clone_flags; + unsigned long newsp; + + /* syscall2 puts clone_flags in er1 and usp in er2 */ + clone_flags = regs->er1; + newsp = regs->er2; + if (!newsp) + newsp = rdusp(); + return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); + +} + +int copy_thread(int nr, unsigned long clone_flags, + unsigned long usp, unsigned long topstk, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + + childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1; + + *childregs = *regs; + childregs->retpc = (unsigned long) ret_from_fork; + childregs->er0 = 0; + + p->thread.usp = usp; + p->thread.ksp = (unsigned long)childregs; + + return 0; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ +/* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = rdusp() & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + + dump->u_ar0 = (struct user_regs_struct *)(((int)(&dump->regs)) -((int)(dump))); + dump->regs.er0 = regs->er0; + dump->regs.er1 = regs->er1; + dump->regs.er2 = regs->er2; + dump->regs.er3 = regs->er3; + dump->regs.er4 = regs->er4; + dump->regs.er5 = regs->er5; + dump->regs.er6 = regs->er6; + dump->regs.orig_er0 = regs->orig_er0; + dump->regs.ccr = regs->ccr; + dump->regs.pc = regs->pc; +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(char *name, char **argv, char **envp,int dummy,...) +{ + int error; + char * filename; + struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4); + + lock_kernel(); + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); +out: + unlock_kernel(); + return error; +} + +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + return ((struct pt_regs *)tsk->thread.esp0)->pc; +} + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)p; + fp = ((struct pt_regs *)p->thread.ksp)->er6; |