diff options
author | Yoshinori Sato <ysato@users.sourceforge.jp> | 2015-01-27 12:46:20 -0500 |
---|---|---|
committer | Yoshinori Sato <ysato@users.sourceforge.jp> | 2015-06-23 00:35:53 -0400 |
commit | 4e0c20981ec16d13cfebaad7ed6245a472df2ed0 (patch) | |
tree | f576a7dfabb2541731d451248beb1f94bf6055d2 | |
parent | fe54616d857da4ccb482eb40fef0e0f3b3d0efaf (diff) |
h8300: miscellaneous functions
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
-rw-r--r-- | arch/h8300/kernel/asm-offsets.c | 67 | ||||
-rw-r--r-- | arch/h8300/kernel/dma.c | 69 | ||||
-rw-r--r-- | arch/h8300/kernel/h8300_ksyms.c | 36 | ||||
-rw-r--r-- | arch/h8300/kernel/module.c | 70 | ||||
-rw-r--r-- | arch/h8300/kernel/sim-console.c | 79 | ||||
-rw-r--r-- | arch/h8300/kernel/syscalls.c | 14 |
6 files changed, 335 insertions, 0 deletions
diff --git a/arch/h8300/kernel/asm-offsets.c b/arch/h8300/kernel/asm-offsets.c new file mode 100644 index 000000000000..dc2d16ce8a0d --- /dev/null +++ b/arch/h8300/kernel/asm-offsets.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * This program is used to generate definitions needed by | ||
3 | * assembly language modules. | ||
4 | * | ||
5 | * We use the technique used in the OSF Mach kernel code: | ||
6 | * generate asm statements containing #defines, | ||
7 | * compile this file to assembler, and then extract the | ||
8 | * #defines from the assembly-language output. | ||
9 | */ | ||
10 | |||
11 | #include <linux/stddef.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/kernel_stat.h> | ||
14 | #include <linux/ptrace.h> | ||
15 | #include <linux/hardirq.h> | ||
16 | #include <linux/kbuild.h> | ||
17 | #include <asm/irq.h> | ||
18 | #include <asm/ptrace.h> | ||
19 | |||
20 | int main(void) | ||
21 | { | ||
22 | /* offsets into the task struct */ | ||
23 | OFFSET(TASK_STATE, task_struct, state); | ||
24 | OFFSET(TASK_FLAGS, task_struct, flags); | ||
25 | OFFSET(TASK_PTRACE, task_struct, ptrace); | ||
26 | OFFSET(TASK_BLOCKED, task_struct, blocked); | ||
27 | OFFSET(TASK_THREAD, task_struct, thread); | ||
28 | OFFSET(TASK_THREAD_INFO, task_struct, stack); | ||
29 | OFFSET(TASK_MM, task_struct, mm); | ||
30 | OFFSET(TASK_ACTIVE_MM, task_struct, active_mm); | ||
31 | |||
32 | /* offsets into the irq_cpustat_t struct */ | ||
33 | DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, | ||
34 | __softirq_pending)); | ||
35 | |||
36 | /* offsets into the thread struct */ | ||
37 | OFFSET(THREAD_KSP, thread_struct, ksp); | ||
38 | OFFSET(THREAD_USP, thread_struct, usp); | ||
39 | OFFSET(THREAD_CCR, thread_struct, ccr); | ||
40 | |||
41 | /* offsets into the pt_regs struct */ | ||
42 | DEFINE(LER0, offsetof(struct pt_regs, er0) - sizeof(long)); | ||
43 | DEFINE(LER1, offsetof(struct pt_regs, er1) - sizeof(long)); | ||
44 | DEFINE(LER2, offsetof(struct pt_regs, er2) - sizeof(long)); | ||
45 | DEFINE(LER3, offsetof(struct pt_regs, er3) - sizeof(long)); | ||
46 | DEFINE(LER4, offsetof(struct pt_regs, er4) - sizeof(long)); | ||
47 | DEFINE(LER5, offsetof(struct pt_regs, er5) - sizeof(long)); | ||
48 | DEFINE(LER6, offsetof(struct pt_regs, er6) - sizeof(long)); | ||
49 | DEFINE(LORIG, offsetof(struct pt_regs, orig_er0) - sizeof(long)); | ||
50 | DEFINE(LSP, offsetof(struct pt_regs, sp) - sizeof(long)); | ||
51 | DEFINE(LCCR, offsetof(struct pt_regs, ccr) - sizeof(long)); | ||
52 | DEFINE(LVEC, offsetof(struct pt_regs, vector) - sizeof(long)); | ||
53 | #if defined(CONFIG_CPU_H8S) | ||
54 | DEFINE(LEXR, offsetof(struct pt_regs, exr) - sizeof(long)); | ||
55 | #endif | ||
56 | DEFINE(LRET, offsetof(struct pt_regs, pc) - sizeof(long)); | ||
57 | |||
58 | DEFINE(PT_PTRACED, PT_PTRACED); | ||
59 | |||
60 | /* offsets in thread_info structure */ | ||
61 | OFFSET(TI_TASK, thread_info, task); | ||
62 | OFFSET(TI_FLAGS, thread_info, flags); | ||
63 | OFFSET(TI_CPU, thread_info, cpu); | ||
64 | OFFSET(TI_PRE, thread_info, preempt_count); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
diff --git a/arch/h8300/kernel/dma.c b/arch/h8300/kernel/dma.c new file mode 100644 index 000000000000..eeb13d3f2424 --- /dev/null +++ b/arch/h8300/kernel/dma.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file COPYING in the main directory of this archive | ||
4 | * for more details. | ||
5 | */ | ||
6 | |||
7 | #include <linux/dma-mapping.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/scatterlist.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <asm/pgalloc.h> | ||
12 | |||
13 | static void *dma_alloc(struct device *dev, size_t size, | ||
14 | dma_addr_t *dma_handle, gfp_t gfp, | ||
15 | struct dma_attrs *attrs) | ||
16 | { | ||
17 | void *ret; | ||
18 | |||
19 | /* ignore region specifiers */ | ||
20 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); | ||
21 | |||
22 | if (dev == NULL || (*dev->dma_mask < 0xffffffff)) | ||
23 | gfp |= GFP_DMA; | ||
24 | ret = (void *)__get_free_pages(gfp, get_order(size)); | ||
25 | |||
26 | if (ret != NULL) { | ||
27 | memset(ret, 0, size); | ||
28 | *dma_handle = virt_to_phys(ret); | ||
29 | } | ||
30 | return ret; | ||
31 | } | ||
32 | |||
33 | static void dma_free(struct device *dev, size_t size, | ||
34 | void *vaddr, dma_addr_t dma_handle, | ||
35 | struct dma_attrs *attrs) | ||
36 | |||
37 | { | ||
38 | free_pages((unsigned long)vaddr, get_order(size)); | ||
39 | } | ||
40 | |||
41 | static dma_addr_t map_page(struct device *dev, struct page *page, | ||
42 | unsigned long offset, size_t size, | ||
43 | enum dma_data_direction direction, | ||
44 | struct dma_attrs *attrs) | ||
45 | { | ||
46 | return page_to_phys(page) + offset; | ||
47 | } | ||
48 | |||
49 | static int map_sg(struct device *dev, struct scatterlist *sgl, | ||
50 | int nents, enum dma_data_direction direction, | ||
51 | struct dma_attrs *attrs) | ||
52 | { | ||
53 | struct scatterlist *sg; | ||
54 | int i; | ||
55 | |||
56 | for_each_sg(sgl, sg, nents, i) { | ||
57 | sg->dma_address = sg_phys(sg); | ||
58 | } | ||
59 | |||
60 | return nents; | ||
61 | } | ||
62 | |||
63 | struct dma_map_ops h8300_dma_map_ops = { | ||
64 | .alloc = dma_alloc, | ||
65 | .free = dma_free, | ||
66 | .map_page = map_page, | ||
67 | .map_sg = map_sg, | ||
68 | }; | ||
69 | EXPORT_SYMBOL(h8300_dma_map_ops); | ||
diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c new file mode 100644 index 000000000000..a9033c838968 --- /dev/null +++ b/arch/h8300/kernel/h8300_ksyms.c | |||
@@ -0,0 +1,36 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/linkage.h> | ||
3 | |||
4 | /* | ||
5 | * libgcc functions - functions that are used internally by the | ||
6 | * compiler... (prototypes are not correct though, but that | ||
7 | * doesn't really matter since they're not versioned). | ||
8 | */ | ||
9 | asmlinkage long __ucmpdi2(long long, long long); | ||
10 | asmlinkage long long __ashldi3(long long, int); | ||
11 | asmlinkage long long __ashrdi3(long long, int); | ||
12 | asmlinkage long long __lshrdi3(long long, int); | ||
13 | asmlinkage long __divsi3(long, long); | ||
14 | asmlinkage long __modsi3(long, long); | ||
15 | asmlinkage unsigned long __umodsi3(unsigned long, unsigned long); | ||
16 | asmlinkage long long __muldi3(long long, long long); | ||
17 | asmlinkage long __mulsi3(long, long); | ||
18 | asmlinkage long __udivsi3(long, long); | ||
19 | asmlinkage void *memcpy(void *, const void *, size_t); | ||
20 | asmlinkage void *memset(void *, int, size_t); | ||
21 | asmlinkage long strncpy_from_user(void *to, void *from, size_t n); | ||
22 | |||
23 | /* gcc lib functions */ | ||
24 | EXPORT_SYMBOL(__ucmpdi2); | ||
25 | EXPORT_SYMBOL(__ashldi3); | ||
26 | EXPORT_SYMBOL(__ashrdi3); | ||
27 | EXPORT_SYMBOL(__lshrdi3); | ||
28 | EXPORT_SYMBOL(__divsi3); | ||
29 | EXPORT_SYMBOL(__modsi3); | ||
30 | EXPORT_SYMBOL(__umodsi3); | ||
31 | EXPORT_SYMBOL(__muldi3); | ||
32 | EXPORT_SYMBOL(__mulsi3); | ||
33 | EXPORT_SYMBOL(__udivsi3); | ||
34 | EXPORT_SYMBOL(memcpy); | ||
35 | EXPORT_SYMBOL(memset); | ||
36 | EXPORT_SYMBOL(strncpy_from_user); | ||
diff --git a/arch/h8300/kernel/module.c b/arch/h8300/kernel/module.c new file mode 100644 index 000000000000..515f6c4e8d80 --- /dev/null +++ b/arch/h8300/kernel/module.c | |||
@@ -0,0 +1,70 @@ | |||
1 | #include <linux/moduleloader.h> | ||
2 | #include <linux/elf.h> | ||
3 | #include <linux/vmalloc.h> | ||
4 | #include <linux/fs.h> | ||
5 | #include <linux/string.h> | ||
6 | #include <linux/kernel.h> | ||
7 | |||
8 | int apply_relocate_add(Elf32_Shdr *sechdrs, | ||
9 | const char *strtab, | ||
10 | unsigned int symindex, | ||
11 | unsigned int relsec, | ||
12 | struct module *me) | ||
13 | { | ||
14 | unsigned int i; | ||
15 | Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; | ||
16 | |||
17 | pr_debug("Applying relocate section %u to %u\n", relsec, | ||
18 | sechdrs[relsec].sh_info); | ||
19 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { | ||
20 | /* This is where to make the change */ | ||
21 | uint32_t *loc = | ||
22 | (uint32_t *)(sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
23 | + rela[i].r_offset); | ||
24 | /* This is the symbol it is referring to. Note that all | ||
25 | undefined symbols have been resolved. */ | ||
26 | Elf32_Sym *sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | ||
27 | + ELF32_R_SYM(rela[i].r_info); | ||
28 | uint32_t v = sym->st_value + rela[i].r_addend; | ||
29 | |||
30 | switch (ELF32_R_TYPE(rela[i].r_info)) { | ||
31 | case R_H8_DIR24R8: | ||
32 | loc = (uint32_t *)((uint32_t)loc - 1); | ||
33 | *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v); | ||
34 | break; | ||
35 | case R_H8_DIR24A8: | ||
36 | if (ELF32_R_SYM(rela[i].r_info)) | ||
37 | *loc += v; | ||
38 | break; | ||
39 | case R_H8_DIR32: | ||
40 | case R_H8_DIR32A16: | ||
41 | *loc += v; | ||
42 | break; | ||
43 | case R_H8_PCREL16: | ||
44 | v -= (unsigned long)loc + 2; | ||
45 | if ((Elf32_Sword)v > 0x7fff || | ||
46 | (Elf32_Sword)v < -(Elf32_Sword)0x8000) | ||
47 | goto overflow; | ||
48 | else | ||
49 | *(unsigned short *)loc = v; | ||
50 | break; | ||
51 | case R_H8_PCREL8: | ||
52 | v -= (unsigned long)loc + 1; | ||
53 | if ((Elf32_Sword)v > 0x7f || | ||
54 | (Elf32_Sword)v < -(Elf32_Sword)0x80) | ||
55 | goto overflow; | ||
56 | else | ||
57 | *(unsigned char *)loc = v; | ||
58 | break; | ||
59 | default: | ||
60 | pr_err("module %s: Unknown relocation: %u\n", | ||
61 | me->name, ELF32_R_TYPE(rela[i].r_info)); | ||
62 | return -ENOEXEC; | ||
63 | } | ||
64 | } | ||
65 | return 0; | ||
66 | overflow: | ||
67 | pr_err("module %s: relocation offset overflow: %08x\n", | ||
68 | me->name, rela[i].r_offset); | ||
69 | return -ENOEXEC; | ||
70 | } | ||
diff --git a/arch/h8300/kernel/sim-console.c b/arch/h8300/kernel/sim-console.c new file mode 100644 index 000000000000..a15edf0565d9 --- /dev/null +++ b/arch/h8300/kernel/sim-console.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * arch/h8300/kernel/early_printk.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Yoshinori Sato <ysato@users.sourceforge.jp> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/console.h> | ||
11 | #include <linux/tty.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | static void sim_write(struct console *co, const char *ptr, | ||
17 | unsigned len) | ||
18 | { | ||
19 | register const int fd __asm__("er0") = 1; /* stdout */ | ||
20 | register const char *_ptr __asm__("er1") = ptr; | ||
21 | register const unsigned _len __asm__("er2") = len; | ||
22 | |||
23 | __asm__(".byte 0x5e,0x00,0x00,0xc7\n\t" /* jsr @0xc7 (sys_write) */ | ||
24 | : : "g"(fd), "g"(_ptr), "g"(_len)); | ||
25 | } | ||
26 | |||
27 | static struct console sim_console = { | ||
28 | .name = "sim_console", | ||
29 | .write = sim_write, | ||
30 | .setup = NULL, | ||
31 | .flags = CON_PRINTBUFFER, | ||
32 | .index = -1, | ||
33 | }; | ||
34 | |||
35 | static char sim_console_buf[32]; | ||
36 | |||
37 | static int sim_probe(struct platform_device *pdev) | ||
38 | { | ||
39 | if (sim_console.data) | ||
40 | return -EEXIST; | ||
41 | |||
42 | if (!strstr(sim_console_buf, "keep")) | ||
43 | sim_console.flags |= CON_BOOT; | ||
44 | |||
45 | register_console(&sim_console); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static int sim_remove(struct platform_device *pdev) | ||
50 | { | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static struct platform_driver sim_driver = { | ||
55 | .probe = sim_probe, | ||
56 | .remove = sim_remove, | ||
57 | .driver = { | ||
58 | .name = "h8300-sim", | ||
59 | .owner = THIS_MODULE, | ||
60 | }, | ||
61 | }; | ||
62 | |||
63 | early_platform_init_buffer("earlyprintk", &sim_driver, | ||
64 | sim_console_buf, ARRAY_SIZE(sim_console_buf)); | ||
65 | |||
66 | static struct platform_device sim_console_device = { | ||
67 | .name = "h8300-sim", | ||
68 | .id = 0, | ||
69 | }; | ||
70 | |||
71 | static struct platform_device *devices[] __initdata = { | ||
72 | &sim_console_device, | ||
73 | }; | ||
74 | |||
75 | void __init sim_console_register(void) | ||
76 | { | ||
77 | early_platform_add_devices(devices, | ||
78 | ARRAY_SIZE(devices)); | ||
79 | } | ||
diff --git a/arch/h8300/kernel/syscalls.c b/arch/h8300/kernel/syscalls.c new file mode 100644 index 000000000000..1f9123a013d3 --- /dev/null +++ b/arch/h8300/kernel/syscalls.c | |||
@@ -0,0 +1,14 @@ | |||
1 | #include <linux/syscalls.h> | ||
2 | #include <linux/signal.h> | ||
3 | #include <linux/unistd.h> | ||
4 | |||
5 | #undef __SYSCALL | ||
6 | #define __SYSCALL(nr, call) [nr] = (call), | ||
7 | |||
8 | #define sys_mmap2 sys_mmap_pgoff | ||
9 | |||
10 | asmlinkage int sys_rt_sigreturn(void); | ||
11 | |||
12 | void *_sys_call_table[__NR_syscalls] = { | ||
13 | #include <asm/unistd.h> | ||
14 | }; | ||