| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: db_machdep.c,v 1.37 2021/03/09 16:44:27 ryo Exp $ */ | | 1 | /* $NetBSD: db_machdep.c,v 1.38 2021/03/11 09:48:40 ryo Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Matt Thomas of 3am Software Foundry. | | 8 | * by Matt Thomas of 3am Software Foundry. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -20,27 +20,27 @@ | | | @@ -20,27 +20,27 @@ |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.37 2021/03/09 16:44:27 ryo Exp $"); | | 33 | __KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.38 2021/03/11 09:48:40 ryo Exp $"); |
34 | | | 34 | |
35 | #ifdef _KERNEL_OPT | | 35 | #ifdef _KERNEL_OPT |
36 | #include "opt_compat_netbsd32.h" | | 36 | #include "opt_compat_netbsd32.h" |
37 | #endif | | 37 | #endif |
38 | | | 38 | |
39 | #include <sys/param.h> | | 39 | #include <sys/param.h> |
40 | #include <sys/systm.h> | | 40 | #include <sys/systm.h> |
41 | #include <sys/atomic.h> | | 41 | #include <sys/atomic.h> |
42 | #include <sys/cpu.h> | | 42 | #include <sys/cpu.h> |
43 | #include <sys/lwp.h> | | 43 | #include <sys/lwp.h> |
44 | #include <sys/intr.h> | | 44 | #include <sys/intr.h> |
45 | | | 45 | |
46 | #include <uvm/uvm.h> | | 46 | #include <uvm/uvm.h> |
| @@ -689,97 +689,114 @@ aarch64_set_wcr_wvr(int n, uint64_t wcr, | | | @@ -689,97 +689,114 @@ aarch64_set_wcr_wvr(int n, uint64_t wcr, |
689 | case 15: DBG_WCR_WVR_SET(15, wcr, wvr); break; | | 689 | case 15: DBG_WCR_WVR_SET(15, wcr, wvr); break; |
690 | } | | 690 | } |
691 | } | | 691 | } |
692 | | | 692 | |
693 | void | | 693 | void |
694 | aarch64_breakpoint_set(int n, vaddr_t addr) | | 694 | aarch64_breakpoint_set(int n, vaddr_t addr) |
695 | { | | 695 | { |
696 | uint64_t bcr, bvr; | | 696 | uint64_t bcr, bvr; |
697 | | | 697 | |
698 | if (addr == 0) { | | 698 | if (addr == 0) { |
699 | bvr = 0; | | 699 | bvr = 0; |
700 | bcr = 0; | | 700 | bcr = 0; |
701 | } else { | | 701 | } else { |
702 | bvr = addr; | | 702 | bvr = addr & DBGBVR_MASK; |
703 | bcr = | | 703 | bcr = |
704 | __SHIFTIN(0, DBGBCR_BT) | | | 704 | __SHIFTIN(0, DBGBCR_BT) | |
705 | __SHIFTIN(0, DBGBCR_LBN) | | | 705 | __SHIFTIN(0, DBGBCR_LBN) | |
706 | __SHIFTIN(0, DBGBCR_SSC) | | | 706 | __SHIFTIN(0, DBGBCR_SSC) | |
707 | __SHIFTIN(0, DBGBCR_HMC) | | | 707 | __SHIFTIN(0, DBGBCR_HMC) | |
708 | __SHIFTIN(15, DBGBCR_BAS) | | | 708 | __SHIFTIN(15, DBGBCR_BAS) | |
709 | __SHIFTIN(3, DBGBCR_PMC) | | | 709 | __SHIFTIN(3, DBGBCR_PMC) | |
710 | __SHIFTIN(1, DBGBCR_E); | | 710 | __SHIFTIN(1, DBGBCR_E); |
711 | } | | 711 | } |
712 | | | 712 | |
713 | aarch64_set_bcr_bvr(n, bcr, bvr); | | 713 | aarch64_set_bcr_bvr(n, bcr, bvr); |
714 | } | | 714 | } |
715 | | | 715 | |
716 | void | | 716 | void |
717 | aarch64_watchpoint_set(int n, vaddr_t addr, int size, int accesstype) | | 717 | aarch64_watchpoint_set(int n, vaddr_t addr, u_int size, u_int accesstype) |
718 | { | | 718 | { |
719 | uint64_t wvr, wcr; | | 719 | uint64_t wvr, wcr; |
720 | uint32_t matchbytebit; | | 720 | uint32_t matchbytebit; |
721 | | | 721 | |
722 | KASSERT(size <= 8); | | 722 | KASSERT(size <= 8); |
723 | if (size > 8) | | 723 | if (size > 8) |
724 | size = 8; | | 724 | size = 8; |
725 | | | 725 | |
726 | /* BAS must be all of whose set bits are contiguous */ | | 726 | /* |
| | | 727 | * It is always watched in 8byte units, and |
| | | 728 | * BAS is a bit field of byte offset in 8byte units. |
| | | 729 | */ |
727 | matchbytebit = 0xff >> (8 - size); | | 730 | matchbytebit = 0xff >> (8 - size); |
728 | matchbytebit <<= (addr & 7); | | 731 | matchbytebit <<= (addr & 7); |
| | | 732 | addr &= ~7UL; |
729 | | | 733 | |
730 | /* load, store, or both */ | | 734 | /* load, store, or both */ |
731 | accesstype &= WATCHPOINT_ACCESS_MASK; | | 735 | accesstype &= WATCHPOINT_ACCESS_MASK; |
732 | if (accesstype == 0) | | 736 | if (accesstype == 0) |
733 | accesstype = WATCHPOINT_ACCESS_LOADSTORE; | | 737 | accesstype = WATCHPOINT_ACCESS_LOADSTORE; |
734 | | | 738 | |
735 | if (addr == 0) { | | 739 | if (addr == 0) { |
736 | wvr = 0; | | 740 | wvr = 0; |
737 | wcr = 0; | | 741 | wcr = 0; |
738 | } else { | | 742 | } else { |
739 | wvr = addr; | | 743 | wvr = addr; |
740 | wcr = | | 744 | wcr = |
741 | __SHIFTIN(0, DBGWCR_MASK) | /* MASK: no mask */ | | 745 | __SHIFTIN(0, DBGWCR_MASK) | /* MASK: no mask */ |
742 | __SHIFTIN(0, DBGWCR_WT) | /* WT: 0 */ | | 746 | __SHIFTIN(0, DBGWCR_WT) | /* WT: 0 */ |
743 | __SHIFTIN(0, DBGWCR_LBN) | /* LBN: 0 */ | | 747 | __SHIFTIN(0, DBGWCR_LBN) | /* LBN: 0 */ |
744 | __SHIFTIN(0, DBGWCR_SSC) | /* SSC: 00 */ | | 748 | __SHIFTIN(0, DBGWCR_SSC) | /* SSC: 00 */ |
745 | __SHIFTIN(0, DBGWCR_HMC) | /* HMC: 0 */ | | 749 | __SHIFTIN(0, DBGWCR_HMC) | /* HMC: 0 */ |
746 | __SHIFTIN(matchbytebit, DBGWCR_BAS) | /* BAS: 0-8byte */ | | 750 | __SHIFTIN(matchbytebit, DBGWCR_BAS) | /* BAS: 0-8byte */ |
747 | __SHIFTIN(accesstype, DBGWCR_LSC) | /* LSC: Load/Store */ | | 751 | __SHIFTIN(accesstype, DBGWCR_LSC) | /* LSC: Load/Store */ |
748 | __SHIFTIN(3, DBGWCR_PAC) | /* PAC: 11 */ | | 752 | __SHIFTIN(3, DBGWCR_PAC) | /* PAC: 11 */ |
749 | __SHIFTIN(1, DBGWCR_E); /* Enable */ | | 753 | __SHIFTIN(1, DBGWCR_E); /* Enable */ |
750 | } | | 754 | } |
751 | | | 755 | |
752 | aarch64_set_wcr_wvr(n, wcr, wvr); | | 756 | aarch64_set_wcr_wvr(n, wcr, wvr); |
753 | } | | 757 | } |
754 | | | 758 | |
755 | static void | | 759 | static int |
756 | db_md_breakpoint_set(int n, vaddr_t addr) | | 760 | db_md_breakpoint_set(int n, vaddr_t addr) |
757 | { | | 761 | { |
758 | if (n >= __arraycount(breakpoint_buf)) | | 762 | if (n >= __arraycount(breakpoint_buf)) |
759 | return; | | 763 | return -1; |
| | | 764 | |
| | | 765 | if ((addr & 3) != 0) { |
| | | 766 | db_printf("address must be 4bytes aligned\n"); |
| | | 767 | return -1; |
| | | 768 | } |
760 | | | 769 | |
761 | breakpoint_buf[n].addr = addr; | | 770 | breakpoint_buf[n].addr = addr; |
| | | 771 | return 0; |
762 | } | | 772 | } |
763 | | | 773 | |
764 | static void | | 774 | static int |
765 | db_md_watchpoint_set(int n, vaddr_t addr, int size, int accesstype) | | 775 | db_md_watchpoint_set(int n, vaddr_t addr, u_int size, u_int accesstype) |
766 | { | | 776 | { |
767 | if (n >= __arraycount(watchpoint_buf)) | | 777 | if (n >= __arraycount(watchpoint_buf)) |
768 | return; | | 778 | return -1; |
| | | 779 | |
| | | 780 | if (size != 0 && ((addr) & ~7UL) != ((addr + size - 1) & ~7UL)) { |
| | | 781 | db_printf( |
| | | 782 | "address and size must fit within a block of 8bytes\n"); |
| | | 783 | return -1; |
| | | 784 | } |
769 | | | 785 | |
770 | watchpoint_buf[n].addr = addr; | | 786 | watchpoint_buf[n].addr = addr; |
771 | watchpoint_buf[n].size = size; | | 787 | watchpoint_buf[n].size = size; |
772 | watchpoint_buf[n].accesstype = accesstype; | | 788 | watchpoint_buf[n].accesstype = accesstype; |
| | | 789 | return 0; |
773 | } | | 790 | } |
774 | | | 791 | |
775 | static void | | 792 | static void |
776 | db_md_breakwatchpoints_clear(void) | | 793 | db_md_breakwatchpoints_clear(void) |
777 | { | | 794 | { |
778 | int i; | | 795 | int i; |
779 | | | 796 | |
780 | for (i = 0; i <= max_breakpoint; i++) | | 797 | for (i = 0; i <= max_breakpoint; i++) |
781 | aarch64_breakpoint_set(i, 0); | | 798 | aarch64_breakpoint_set(i, 0); |
782 | for (i = 0; i <= max_watchpoint; i++) | | 799 | for (i = 0; i <= max_watchpoint; i++) |
783 | aarch64_watchpoint_set(i, 0, 0, 0); | | 800 | aarch64_watchpoint_set(i, 0, 0, 0); |
784 | } | | 801 | } |
785 | | | 802 | |
| @@ -883,87 +900,87 @@ show_watchpoints(void) | | | @@ -883,87 +900,87 @@ show_watchpoints(void) |
883 | break; | | 900 | break; |
884 | } | | 901 | } |
885 | db_printf("\n"); | | 902 | db_printf("\n"); |
886 | nused++; | | 903 | nused++; |
887 | } | | 904 | } |
888 | } | | 905 | } |
889 | db_printf("watchpoint used %d/%d\n", nused, max_watchpoint + 1); | | 906 | db_printf("watchpoint used %d/%d\n", nused, max_watchpoint + 1); |
890 | } | | 907 | } |
891 | | | 908 | |
892 | void | | 909 | void |
893 | db_md_break_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | | 910 | db_md_break_cmd(db_expr_t addr, bool have_addr, db_expr_t count, |
894 | const char *modif) | | 911 | const char *modif) |
895 | { | | 912 | { |
896 | int i; | | 913 | int i, rc; |
897 | int added, cleared; | | 914 | int added, cleared; |
898 | | | 915 | |
899 | if (!have_addr) { | | 916 | if (!have_addr) { |
900 | show_breakpoints(); | | 917 | show_breakpoints(); |
901 | return; | | 918 | return; |
902 | } | | 919 | } |
903 | | | 920 | |
904 | addr &= DBGBVR_MASK; | | | |
905 | added = -1; | | 921 | added = -1; |
906 | cleared = -1; | | 922 | cleared = -1; |
907 | if (0 <= addr && addr <= max_breakpoint) { | | 923 | if (0 <= addr && addr <= max_breakpoint) { |
908 | i = addr; | | 924 | i = addr; |
909 | if (breakpoint_buf[i].addr != 0) { | | 925 | if (breakpoint_buf[i].addr != 0) { |
910 | db_md_breakpoint_set(i, 0); | | 926 | db_md_breakpoint_set(i, 0); |
911 | cleared = i; | | 927 | cleared = i; |
912 | } | | 928 | } |
913 | } else { | | 929 | } else { |
914 | for (i = 0; i <= max_breakpoint; i++) { | | 930 | for (i = 0; i <= max_breakpoint; i++) { |
915 | if (breakpoint_buf[i].addr == addr) { | | 931 | if (breakpoint_buf[i].addr == addr) { |
916 | db_md_breakpoint_set(i, 0); | | 932 | db_md_breakpoint_set(i, 0); |
917 | cleared = i; | | 933 | cleared = i; |
918 | } | | 934 | } |
919 | } | | 935 | } |
920 | if (cleared == -1) { | | 936 | if (cleared == -1) { |
921 | for (i = 0; i <= max_breakpoint; i++) { | | 937 | for (i = 0; i <= max_breakpoint; i++) { |
922 | if (breakpoint_buf[i].addr == 0) { | | 938 | if (breakpoint_buf[i].addr == 0) { |
923 | db_md_breakpoint_set(i, addr); | | 939 | rc = db_md_breakpoint_set(i, addr); |
| | | 940 | if (rc != 0) |
| | | 941 | return; |
924 | added = i; | | 942 | added = i; |
925 | break; | | 943 | break; |
926 | } | | 944 | } |
927 | } | | 945 | } |
928 | if (i > max_breakpoint) { | | 946 | if (i > max_breakpoint) { |
929 | db_printf("no more available breakpoint\n"); | | 947 | db_printf("no more available breakpoint\n"); |
930 | } | | 948 | } |
931 | } | | 949 | } |
932 | } | | 950 | } |
933 | | | 951 | |
934 | if (added >= 0) | | 952 | if (added >= 0) |
935 | db_printf("add breakpoint %d as %016"DDB_EXPR_FMT"x\n", | | 953 | db_printf("add breakpoint %d as %016"DDB_EXPR_FMT"x\n", |
936 | added, addr); | | 954 | added, addr); |
937 | if (cleared >= 0) | | 955 | if (cleared >= 0) |
938 | db_printf("clear breakpoint %d\n", cleared); | | 956 | db_printf("clear breakpoint %d\n", cleared); |
939 | | | 957 | |
940 | show_breakpoints(); | | 958 | show_breakpoints(); |
941 | } | | 959 | } |
942 | | | 960 | |
943 | void | | 961 | void |
944 | db_md_watch_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | | 962 | db_md_watch_cmd(db_expr_t addr, bool have_addr, db_expr_t count, |
945 | const char *modif) | | 963 | const char *modif) |
946 | { | | 964 | { |
947 | int i; | | 965 | int i, rc; |
948 | int added, cleared; | | 966 | int added, cleared; |
949 | int accesstype, watchsize; | | 967 | u_int accesstype, watchsize; |
950 | | | 968 | |
951 | if (!have_addr) { | | 969 | if (!have_addr) { |
952 | show_watchpoints(); | | 970 | show_watchpoints(); |
953 | return; | | 971 | return; |
954 | } | | 972 | } |
955 | | | 973 | |
956 | addr &= DBGWVR_MASK; | | | |
957 | accesstype = watchsize = 0; | | 974 | accesstype = watchsize = 0; |
958 | if ((modif != NULL) && (*modif != '\0')) { | | 975 | if ((modif != NULL) && (*modif != '\0')) { |
959 | int ch; | | 976 | int ch; |
960 | for (; *modif != '\0'; modif++) { | | 977 | for (; *modif != '\0'; modif++) { |
961 | ch = *modif; | | 978 | ch = *modif; |
962 | | | 979 | |
963 | switch (ch) { | | 980 | switch (ch) { |
964 | case '1': | | 981 | case '1': |
965 | case '2': | | 982 | case '2': |
966 | case '3': | | 983 | case '3': |
967 | case '4': | | 984 | case '4': |
968 | case '5': | | 985 | case '5': |
969 | case '6': | | 986 | case '6': |
| @@ -993,28 +1010,30 @@ db_md_watch_cmd(db_expr_t addr, bool hav | | | @@ -993,28 +1010,30 @@ db_md_watch_cmd(db_expr_t addr, bool hav |
993 | db_md_watchpoint_set(i, 0, 0, 0); | | 1010 | db_md_watchpoint_set(i, 0, 0, 0); |
994 | cleared = i; | | 1011 | cleared = i; |
995 | } | | 1012 | } |
996 | } else { | | 1013 | } else { |
997 | for (i = 0; i <= max_watchpoint; i++) { | | 1014 | for (i = 0; i <= max_watchpoint; i++) { |
998 | if (watchpoint_buf[i].addr == addr) { | | 1015 | if (watchpoint_buf[i].addr == addr) { |
999 | db_md_watchpoint_set(i, 0, 0, 0); | | 1016 | db_md_watchpoint_set(i, 0, 0, 0); |
1000 | cleared = i; | | 1017 | cleared = i; |
1001 | } | | 1018 | } |
1002 | } | | 1019 | } |
1003 | if (cleared == -1) { | | 1020 | if (cleared == -1) { |
1004 | for (i = 0; i <= max_watchpoint; i++) { | | 1021 | for (i = 0; i <= max_watchpoint; i++) { |
1005 | if (watchpoint_buf[i].addr == 0) { | | 1022 | if (watchpoint_buf[i].addr == 0) { |
1006 | db_md_watchpoint_set(i, addr, watchsize, | | 1023 | rc = db_md_watchpoint_set(i, addr, |
1007 | accesstype); | | 1024 | watchsize, accesstype); |
| | | 1025 | if (rc != 0) |
| | | 1026 | return; |
1008 | added = i; | | 1027 | added = i; |
1009 | break; | | 1028 | break; |
1010 | } | | 1029 | } |
1011 | } | | 1030 | } |
1012 | if (i > max_watchpoint) { | | 1031 | if (i > max_watchpoint) { |
1013 | db_printf("no more available watchpoint\n"); | | 1032 | db_printf("no more available watchpoint\n"); |
1014 | } | | 1033 | } |
1015 | } | | 1034 | } |
1016 | } | | 1035 | } |
1017 | | | 1036 | |
1018 | if (added >= 0) | | 1037 | if (added >= 0) |
1019 | db_printf("add watchpoint %d as %016"DDB_EXPR_FMT"x\n", | | 1038 | db_printf("add watchpoint %d as %016"DDB_EXPR_FMT"x\n", |
1020 | added, addr); | | 1039 | added, addr); |