├── patch.ld ├── LICENSE ├── src ├── version.c ├── patch.c ├── debugger.c └── debugger_base.c ├── README.md └── Makefile /patch.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | INCLUDE gen/memory.ld 4 | } 5 | 6 | SECTIONS 7 | { 8 | INCLUDE gen/flashpatches.ld 9 | INCLUDE gen/nexmon.ld 10 | } 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | ########### ########### ########## ########## 3 | ############ ############ ############ ############ 4 | ## ## ## ## ## ## ## 5 | ## ## ## ## ## ## ## 6 | ########### #### ###### ## ## ## ## ###### 7 | ########### #### # ## ## ## ## # # 8 | ## ## ###### ## ## ## ## # # 9 | ## ## # ## ## ## ## # # 10 | ############ ##### ###### ## ## ## ##### ###### 11 | ########### ########### ## ## ## ########## 12 | 13 | S E C U R E M O B I L E N E T W O R K I N G 14 | 15 | License: 16 | 17 | Copyright (c) 2017 Secure Mobile Networking Lab (SEEMOO) 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a 20 | copy of this software and associated documentation files (the 21 | "Software"), to deal in the Software without restriction, including 22 | without limitation the rights to use, copy, modify, merge, publish, 23 | distribute, sublicense, and/or sell copies of the Software, and to 24 | permit persons to whom the Software is furnished to do so, subject to 25 | the following conditions: 26 | 27 | 1. The above copyright notice and this permission notice shall be 28 | include in all copies or substantial portions of the Software. 29 | 30 | 2. Any use of the Software which results in an academic publication or 31 | other publication which includes a bibliography must include 32 | citations to the nexmon project a): 33 | 34 | a) "Matthias Schulz, Daniel Wegemer and Matthias Hollick. Nexmon: 35 | The C-based Firmware Patching Framework. https://nexmon.org" 36 | 37 | 3. The Software is not used by, in cooperation with, or on behalf of 38 | any armed forces, intelligence agencies, reconnaissance agencies, 39 | defense agencies, offense agencies or any supplier, contractor, or 40 | research associated. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 43 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 44 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 45 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 46 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 47 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 48 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 49 | -------------------------------------------------------------------------------- /src/version.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * * 3 | * ########### ########### ########## ########## * 4 | * ############ ############ ############ ############ * 5 | * ## ## ## ## ## ## ## * 6 | * ## ## ## ## ## ## ## * 7 | * ########### #### ###### ## ## ## ## ###### * 8 | * ########### #### # ## ## ## ## # # * 9 | * ## ## ###### ## ## ## ## # # * 10 | * ## ## # ## ## ## ## # # * 11 | * ############ ##### ###### ## ## ## ##### ###### * 12 | * ########### ########### ## ## ## ########## * 13 | * * 14 | * S E C U R E M O B I L E N E T W O R K I N G * 15 | * * 16 | * This file is part of NexMon. * 17 | * * 18 | * Copyright (c) 2016 NexMon Team * 19 | * * 20 | * NexMon is free software: you can redistribute it and/or modify * 21 | * it under the terms of the GNU General Public License as published by * 22 | * the Free Software Foundation, either version 3 of the License, or * 23 | * (at your option) any later version. * 24 | * * 25 | * NexMon is distributed in the hope that it will be useful, * 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 28 | * GNU General Public License for more details. * 29 | * * 30 | * You should have received a copy of the GNU General Public License * 31 | * along with NexMon. If not, see . * 32 | * * 33 | **************************************************************************/ 34 | 35 | #pragma NEXMON targetregion "patch" 36 | 37 | #include // definition of firmware version macros 38 | #include // macros used to craete patches such as BLPatch, BPatch, ... 39 | 40 | char version[] = "nexmon_ver: " GIT_VERSION "-" BUILD_NUMBER "\n"; 41 | 42 | __attribute__((at(0x1F2470, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 43 | GenericPatch4(version_patch, version); 44 | -------------------------------------------------------------------------------- /src/patch.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * * 3 | * ########### ########### ########## ########## * 4 | * ############ ############ ############ ############ * 5 | * ## ## ## ## ## ## ## * 6 | * ## ## ## ## ## ## ## * 7 | * ########### #### ###### ## ## ## ## ###### * 8 | * ########### #### # ## ## ## ## # # * 9 | * ## ## ###### ## ## ## ## # # * 10 | * ## ## # ## ## ## ## # # * 11 | * ############ ##### ###### ## ## ## ##### ###### * 12 | * ########### ########### ## ## ## ########## * 13 | * * 14 | * S E C U R E M O B I L E N E T W O R K I N G * 15 | * * 16 | * This file is part of NexMon. * 17 | * * 18 | * Copyright (c) 2016 NexMon Team * 19 | * * 20 | * NexMon is free software: you can redistribute it and/or modify * 21 | * it under the terms of the GNU General Public License as published by * 22 | * the Free Software Foundation, either version 3 of the License, or * 23 | * (at your option) any later version. * 24 | * * 25 | * NexMon is distributed in the hope that it will be useful, * 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 28 | * GNU General Public License for more details. * 29 | * * 30 | * You should have received a copy of the GNU General Public License * 31 | * along with NexMon. If not, see . * 32 | * * 33 | **************************************************************************/ 34 | 35 | #pragma NEXMON targetregion "patch" 36 | 37 | #include // definition of firmware version macros 38 | #include // contains macros to access the debug hardware 39 | #include // wrapper definitions for functions that already exist in the firmware 40 | #include // structures that are used by the code in the firmware 41 | #include // useful helper functions 42 | #include // macros used to craete patches such as BLPatch, BPatch, ... 43 | #include // rates used to build the ratespec for frame injection 44 | #include // capabilities included in a nexmon patch 45 | 46 | int capabilities = NEX_CAP_MONITOR_MODE | NEX_CAP_MONITOR_MODE_RADIOTAP | NEX_CAP_FRAME_INJECTION; 47 | 48 | // Hook the call to wlc_ucode_write in wlc_ucode_download 49 | __attribute__((at(0x1F4F08, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_40_r581243))) 50 | __attribute__((at(0x1F4F14, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 51 | BLPatch(wlc_ucode_write_compressed, wlc_ucode_write_compressed); 52 | 53 | // reduce the amount of ucode memory freed to become part of the heap 54 | __attribute__((at(0x1816E0, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 55 | GenericPatch4(hndrte_reclaim_0_end, PATCHSTART); 56 | 57 | extern unsigned char templateram_bin[]; 58 | 59 | // Moving template ram to another place in the ucode region 60 | __attribute__((at(0x185544, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 61 | GenericPatch4(templateram_bin, templateram_bin); 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![NexMon logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/nexmon.png) 2 | 3 | # Nexmon Debugger 4 | 5 | To analyze the FullMAC firmware running on the ARM microcontroller in the BCM4339 Wi-Fi chip, 6 | we created a debugger in software that directly accesses the hardware registers of the ARM 7 | Debugging core. As we do not have access to the JTAG port, we generate exceptions whenever a 8 | breakpoint or watchpoint is triggered. We handle those exceptions in our firmware patch and 9 | can then continue with the execution of the firmware code. 10 | 11 | In our example, we set a breakpoint at the `printf` function: 12 | ``` 13 | dbg_set_breakpoint_for_addr_match(0, 0x126f0); // trigger on printf 14 | ``` 15 | When it triggers, the function `handle_pref_abort_exception` is called. There, we check if 16 | register `R1` points to the string `sdpcmd_dpc`. If the condition matches, we print a debug 17 | message and activate single-step debugging. To this end, we set the breakpoint to trigger on 18 | a mismatch of the address of the current program counter. Then we can decide to either trigger 19 | on a mismatch of the current program counter address again for single stepping or reset the 20 | breakpoint to the original address of the `printf` funciton. 21 | 22 | Additionally, we set a memory watchpoint on the address of the string 23 | `%s: Broadcom SDPCMD CDC driver`: 24 | ``` 25 | dbg_set_watchpoint_for_addr_match(0, 0x1FC2A4); // trigger on "%s: Broadcom SDPCMD CDC driver" string 26 | ``` 27 | Whenever, code reads or writes to this address, a data abort exception is triggered that is 28 | handled by the `handle_data_abort_exception` function. In this function, we print the address 29 | of the instruction accessing monitored memory location. We also disable the watchpoint and set 30 | a new breakpoint to trigger on an address mismatch of the current program counter to advance 31 | by one instruction. The breakpoint handler reactivates the watchpoint. 32 | 33 | The output observed on the console is as follows: 34 | ``` 35 | start=0x001eb5d8 len=0x00000800 36 | 37 | RTE (USB-SDIO-CDC) 6.37.32.RC23.34.43 (r639704) on BCM4339 r1 @ 37.4/161.3/161.3MHz 38 | 000000.010 WP hit pc=00012b3a 39 | 000000.013 WP hit pc=00012b3a 40 | 000000.010 sdpcmdcdc0: Broadcom SDPCMD CDC driver 41 | 000000.141 reclaim section 0: Returned 31688 bytes to the heap 42 | 000000.189 nexmon_ver: 63fb-dirty-14 43 | 000000.192 wl_nd_ra_filter_init: Enter.. 44 | 000000.196 TCAM: 256 used: 198 exceed:0 45 | 000000.200 WP hit pc=000126c2 46 | 000000.203 reclaim section 1: Returned 71844 bytes to the heap 47 | 000000.208 BP0 step 0: pc=000126f0 *r1=sdpcmd_dpc 48 | 000000.213 BP0 step 1: pc=000126f2 49 | 000000.216 BP0 step 2: pc=000126f4 50 | 000000.219 BP0 step 3: pc=000126f6 51 | 000000.223 BP0 step 4: pc=000126fa 52 | 000000.226 BP0 single-stepping done 53 | 000000.229 sdpcmd_dpc: Enable 54 | 000000.234 wl0: wlc_bmac_ucodembss_hwcap: Insuff mem for MBSS: templ memblks 192 fifo memblks 259 55 | 000000.249 wl0: wlc_enable_probe_req: state down, deferring setting of host flags 56 | 000000.295 wl0: wlc_enable_probe_req: state down, deferring setting of host flags 57 | 000000.303 wl0: wlc_enable_probe_req: state down, deferring setting of host flags 58 | ``` 59 | 60 | `0x12b3a` is an instruction in the `vsnprintf` function called during the `printf` call writing to 61 | the chip's console. `0x126c2` is an instruction in the `memset` function, called after initialization 62 | when parts of the code used during initialization is freed and assigned to the heap. 63 | 64 | # Extract from our License 65 | 66 | Any use of the Software which results in an academic publication or 67 | other publication which includes a bibliography must include 68 | citations to the nexmon project (1): 69 | 70 | 1. "Matthias Schulz, Daniel Wegemer and Matthias Hollick. Nexmon: 71 | The C-based Firmware Patching Framework. https://nexmon.org" 72 | 73 | # Getting Started 74 | 75 | To compile the source code, you are required to first checkout a copy of the original nexmon 76 | repository that contains our C-based patching framework for Wi-Fi firmwares. That you checkout 77 | this repository as one of the sub-projects in the corresponding patches sub-directory. This 78 | allows you to build and compile all the firmware patches required to repeat our experiments. 79 | The following steps will get you started on Xubuntu 16.04 LTS: 80 | 81 | 1. Install some dependencies: `sudo apt-get install git gawk qpdf adb` 82 | 2. **Only necessary for x86_64 systems**, install i386 libs: 83 | 84 | ``` 85 | sudo dpkg --add-architecture i386 86 | sudo apt-get update 87 | sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 88 | ``` 89 | 3. Clone the nexmon base repository: `git clone https://github.com/seemoo-lab/nexmon.git`. 90 | 4. Download and extract Android NDK r11c (use exactly this version!). 91 | 5. Export the NDK_ROOT environment variable pointing to the location where you extracted the ndk so that it can be found by our build environment. 92 | 6. Navigate to the previously cloned nexmon directory and execute `source setup_env.sh` to set a couple of environment variables. 93 | 7. Run `make` to extract ucode, templateram and flashpatches from the original firmwares. 94 | 8. Navigate to utilities and run `make` to build all utilities such as nexmon. 95 | 9. Attach your rooted Nexus 5 smartphone running stock firmware version 6.0.1 (M4B30Z, Dec 2016). 96 | 10. Run `make install` to install all the built utilities on your phone. 97 | 11. Navigate to patches/bcm4339/6_37_34_43/ and clone this repository: `git clone https://github.com/seemoo-lab/wintech2017_nexmon_ping_offloading.git` 98 | 12. Enter the created subdirectory wisec2017_nexmon_jammer and run `make install-firmware` to compile our firmware patch and install it on the attached Nexus 5 smartphone. 99 | 100 | # References 101 | 102 | * Matthias Schulz, Daniel Wegemer and Matthias Hollick. **Nexmon: The C-based Firmware Patching Framework**. https://nexmon.org 103 | 104 | [Get references as bibtex file](https://nexmon.org/bib) 105 | 106 | # Contact 107 | 108 | * [Matthias Schulz](https://seemoo.tu-darmstadt.de/mschulz) 109 | 110 | # Powered By 111 | 112 | ## Secure Mobile Networking Lab (SEEMOO) 113 | ![SEEMOO logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/seemoo.png) 114 | ## Networked Infrastructureless Cooperation for Emergency Response (NICER) 115 | ![NICER logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/nicer.png) 116 | ## Multi-Mechanisms Adaptation for the Future Internet (MAKI) 117 | ![MAKI logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/maki.png) 118 | ## Technische Universität Darmstadt 119 | ![TU Darmstadt logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/tudarmstadt.png) 120 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always --tags) 2 | include ../version.mk 3 | include $(FW_PATH)/definitions.mk 4 | 5 | LOCAL_SRCS=$(wildcard src/*.c) src/ucode_compressed.c src/templateram.c 6 | COMMON_SRCS=$(wildcard $(NEXMON_ROOT)/patches/common/*.c) 7 | FW_SRCS=$(wildcard $(FW_PATH)/*.c) 8 | 9 | OBJS=$(addprefix obj/,$(notdir $(LOCAL_SRCS:.c=.o)) $(notdir $(COMMON_SRCS:.c=.o)) $(notdir $(FW_SRCS:.c=.o))) 10 | 11 | CFLAGS= \ 12 | -fplugin=$(CCPLUGIN) \ 13 | -fplugin-arg-nexmon-objfile=$@ \ 14 | -fplugin-arg-nexmon-prefile=gen/nexmon.pre \ 15 | -fplugin-arg-nexmon-chipver=$(NEXMON_CHIP_NUM) \ 16 | -fplugin-arg-nexmon-fwver=$(NEXMON_FW_VERSION_NUM) \ 17 | -fno-strict-aliasing \ 18 | -DNEXMON_CHIP=$(NEXMON_CHIP) \ 19 | -DNEXMON_FW_VERSION=$(NEXMON_FW_VERSION) \ 20 | -DPATCHSTART=$(PATCHSTART) \ 21 | -DUCODESIZE=$(UCODESIZE) \ 22 | -DGIT_VERSION=\"$(GIT_VERSION)\" \ 23 | -DBUILD_NUMBER=\"$$(cat BUILD_NUMBER)\" \ 24 | -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -march=$(NEXMON_ARCH) \ 25 | -ffunction-sections -fdata-sections \ 26 | -I$(NEXMON_ROOT)/patches/include \ 27 | -Iinclude \ 28 | -I$(FW_PATH) 29 | 30 | all: fw_bcmdhd.bin 31 | 32 | init: FORCE 33 | $(Q)if ! test -f BUILD_NUMBER; then echo 0 > BUILD_NUMBER; fi 34 | $(Q)echo $$(($$(cat BUILD_NUMBER) + 1)) > BUILD_NUMBER 35 | $(Q)touch src/version.c 36 | $(Q)make -s -f $(NEXMON_ROOT)/patches/common/header.mk 37 | @printf "\033[0;31m CREATING DIRECTORIES\033[0m obj, gen, log\n" 38 | $(Q)mkdir -p obj gen log 39 | 40 | obj/%.o: src/%.c 41 | @printf "\033[0;31m COMPILING\033[0m %s => %s (details: log/compiler.log)\n" $< $@ 42 | $(Q)cat gen/nexmon.pre 2>>log/error.log | gawk '{ if ($$3 != "$@") print; }' > tmp && mv tmp gen/nexmon.pre 43 | $(Q)$(CC)gcc $(CFLAGS) -c $< -o $@ >>log/compiler.log 44 | 45 | obj/%.o: $(NEXMON_ROOT)/patches/common/%.c 46 | @printf "\033[0;31m COMPILING\033[0m %s => %s (details: log/compiler.log)\n" $< $@ 47 | $(Q)cat gen/nexmon.pre 2>>log/error.log | gawk '{ if ($$3 != "$@") print; }' > tmp && mv tmp gen/nexmon.pre 48 | $(Q)$(CC)gcc $(CFLAGS) -c $< -o $@ >>log/compiler.log 49 | 50 | obj/%.o: $(FW_PATH)/%.c 51 | @printf "\033[0;31m COMPILING\033[0m %s => %s (details: log/compiler.log)\n" $< $@ 52 | $(Q)cat gen/nexmon.pre 2>>log/error.log | gawk '{ if ($$3 != "$@") print; }' > tmp && mv tmp gen/nexmon.pre 53 | $(Q)$(CC)gcc $(CFLAGS) -c $< -o $@ >>log/compiler.log 54 | 55 | gen/nexmon2.pre: $(OBJS) 56 | @printf "\033[0;31m PREPARING\033[0m %s => %s\n" "gen/nexmon.pre" $@ 57 | $(Q)cat gen/nexmon.pre | awk '{ if ($$3 != "obj/flashpatches.o" && $$3 != "obj/wrapper.o") { print $$0; } }' > tmp 58 | $(Q)cat gen/nexmon.pre | awk '{ if ($$3 == "obj/flashpatches.o" || $$3 == "obj/wrapper.o") { print $$0; } }' >> tmp 59 | $(Q)cat tmp | awk '{ if ($$1 ~ /^0x/) { if ($$3 != "obj/flashpatches.o" && $$3 != "obj/wrapper.o") { if (!x[$$1]++) { print $$0; } } else { if (!x[$$1]) { print $$0; } } } else { print $$0; } }' > gen/nexmon2.pre 60 | 61 | gen/nexmon.ld: gen/nexmon2.pre $(OBJS) 62 | @printf "\033[0;31m GENERATING LINKER FILE\033[0m gen/nexmon.pre => %s\n" $@ 63 | $(Q)sort gen/nexmon2.pre | gawk -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.ld.awk > $@ 64 | 65 | gen/nexmon.mk: gen/nexmon2.pre $(OBJS) $(FW_PATH)/definitions.mk 66 | @printf "\033[0;31m GENERATING MAKE FILE\033[0m gen/nexmon.pre => %s\n" $@ 67 | $(Q)printf "fw_bcmdhd.bin: gen/patch.elf FORCE\n" > $@ 68 | $(Q)sort gen/nexmon2.pre | \ 69 | gawk -v src_file=gen/patch.elf -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.mk.1.awk | \ 70 | gawk -v ramstart=$(RAMSTART) -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.mk.2.awk >> $@ 71 | $(Q)printf "\nFORCE:\n" >> $@ 72 | $(Q)gawk '!a[$$0]++' $@ > tmp && mv tmp $@ 73 | 74 | gen/flashpatches.ld: gen/nexmon2.pre $(OBJS) 75 | @printf "\033[0;31m GENERATING LINKER FILE\033[0m gen/nexmon.pre => %s\n" $@ 76 | $(Q)sort gen/nexmon2.pre | \ 77 | gawk -f $(NEXMON_ROOT)/buildtools/scripts/flashpatches.ld.awk > $@ 78 | 79 | gen/flashpatches.mk: gen/nexmon2.pre $(OBJS) $(FW_PATH)/definitions.mk 80 | @printf "\033[0;31m GENERATING MAKE FILE\033[0m gen/nexmon.pre => %s\n" $@ 81 | $(Q)cat gen/nexmon2.pre | gawk \ 82 | -v fp_data_base=$(FP_DATA_BASE) \ 83 | -v fp_config_base=$(FP_CONFIG_BASE) \ 84 | -v fp_data_end_ptr=$(FP_DATA_END_PTR) \ 85 | -v fp_config_base_ptr_1=$(FP_CONFIG_BASE_PTR_1) \ 86 | -v fp_config_end_ptr_1=$(FP_CONFIG_END_PTR_1) \ 87 | -v fp_config_base_ptr_2=$(FP_CONFIG_BASE_PTR_2) \ 88 | -v fp_config_end_ptr_2=$(FP_CONFIG_END_PTR_2) \ 89 | -v ramstart=$(RAMSTART) \ 90 | -v out_file=fw_bcmdhd.bin \ 91 | -v src_file=gen/patch.elf \ 92 | -f $(NEXMON_ROOT)/buildtools/scripts/flashpatches.mk.awk > $@ 93 | 94 | gen/memory.ld: $(FW_PATH)/definitions.mk 95 | @printf "\033[0;31m GENERATING LINKER FILE\033[0m %s\n" $@ 96 | $(Q)printf "rom : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(ROMSTART) $(ROMSIZE) > $@ 97 | $(Q)printf "ram : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(RAMSTART) $(RAMSIZE) >> $@ 98 | $(Q)printf "patch : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(PATCHSTART) $(PATCHSIZE) >> $@ 99 | $(Q)printf "ucode : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(UCODESTART) $$(($(FP_CONFIG_BASE) - $(UCODESTART))) >> $@ 100 | $(Q)printf "fpconfig : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(FP_CONFIG_BASE) $(FP_CONFIG_SIZE) >> $@ 101 | 102 | gen/patch.elf: patch.ld gen/nexmon.ld gen/flashpatches.ld gen/memory.ld $(OBJS) 103 | @printf "\033[0;31m LINKING OBJECTS\033[0m => %s (details: log/linker.log, log/linker.err)\n" $@ 104 | $(Q)$(CC)ld -T $< -o $@ --gc-sections --print-gc-sections -M >>log/linker.log 2>>log/linker.err 105 | 106 | fw_bcmdhd.bin: init gen/patch.elf $(FW_PATH)/$(RAM_FILE) gen/nexmon.mk gen/flashpatches.mk 107 | $(Q)cp $(FW_PATH)/$(RAM_FILE) $@ 108 | @printf "\033[0;31m APPLYING FLASHPATCHES\033[0m gen/flashpatches.mk => %s (details: log/flashpatches.log)\n" $@ 109 | $(Q)make -f gen/flashpatches.mk >>log/flashpatches.log 2>>log/flashpatches.log 110 | @printf "\033[0;31m APPLYING PATCHES\033[0m gen/nexmon.mk => %s (details: log/patches.log)\n" $@ 111 | $(Q)make -f gen/nexmon.mk >>log/patches.log 2>>log/flashpatches.log 112 | 113 | ################################################################### 114 | # ucode compression related 115 | ################################################################### 116 | 117 | ifneq ($(wildcard src/ucode.asm), ) 118 | gen/ucode.bin: src/ucode.asm 119 | @printf "\033[0;31m ASSEMBLING UCODE\033[0m %s => %s\n" $< $@ 120 | 121 | ifneq ($(wildcard $(NEXMON_ROOT)/buildtools/b43/assembler/b43-asm.bin), ) 122 | $(Q)PATH=$(PATH):$(NEXMON_ROOT)/buildtools/b43/assembler $(NEXMON_ROOT)/buildtools/b43/assembler/b43-asm $< $@ --format raw-le32 123 | else 124 | $(error Warning: please compile b43-asm.bin first) 125 | endif 126 | 127 | else 128 | gen/ucode.bin: $(FW_PATH)/ucode.bin 129 | @printf "\033[0;31m COPYING UCODE\033[0m %s => %s\n" $< $@ 130 | $(Q)cp $< $@ 131 | endif 132 | 133 | gen/ucode_compressed.bin: gen/ucode.bin 134 | @printf "\033[0;31m COMPRESSING UCODE\033[0m %s => %s\n" $< $@ 135 | $(Q)cat $< | $(ZLIBFLATE) > $@ 136 | 137 | src/ucode_compressed.c: gen/ucode_compressed.bin 138 | @printf "\033[0;31m GENERATING C FILE\033[0m %s => %s\n" $< $@ 139 | $(Q)printf "#pragma NEXMON targetregion \"ucode\"\n\n" > $@ 140 | $(Q)cd $(dir $<) && xxd -i $(notdir $<) >> $(shell pwd)/$@ 141 | 142 | src/templateram.c: $(FW_PATH)/templateram.bin 143 | @printf "\033[0;31m GENERATING C FILE\033[0m %s => %s\n" $< $@ 144 | $(Q)printf "#pragma NEXMON targetregion \"ucode\"\n\n" > $@ 145 | $(Q)cd $(dir $<) && xxd -i $(notdir $<) >> $(shell pwd)/$@ 146 | 147 | ################################################################### 148 | 149 | check-nexmon-setup-env: 150 | ifndef NEXMON_SETUP_ENV 151 | $(error run 'source setup_env.sh' first in the repository\'s root directory) 152 | endif 153 | 154 | install-firmware: fw_bcmdhd.bin 155 | @printf "\033[0;31m REMOUNTING /system\033[0m\n" 156 | $(Q)adb shell 'su -c "mount -o rw,remount /system"' 157 | @printf "\033[0;31m COPYING TO PHONE\033[0m %s => /sdcard/%s\n" $< $< 158 | $(Q)adb push $< /sdcard/ >> log/adb.log 2>> log/adb.log 159 | @printf "\033[0;31m COPYING\033[0m /sdcard/fw_bcmdhd.bin => /vendor/firmware/fw_bcmdhd.bin\n" 160 | $(Q)adb shell 'su -c "cp /sdcard/fw_bcmdhd.bin /vendor/firmware/fw_bcmdhd.bin"' 161 | @printf "\033[0;31m RELOADING FIRMWARE\033[0m\n" 162 | $(Q)adb shell 'su -c "ifconfig wlan0 down && ifconfig wlan0 up"' 163 | 164 | backup-firmware: FORCE 165 | adb shell 'su -c "cp /vendor/firmware/fw_bcmdhd.bin /sdcard/fw_bcmdhd.orig.bin"' 166 | adb pull /sdcard/fw_bcmdhd.orig.bin 167 | 168 | install-backup: fw_bcmdhd.orig.bin 169 | adb shell 'su -c "mount -o rw,remount /system"' && \ 170 | adb push $< /sdcard/ && \ 171 | adb shell 'su -c "cp /sdcard/fw_bcmdhd.bin /vendor/firmware/fw_bcmdhd.bin"' 172 | adb shell 'su -c "ifconfig wlan0 down && ifconfig wlan0 up"' 173 | 174 | clean-firmware: FORCE 175 | @printf "\033[0;31m CLEANING\033[0m\n" 176 | $(Q)rm -fr fw_bcmdhd.bin obj gen log src/ucode_compressed.c src/templateram.c 177 | 178 | clean: clean-firmware 179 | $(Q)rm -f BUILD_NUMBER 180 | 181 | FORCE: 182 | -------------------------------------------------------------------------------- /src/debugger.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * * 3 | * ########### ########### ########## ########## * 4 | * ############ ############ ############ ############ * 5 | * ## ## ## ## ## ## ## * 6 | * ## ## ## ## ## ## ## * 7 | * ########### #### ###### ## ## ## ## ###### * 8 | * ########### #### # ## ## ## ## # # * 9 | * ## ## ###### ## ## ## ## # # * 10 | * ## ## # ## ## ## ## # # * 11 | * ############ ##### ###### ## ## ## ##### ###### * 12 | * ########### ########### ## ## ## ########## * 13 | * * 14 | * S E C U R E M O B I L E N E T W O R K I N G * 15 | * * 16 | * Warning: * 17 | * * 18 | * Our software may damage your hardware and may void your hardware’s * 19 | * warranty! You use our tools at your own risk and responsibility! * 20 | * * 21 | * License: * 22 | * Copyright (c) 2017 NexMon Team * 23 | * * 24 | * Permission is hereby granted, free of charge, to any person obtaining * 25 | * a copy of this software and associated documentation files (the * 26 | * "Software"), to deal in the Software without restriction, including * 27 | * without limitation the rights to use, copy, modify, merge, publish, * 28 | * distribute copies of the Software, and to permit persons to whom the * 29 | * Software is furnished to do so, subject to the following conditions: * 30 | * * 31 | * The above copyright notice and this permission notice shall be included * 32 | * in all copies or substantial portions of the Software. * 33 | * * 34 | * Any use of the Software which results in an academic publication or * 35 | * other publication which includes a bibliography must include a citation * 36 | * to the author's publication "M. Schulz, D. Wegemer and M. Hollick. * 37 | * NexMon: A Cookbook for Firmware Modifications on Smartphones to Enable * 38 | * Monitor Mode.". * 39 | * * 40 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 41 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 42 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 43 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * 44 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * 45 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * 46 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 47 | * * * 48 | **************************************************************************/ 49 | 50 | #pragma NEXMON targetregion "patch" 51 | 52 | #include // definition of firmware version macros 53 | #include // wrapper definitions for functions that already exist in the firmware 54 | #include // structures that are used by the code in the firmware 55 | #include // useful helper functions 56 | #include // macros used to craete patches such as BLPatch, BPatch, ... 57 | #include // contains macros to access the debug hardware 58 | 59 | /** 60 | * Replaces the SP and LR registers on the stack with those of the system mode. 61 | * As we decided to stay in abort mode to handle breakpoints and watchpoints, we need to 62 | * change to system mode to fetch the correct sp and lr registers to store the correct state 63 | * on the stack. The required state is the one before the prefetch/data abort exception. 64 | */ 65 | // function implemented in debugger_base.c 66 | extern struct trace * fix_sp_lr(struct trace *trace); 67 | extern void set_abort_stack_pointer(void); 68 | 69 | /** 70 | * Saves one-hot encoded which breakpoint was hit 71 | */ 72 | unsigned char breakpoint_hit = 0; 73 | 74 | /** 75 | * Saves one-hot encoded whether we should perform single stepping 76 | */ 77 | unsigned char single_stepping = 0; 78 | 79 | /** 80 | * Breakpoint step counter, saves how many steps we performed after triggering the breakpoint 81 | */ 82 | 83 | unsigned int breakpoint_cnt0 = 0; 84 | unsigned int breakpoint_cnt1 = 0; 85 | unsigned int breakpoint_cnt2 = 0; 86 | unsigned int breakpoint_cnt3 = 0; 87 | 88 | /** 89 | * Saves one-hot encoded which watchpoint was hit 90 | */ 91 | unsigned char watchpoint_hit = 0; 92 | 93 | /** 94 | * Watchpoint hit counter, saves how often a watchpoint was hit 95 | */ 96 | unsigned char watchpoint_hit_counter = 0; 97 | 98 | /** 99 | * Watchpoint hit limit, defines how often a watchpoint should trigger 100 | */ 101 | unsigned char watchpoint_hit_limit = 20; 102 | 103 | /** 104 | * Watchpoint handler function 105 | */ 106 | void __attribute__((optimize("O0"))) 107 | handle_data_abort_exception(struct trace *trace) 108 | { 109 | fix_sp_lr(trace); 110 | 111 | // TODO 112 | // Currently I do not know how to find out, which watchpoint was triggered, so here I always handle watchpoint 0 113 | watchpoint_hit |= DBGWP0; 114 | 115 | // Disable the watchpoint so that the instruction that triggered the watchpoint can be executed without triggering the watchpoint again. 116 | dbg_disable_watchpoint(0); 117 | dbg_disable_watchpoint(1); 118 | dbg_disable_watchpoint(2); 119 | dbg_disable_watchpoint(3); 120 | 121 | printf(" WP hit pc=%08x\n", trace->pc); 122 | 123 | // Set breakpoint 3 to reset the watchpoint after executing the instruction that triggered the watchpoint. 124 | dbg_set_breakpoint_for_addr_mismatch(3, trace->PC); 125 | } 126 | 127 | /** 128 | * Breakpoint handler function 129 | */ 130 | void __attribute__((optimize("O0"))) 131 | handle_pref_abort_exception(struct trace *trace) 132 | { 133 | fix_sp_lr(trace); 134 | 135 | // check whether breakpoint 0 is enabled 136 | if(dbg_is_breakpoint_enabled(0)) { 137 | if (dbg_triggers_on_breakpoint_address(0, trace->pc)) { 138 | // to continue executed on the instruction where breakpoint 0 triggered, we set the breakpoint type 139 | // to address mismatch to trigger on any instruction except the breakpoint address 140 | dbg_set_breakpoint_type_to_instr_addr_mismatch(0); 141 | 142 | if (!strncmp((char *) trace->r1, "sdpcmd_dpc", 10)) { 143 | printf(" BP0 step %d: pc=%08x *r1=%s\n", breakpoint_cnt0, trace->pc, trace->r1); 144 | // activate single-stepping for this breakpoint 145 | single_stepping |= DBGBP0; 146 | } 147 | 148 | // to know which breakpoint mismatch was triggerd on a next breakpoint hit, we set a bit in the breakpoint_hit variable 149 | breakpoint_hit |= DBGBP0; 150 | } else if (breakpoint_hit & DBGBP0) { 151 | // check whether single-stepping should be activated for this breakpoint 152 | if (single_stepping & DBGBP0) { 153 | // we reset the breakpoint for address mismatch for single-stepping 154 | dbg_set_breakpoint_for_addr_mismatch(0, trace->pc); 155 | 156 | // increase the breakpoint step counter 157 | breakpoint_cnt0++; 158 | 159 | printf(" BP0 step %d: pc=%08x\n", breakpoint_cnt0, trace->pc); 160 | 161 | // after 4 steps, we want to stop single-stepping 162 | if ((breakpoint_cnt0 == 4)) { 163 | // we can now reset the breakpoint to trigger on printf again (in case we do not want to disable it) 164 | dbg_set_breakpoint_for_addr_match(0, 0x126f0); 165 | 166 | // we reset the breakpoint counter back to zero 167 | breakpoint_cnt0 = 0; 168 | 169 | // we disable the breakpoint 170 | //dbg_disable_breakpoint(0); 171 | 172 | // we unset the bit in the breakpoint_hit variable for breakpoint 0 173 | breakpoint_hit &= ~DBGBP0; 174 | 175 | // we disable single-stepping for this breakpoint 176 | single_stepping &= ~DBGBP0; 177 | 178 | printf(" BP0 single-stepping done\n"); 179 | } 180 | } else { 181 | // we reset the breakpoint for address matching 182 | dbg_set_breakpoint_type_to_instr_addr_match(0); 183 | 184 | // we reset the breakpoint counter back to zero 185 | breakpoint_cnt0 = 0; 186 | 187 | // we unset the bit in the breakpoint_hit variable for breakpoint 0 188 | breakpoint_hit &= ~DBGBP0; 189 | } 190 | } 191 | } 192 | 193 | // check whether breakpoint 3 is enabled 194 | if (dbg_is_breakpoint_enabled(3)) { 195 | // Used to reset watchpoint 196 | if (watchpoint_hit & DBGWP0) { 197 | dbg_disable_breakpoint(3); 198 | 199 | // we unset the bit in the watchpoint_hit variable for watchpoint 0 200 | watchpoint_hit &= ~DBGWP0; 201 | 202 | // reenable watchpoint 0 only if the hit counter is below our limit 203 | if (++watchpoint_hit_counter < watchpoint_hit_limit) { 204 | dbg_enable_watchpoint(0); 205 | } else { 206 | printf("WP0 not reset (%d)\n", watchpoint_hit_counter); 207 | } 208 | } 209 | } 210 | } 211 | 212 | void 213 | set_debug_registers(void) 214 | { 215 | set_abort_stack_pointer(); 216 | dbg_unlock_debug_registers(); 217 | dbg_disable_breakpoint(0); 218 | dbg_disable_breakpoint(1); 219 | dbg_disable_breakpoint(2); 220 | dbg_disable_breakpoint(3); 221 | dbg_enable_monitor_mode_debugging(); 222 | 223 | // Programm Breakpoint to match the instruction we want to hit 224 | dbg_set_breakpoint_for_addr_match(0, 0x126f0); // trigger on printf 225 | 226 | // Program watchpoint to match the address we want to monitor 227 | //dbg_set_watchpoint_for_addr_match(0, 0x1D3A59); // trigger on "TCAM: %d used: %d exceed:%d" string 228 | dbg_set_watchpoint_for_addr_match(0, 0x1FC2A4); // trigger on "%s: Broadcom SDPCMD CDC driver" string 229 | } 230 | -------------------------------------------------------------------------------- /src/debugger_base.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * * 3 | * ########### ########### ########## ########## * 4 | * ############ ############ ############ ############ * 5 | * ## ## ## ## ## ## ## * 6 | * ## ## ## ## ## ## ## * 7 | * ########### #### ###### ## ## ## ## ###### * 8 | * ########### #### # ## ## ## ## # # * 9 | * ## ## ###### ## ## ## ## # # * 10 | * ## ## # ## ## ## ## # # * 11 | * ############ ##### ###### ## ## ## ##### ###### * 12 | * ########### ########### ## ## ## ########## * 13 | * * 14 | * S E C U R E M O B I L E N E T W O R K I N G * 15 | * * 16 | * Warning: * 17 | * * 18 | * Our software may damage your hardware and may void your hardware’s * 19 | * warranty! You use our tools at your own risk and responsibility! * 20 | * * 21 | * License: * 22 | * Copyright (c) 2017 NexMon Team * 23 | * * 24 | * Permission is hereby granted, free of charge, to any person obtaining * 25 | * a copy of this software and associated documentation files (the * 26 | * "Software"), to deal in the Software without restriction, including * 27 | * without limitation the rights to use, copy, modify, merge, publish, * 28 | * distribute copies of the Software, and to permit persons to whom the * 29 | * Software is furnished to do so, subject to the following conditions: * 30 | * * 31 | * The above copyright notice and this permission notice shall be included * 32 | * in all copies or substantial portions of the Software. * 33 | * * 34 | * Any use of the Software which results in an academic publication or * 35 | * other publication which includes a bibliography must include a citation * 36 | * to the author's publication "M. Schulz, D. Wegemer and M. Hollick. * 37 | * NexMon: A Cookbook for Firmware Modifications on Smartphones to Enable * 38 | * Monitor Mode.". * 39 | * * 40 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 41 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 42 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 43 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * 44 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * 45 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * 46 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 47 | * * * 48 | **************************************************************************/ 49 | 50 | #pragma NEXMON targetregion "patch" 51 | 52 | #include // definition of firmware version macros 53 | #include // wrapper definitions for functions that already exist in the firmware 54 | #include // structures that are used by the code in the firmware 55 | #include // useful helper functions 56 | #include // macros used to craete patches such as BLPatch, BPatch, ... 57 | #include // contains macros to access the debug hardware 58 | 59 | // functions implemented in debugger.c 60 | extern void handle_pref_abort_exception(struct trace *trace); 61 | extern void set_debug_registers(void); 62 | 63 | /** 64 | * Replaces the SP and LR registers on the stack with those of the system mode. 65 | * As we decided to stay in abort mode to handle breakpoints and watchpoints, we need to 66 | * change to system mode to fetch the correct sp and lr registers to store the correct state 67 | * on the stack. The required state is the one before the prefetch/data abort exception. 68 | */ 69 | struct trace * __attribute__((optimize("O0"))) 70 | fix_sp_lr(struct trace *trace) 71 | { 72 | register unsigned int sp_sys asm("r1"); 73 | register unsigned int lr_sys asm("r2"); 74 | 75 | dbg_disable_monitor_mode_debugging(); 76 | dbg_change_processor_mode(DBG_PROCESSOR_MODE_SYS); 77 | asm("mov %[result], sp" : [result] "=r" (sp_sys)); 78 | asm("mov %[result], lr" : [result] "=r" (lr_sys)); 79 | dbg_change_processor_mode(DBG_PROCESSOR_MODE_ABT); 80 | dbg_enable_monitor_mode_debugging(); 81 | 82 | trace->lr = lr_sys; 83 | trace->sp = sp_sys; 84 | 85 | return trace; 86 | } 87 | 88 | // 1 KiBi for stack in abort mode 89 | uint32 stack_abt[256] = { 0x54424153 }; 90 | 91 | /** 92 | * Sets the stack pointer of the abort mode to be at the end of the current stack area, a part that is likely not used during regular program execution 93 | */ 94 | void __attribute__((optimize("O0"))) 95 | set_abort_stack_pointer(void) 96 | { 97 | register unsigned int sp_abt asm("r0") = (uint32) &stack_abt[255]; 98 | 99 | dbg_change_processor_mode(DBG_PROCESSOR_MODE_ABT); 100 | asm("mov sp, %[value]" : : [value] "r" (sp_abt)); 101 | dbg_change_processor_mode(DBG_PROCESSOR_MODE_SYS); 102 | } 103 | 104 | /** 105 | * is called before the wlc_ucode_download function to print our hello world message 106 | */ 107 | __attribute__((at(0x180020, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 108 | __attribute__((naked)) void 109 | c_main_hook(void) 110 | { 111 | asm( 112 | "push {r0-r3,lr}\n" // Push the registers that could be modified by a call to a C function 113 | "bl set_debug_registers\n" // Call a C function 114 | "pop {r0-r3,lr}\n" // Pop the registers that were saved before 115 | "b c_main\n" // Call the hooked function 116 | ); 117 | } 118 | 119 | __attribute__((at(0x181240, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 120 | GenericPatch4(c_main_hook, c_main_hook + 1); 121 | 122 | /** 123 | * Exception handler that is triggered on reset/startup/powerup 124 | */ 125 | __attribute__((naked)) void 126 | tr_reset_hook(void) 127 | { 128 | asm( 129 | "mrs r0, cpsr\n" 130 | "mov r1, #0x1f\n" 131 | "bic r0, r0, r1\n" 132 | "mov r1, #0xdf\n" 133 | "orr r0, r0, r1\n" 134 | "msr cpsr_fc, r0\n" 135 | "b setup\n" 136 | ); 137 | } 138 | 139 | /** 140 | * Exception handler that is triggered by watchpoint or illegal address access 141 | */ 142 | __attribute__((at(0x180FAA, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 143 | __attribute__((naked)) void 144 | tr_data_abort_hook(void) 145 | { 146 | asm( 147 | "sub lr, lr, #8\n" // we directly subtract 4 from the link register (original code overwrites the stack pointer first) 148 | "srsdb sp!, #0x17\n" // stores return state (LR and SPSR) to the stack of the abort mode (0x17) (original codes switches to system mode (0x1F)) 149 | "push {r0}\n" 150 | "push {lr}\n" // here we do not get the expected link register from the system mode, but the link register from the abort mode 151 | "sub sp, sp, #24\n" 152 | "push {r0-r7}\n" 153 | "eor r0, r0, r0\n" 154 | "add r0, r0, #4\n" 155 | "b handle_exceptions\n" 156 | ); 157 | } 158 | 159 | /** 160 | * Exception handler that is triggered by breakpoint 161 | */ 162 | __attribute__((at(0x180F88, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 163 | __attribute__((naked)) void 164 | tr_pref_abort_hook(void) 165 | { 166 | asm( 167 | "sub lr, lr, #4\n" // we directly subtract 4 from the link register (original code overwrites the stack pointer first) 168 | "srsdb sp!, #0x17\n" // stores return state (LR and SPSR) to the stack of the abort mode (0x17) (original codes switches to system mode (0x1F)) 169 | "push {r0}\n" 170 | "push {lr}\n" // here we do not get the expected link register from the system mode, but the link register from the abort mode 171 | "sub sp, sp, #24\n" 172 | "push {r0-r7}\n" 173 | "eor r0, r0, r0\n" 174 | "add r0, r0, #3\n" 175 | "b handle_exceptions\n" 176 | ); 177 | } 178 | 179 | __attribute__((naked)) void 180 | choose_exception_handler(void) 181 | { 182 | asm( 183 | "cmp r0, #3\n" 184 | "beq label_pref_abort\n" 185 | "cmp r0, #4\n" 186 | "beq label_data_abort\n" 187 | "label_continue_exception:\n" 188 | "cmp r0, #6\n" // check if fast interrupt 189 | "bne label_other_exception\n" // if interrupt was not a fast interrupt 190 | "cmp r1, #64\n" // if FIQ was enabled, enable it again 191 | "beq label_other_exception\n" 192 | "cpsie f\n" 193 | "label_other_exception:\n" 194 | "mov r0, sp\n" 195 | "push {lr}\n" 196 | "pop {lr}\n" 197 | "b dump_stack_print_dbg_stuff_intr_handler\n" 198 | "label_pref_abort:\n" 199 | "mov r0, sp\n" 200 | "push {lr}\n" 201 | "pop {lr}\n" 202 | "b handle_pref_abort_exception\n" 203 | "label_data_abort:\n" 204 | "mrc p15, 0, r0, c5, c0, 0\n" // read DFSR 205 | "and r0, r0, #0x1F\n" // select FS bits from DFSR 206 | "cmp r0, #2\n" // compare FS to "debug event" 207 | "bne label_continue_exception\n" // if data abort not caused by a "debug event", go to regular exception handler 208 | "mov r0, sp\n" 209 | "b handle_data_abort_exception\n" 210 | ); 211 | } 212 | 213 | /** 214 | * 215 | */ 216 | __attribute__((at(0x181032, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 217 | __attribute__((naked)) void 218 | handle_exceptions(void) 219 | { 220 | asm( 221 | "mov r4, sp\n" 222 | "add r4, r4, #64\n" 223 | "ldmia r4!, {r1,r3}\n" 224 | "mrs r2, cpsr\n" 225 | "push {r0-r3}\n" 226 | "sub r4, r4, #12\n" 227 | "str r1, [r4]\n" 228 | "and r1, r3, #64\n" // r3 is CPSR_SYS, bit 6 is the FIQ mask bit 229 | "mov r7, sp\n" 230 | "add r7, r7, #88\n" 231 | "mov r6, r12\n" 232 | "mov r5, r11\n" 233 | "mov r4, r10\n" 234 | "mov r3, r9\n" 235 | "mov r2, r8\n" 236 | "add sp, sp, #72\n" 237 | "push {r2-r7}\n" 238 | /* 239 | * Now the stack looks like this: 240 | * SPSR -> CPSR_SYS 241 | * LR_ABT -> PC_SYS 242 | * PC_SYS 243 | * LR_ABT call fix_sp_lr to change this to LR_SYS 244 | * SP_ABT call fix_sp_lr to change this to SP_SYS 245 | * R12 246 | * R11 247 | * R10 248 | * R9 249 | * R8 250 | * R7 251 | * R6 252 | * R5 253 | * R4 254 | * R3 255 | * R2 256 | * R1 257 | * R0 258 | * CPSR_SYS 259 | * CPSR_ABT 260 | * PC_SYS 261 | * Exception ID 262 | */ 263 | "sub sp, sp, #48\n" 264 | "bl choose_exception_handler\n" 265 | "cpsid if\n" 266 | "add sp, sp, #48\n" 267 | "pop {r0-r6}\n" 268 | "mov r8, r0\n" 269 | "mov r9, r1\n" 270 | "mov r10, r2\n" 271 | "mov r11, r3\n" 272 | "mov r12, r4\n" 273 | "mov lr, r6\n" 274 | "sub sp, sp, #60\n" 275 | "pop {r0-r7}\n" 276 | "add sp, sp, #32\n" 277 | "rfefd sp!\n" 278 | ); 279 | } 280 | 281 | // The following patch, that is necessary to access debug registers in an interrupt handler breaks normal wifi operation 282 | // write nops over the si_update_chipcontrol_shm(sii, 5, 16, 0) call in si_setup_cores 283 | __attribute__((at(0x18545A, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) 284 | GenericPatch4(activate_debugger, 0xBF00BF00); 285 | 286 | 287 | --------------------------------------------------------------------------------