diff options
| -rw-r--r-- | arch/blackfin/kernel/kgdb.c | 205 | ||||
| -rw-r--r-- | arch/blackfin/mm/Makefile | 2 | ||||
| -rw-r--r-- | arch/blackfin/mm/maccess.c | 97 |
3 files changed, 98 insertions, 206 deletions
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c index f1036b6b9293..da03848bfdd6 100644 --- a/arch/blackfin/kernel/kgdb.c +++ b/arch/blackfin/kernel/kgdb.c | |||
| @@ -6,23 +6,9 @@ | |||
| 6 | * Licensed under the GPL-2 or later. | 6 | * Licensed under the GPL-2 or later. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/string.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/sched.h> | ||
| 12 | #include <linux/smp.h> | ||
| 13 | #include <linux/spinlock.h> | ||
| 14 | #include <linux/delay.h> | ||
| 15 | #include <linux/ptrace.h> /* for linux pt_regs struct */ | 9 | #include <linux/ptrace.h> /* for linux pt_regs struct */ |
| 16 | #include <linux/kgdb.h> | 10 | #include <linux/kgdb.h> |
| 17 | #include <linux/console.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/errno.h> | ||
| 20 | #include <linux/irq.h> | ||
| 21 | #include <linux/uaccess.h> | 11 | #include <linux/uaccess.h> |
| 22 | #include <asm/system.h> | ||
| 23 | #include <asm/traps.h> | ||
| 24 | #include <asm/blackfin.h> | ||
| 25 | #include <asm/dma.h> | ||
| 26 | 12 | ||
| 27 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | 13 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) |
| 28 | { | 14 | { |
| @@ -424,182 +410,6 @@ struct kgdb_arch arch_kgdb_ops = { | |||
| 424 | .correct_hw_break = bfin_correct_hw_break, | 410 | .correct_hw_break = bfin_correct_hw_break, |
| 425 | }; | 411 | }; |
| 426 | 412 | ||
| 427 | static int hex(char ch) | ||
| 428 | { | ||
| 429 | if ((ch >= 'a') && (ch <= 'f')) | ||
| 430 | return ch - 'a' + 10; | ||
| 431 | if ((ch >= '0') && (ch <= '9')) | ||
| 432 | return ch - '0'; | ||
| 433 | if ((ch >= 'A') && (ch <= 'F')) | ||
| 434 | return ch - 'A' + 10; | ||
| 435 | return -1; | ||
| 436 | } | ||
| 437 | |||
| 438 | static int validate_memory_access_address(unsigned long addr, int size) | ||
| 439 | { | ||
| 440 | if (size < 0 || addr == 0) | ||
| 441 | return -EFAULT; | ||
| 442 | return bfin_mem_access_type(addr, size); | ||
| 443 | } | ||
| 444 | |||
| 445 | static int bfin_probe_kernel_read(char *dst, char *src, int size) | ||
| 446 | { | ||
| 447 | unsigned long lsrc = (unsigned long)src; | ||
| 448 | int mem_type; | ||
| 449 | |||
| 450 | mem_type = validate_memory_access_address(lsrc, size); | ||
| 451 | if (mem_type < 0) | ||
| 452 | return mem_type; | ||
| 453 | |||
| 454 | if (lsrc >= SYSMMR_BASE) { | ||
| 455 | if (size == 2 && lsrc % 2 == 0) { | ||
| 456 | u16 mmr = bfin_read16(src); | ||
| 457 | memcpy(dst, &mmr, sizeof(mmr)); | ||
| 458 | return 0; | ||
| 459 | } else if (size == 4 && lsrc % 4 == 0) { | ||
| 460 | u32 mmr = bfin_read32(src); | ||
| 461 | memcpy(dst, &mmr, sizeof(mmr)); | ||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | } else { | ||
| 465 | switch (mem_type) { | ||
| 466 | case BFIN_MEM_ACCESS_CORE: | ||
| 467 | case BFIN_MEM_ACCESS_CORE_ONLY: | ||
| 468 | return probe_kernel_read(dst, src, size); | ||
| 469 | /* XXX: should support IDMA here with SMP */ | ||
| 470 | case BFIN_MEM_ACCESS_DMA: | ||
| 471 | if (dma_memcpy(dst, src, size)) | ||
| 472 | return 0; | ||
| 473 | break; | ||
| 474 | case BFIN_MEM_ACCESS_ITEST: | ||
| 475 | if (isram_memcpy(dst, src, size)) | ||
| 476 | return 0; | ||
| 477 | break; | ||
| 478 | } | ||
| 479 | } | ||
| 480 | |||
| 481 | return -EFAULT; | ||
| 482 | } | ||
| 483 | |||
| 484 | static int bfin_probe_kernel_write(char *dst, char *src, int size) | ||
| 485 | { | ||
| 486 | unsigned long ldst = (unsigned long)dst; | ||
| 487 | int mem_type; | ||
| 488 | |||
| 489 | mem_type = validate_memory_access_address(ldst, size); | ||
| 490 | if (mem_type < 0) | ||
| 491 | return mem_type; | ||
| 492 | |||
| 493 | if (ldst >= SYSMMR_BASE) { | ||
| 494 | if (size == 2 && ldst % 2 == 0) { | ||
| 495 | u16 mmr; | ||
| 496 | memcpy(&mmr, src, sizeof(mmr)); | ||
| 497 | bfin_write16(dst, mmr); | ||
| 498 | return 0; | ||
| 499 | } else if (size == 4 && ldst % 4 == 0) { | ||
| 500 | u32 mmr; | ||
| 501 | memcpy(&mmr, src, sizeof(mmr)); | ||
| 502 | bfin_write32(dst, mmr); | ||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | } else { | ||
| 506 | switch (mem_type) { | ||
| 507 | case BFIN_MEM_ACCESS_CORE: | ||
| 508 | case BFIN_MEM_ACCESS_CORE_ONLY: | ||
| 509 | return probe_kernel_write(dst, src, size); | ||
| 510 | /* XXX: should support IDMA here with SMP */ | ||
| 511 | case BFIN_MEM_ACCESS_DMA: | ||
| 512 | if (dma_memcpy(dst, src, size)) | ||
| 513 | return 0; | ||
| 514 | break; | ||
| 515 | case BFIN_MEM_ACCESS_ITEST: | ||
| 516 | if (isram_memcpy(dst, src, size)) | ||
| 517 | return 0; | ||
| 518 | break; | ||
| 519 | } | ||
| 520 | } | ||
| 521 | |||
| 522 | return -EFAULT; | ||
| 523 | } | ||
| 524 | |||
| 525 | /* | ||
| 526 | * Convert the memory pointed to by mem into hex, placing result in buf. | ||
| 527 | * Return a pointer to the last char put in buf (null). May return an error. | ||
| 528 | */ | ||
| 529 | int kgdb_mem2hex(char *mem, char *buf, int count) | ||
| 530 | { | ||
| 531 | char *tmp; | ||
| 532 | int err; | ||
| 533 | |||
| 534 | /* | ||
| 535 | * We use the upper half of buf as an intermediate buffer for the | ||
| 536 | * raw memory copy. Hex conversion will work against this one. | ||
| 537 | */ | ||
| 538 | tmp = buf + count; | ||
| 539 | |||
| 540 | err = bfin_probe_kernel_read(tmp, mem, count); | ||
| 541 | if (!err) { | ||
| 542 | while (count > 0) { | ||
| 543 | buf = pack_hex_byte(buf, *tmp); | ||
| 544 | tmp++; | ||
| 545 | count--; | ||
| 546 | } | ||
| 547 | |||
| 548 | *buf = 0; | ||
| 549 | } | ||
| 550 | |||
| 551 | return err; | ||
| 552 | } | ||
| 553 | |||
| 554 | /* | ||
| 555 | * Copy the binary array pointed to by buf into mem. Fix $, #, and | ||
| 556 | * 0x7d escaped with 0x7d. Return a pointer to the character after | ||
| 557 | * the last byte written. | ||
| 558 | */ | ||
| 559 | int kgdb_ebin2mem(char *buf, char *mem, int count) | ||
| 560 | { | ||
| 561 | char *tmp_old, *tmp_new; | ||
| 562 | int size; | ||
| 563 | |||
| 564 | tmp_old = tmp_new = buf; | ||
| 565 | |||
| 566 | for (size = 0; size < count; ++size) { | ||
| 567 | if (*tmp_old == 0x7d) | ||
| 568 | *tmp_new = *(++tmp_old) ^ 0x20; | ||
| 569 | else | ||
| 570 | *tmp_new = *tmp_old; | ||
| 571 | tmp_new++; | ||
| 572 | tmp_old++; | ||
| 573 | } | ||
| 574 | |||
| 575 | return bfin_probe_kernel_write(mem, buf, count); | ||
| 576 | } | ||
| 577 | |||
| 578 | /* | ||
| 579 | * Convert the hex array pointed to by buf into binary to be placed in mem. | ||
| 580 | * Return a pointer to the character AFTER the last byte written. | ||
| 581 | * May return an error. | ||
| 582 | */ | ||
| 583 | int kgdb_hex2mem(char *buf, char *mem, int count) | ||
| 584 | { | ||
| 585 | char *tmp_raw, *tmp_hex; | ||
| 586 | |||
| 587 | /* | ||
| 588 | * We use the upper half of buf as an intermediate buffer for the | ||
| 589 | * raw memory that is converted from hex. | ||
| 590 | */ | ||
| 591 | tmp_raw = buf + count * 2; | ||
| 592 | |||
| 593 | tmp_hex = tmp_raw - 1; | ||
| 594 | while (tmp_hex >= buf) { | ||
| 595 | tmp_raw--; | ||
| 596 | *tmp_raw = hex(*tmp_hex--); | ||
| 597 | *tmp_raw |= hex(*tmp_hex--) << 4; | ||
| 598 | } | ||
| 599 | |||
| 600 | return bfin_probe_kernel_write(mem, tmp_raw, count); | ||
| 601 | } | ||
| 602 | |||
| 603 | #define IN_MEM(addr, size, l1_addr, l1_size) \ | 413 | #define IN_MEM(addr, size, l1_addr, l1_size) \ |
| 604 | ({ \ | 414 | ({ \ |
| 605 | unsigned long __addr = (unsigned long)(addr); \ | 415 | unsigned long __addr = (unsigned long)(addr); \ |
| @@ -629,21 +439,6 @@ int kgdb_validate_break_address(unsigned long addr) | |||
| 629 | return -EFAULT; | 439 | return -EFAULT; |
| 630 | } | 440 | } |
| 631 | 441 | ||
| 632 | int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) | ||
| 633 | { | ||
| 634 | int err = bfin_probe_kernel_read(saved_instr, (char *)addr, | ||
| 635 | BREAK_INSTR_SIZE); | ||
| 636 | if (err) | ||
| 637 | return err; | ||
| 638 | return bfin_probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr, | ||
| 639 | BREAK_INSTR_SIZE); | ||
| 640 | } | ||
| 641 | |||
| 642 | int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) | ||
| 643 | { | ||
| 644 | return bfin_probe_kernel_write((char *)addr, bundle, BREAK_INSTR_SIZE); | ||
| 645 | } | ||
| 646 | |||
| 647 | int kgdb_arch_init(void) | 442 | int kgdb_arch_init(void) |
| 648 | { | 443 | { |
| 649 | kgdb_single_step = 0; | 444 | kgdb_single_step = 0; |
diff --git a/arch/blackfin/mm/Makefile b/arch/blackfin/mm/Makefile index d489f894f4b1..4c011b1f661f 100644 --- a/arch/blackfin/mm/Makefile +++ b/arch/blackfin/mm/Makefile | |||
| @@ -2,4 +2,4 @@ | |||
| 2 | # arch/blackfin/mm/Makefile | 2 | # arch/blackfin/mm/Makefile |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := sram-alloc.o isram-driver.o init.o | 5 | obj-y := sram-alloc.o isram-driver.o init.o maccess.o |
diff --git a/arch/blackfin/mm/maccess.c b/arch/blackfin/mm/maccess.c new file mode 100644 index 000000000000..b71cebc1f8a3 --- /dev/null +++ b/arch/blackfin/mm/maccess.c | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | /* | ||
| 2 | * safe read and write memory routines callable while atomic | ||
| 3 | * | ||
| 4 | * Copyright 2005-2008 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/uaccess.h> | ||
| 10 | #include <asm/dma.h> | ||
| 11 | |||
| 12 | static int validate_memory_access_address(unsigned long addr, int size) | ||
| 13 | { | ||
| 14 | if (size < 0 || addr == 0) | ||
| 15 | return -EFAULT; | ||
| 16 | return bfin_mem_access_type(addr, size); | ||
| 17 | } | ||
| 18 | |||
| 19 | long probe_kernel_read(void *dst, void *src, size_t size) | ||
| 20 | { | ||
| 21 | unsigned long lsrc = (unsigned long)src; | ||
| 22 | int mem_type; | ||
| 23 | |||
| 24 | mem_type = validate_memory_access_address(lsrc, size); | ||
| 25 | if (mem_type < 0) | ||
| 26 | return mem_type; | ||
| 27 | |||
| 28 | if (lsrc >= SYSMMR_BASE) { | ||
| 29 | if (size == 2 && lsrc % 2 == 0) { | ||
| 30 | u16 mmr = bfin_read16(src); | ||
| 31 | memcpy(dst, &mmr, sizeof(mmr)); | ||
| 32 | return 0; | ||
| 33 | } else if (size == 4 && lsrc % 4 == 0) { | ||
| 34 | u32 mmr = bfin_read32(src); | ||
| 35 | memcpy(dst, &mmr, sizeof(mmr)); | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | } else { | ||
| 39 | switch (mem_type) { | ||
| 40 | case BFIN_MEM_ACCESS_CORE: | ||
| 41 | case BFIN_MEM_ACCESS_CORE_ONLY: | ||
| 42 | return __probe_kernel_read(dst, src, size); | ||
| 43 | /* XXX: should support IDMA here with SMP */ | ||
| 44 | case BFIN_MEM_ACCESS_DMA: | ||
| 45 | if (dma_memcpy(dst, src, size)) | ||
| 46 | return 0; | ||
| 47 | break; | ||
| 48 | case BFIN_MEM_ACCESS_ITEST: | ||
| 49 | if (isram_memcpy(dst, src, size)) | ||
| 50 | return 0; | ||
| 51 | break; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | return -EFAULT; | ||
| 56 | } | ||
| 57 | |||
| 58 | long probe_kernel_write(void *dst, void *src, size_t size) | ||
| 59 | { | ||
| 60 | unsigned long ldst = (unsigned long)dst; | ||
| 61 | int mem_type; | ||
| 62 | |||
| 63 | mem_type = validate_memory_access_address(ldst, size); | ||
| 64 | if (mem_type < 0) | ||
| 65 | return mem_type; | ||
| 66 | |||
| 67 | if (ldst >= SYSMMR_BASE) { | ||
| 68 | if (size == 2 && ldst % 2 == 0) { | ||
| 69 | u16 mmr; | ||
| 70 | memcpy(&mmr, src, sizeof(mmr)); | ||
| 71 | bfin_write16(dst, mmr); | ||
| 72 | return 0; | ||
| 73 | } else if (size == 4 && ldst % 4 == 0) { | ||
| 74 | u32 mmr; | ||
| 75 | memcpy(&mmr, src, sizeof(mmr)); | ||
| 76 | bfin_write32(dst, mmr); | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | } else { | ||
| 80 | switch (mem_type) { | ||
| 81 | case BFIN_MEM_ACCESS_CORE: | ||
| 82 | case BFIN_MEM_ACCESS_CORE_ONLY: | ||
| 83 | return __probe_kernel_write(dst, src, size); | ||
| 84 | /* XXX: should support IDMA here with SMP */ | ||
| 85 | case BFIN_MEM_ACCESS_DMA: | ||
| 86 | if (dma_memcpy(dst, src, size)) | ||
| 87 | return 0; | ||
| 88 | break; | ||
| 89 | case BFIN_MEM_ACCESS_ITEST: | ||
| 90 | if (isram_memcpy(dst, src, size)) | ||
| 91 | return 0; | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | return -EFAULT; | ||
| 97 | } | ||
