├── .gitignore ├── DirectHW.c ├── DirectHW.dmg ├── DirectHW.h ├── Makefile ├── README.md ├── check-flockdn ├── rdmem.c ├── rdpci.c ├── unhex └── wrmem.c /.gitignore: -------------------------------------------------------------------------------- 1 | .*.d 2 | .*.swp 3 | *.o 4 | rdmem 5 | wrmem 6 | rdpci 7 | -------------------------------------------------------------------------------- /DirectHW.c: -------------------------------------------------------------------------------- 1 | /* 2 | * DirectHW.c - userspace part for DirectHW 3 | * 4 | * Copyright © 2008-2010 coresystems GmbH 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "DirectHW.h" 26 | 27 | #ifndef MAP_FAILED 28 | #define MAP_FAILED ((void *)-1) 29 | #endif 30 | 31 | /* define WANT_OLD_API for support of OSX 10.4 and earlier */ 32 | #undef WANT_OLD_API 33 | 34 | /* define DEBUG to print Framework debugging information */ 35 | static const int debug; 36 | 37 | #define err_get_system(err) (((err)>>26)&0x3f) 38 | #define err_get_sub(err) (((err)>>14)&0xfff) 39 | #define err_get_code(err) ((err)&0x3fff) 40 | 41 | enum { 42 | kReadIO, 43 | kWriteIO, 44 | kPrepareMap, 45 | kReadMSR, 46 | kWriteMSR, 47 | kNumberOfMethods 48 | }; 49 | 50 | typedef struct { 51 | UInt32 offset; 52 | UInt32 width; 53 | UInt32 data; 54 | } iomem_t; 55 | 56 | typedef struct { 57 | UInt64 addr; 58 | UInt64 size; 59 | } map_t; 60 | 61 | typedef struct { 62 | UInt32 core; 63 | UInt32 index; 64 | UInt32 hi; 65 | UInt32 lo; 66 | } msrcmd_t; 67 | 68 | static io_connect_t connect = -1; 69 | static io_service_t iokit_uc; 70 | 71 | static int darwin_init(void) 72 | { 73 | kern_return_t err; 74 | 75 | /* Note the actual security happens in the kernel module. 76 | * This check is just candy to be able to get nicer output 77 | */ 78 | if (getuid() != 0) { 79 | /* Fun's reserved for root */ 80 | errno = EPERM; 81 | return -1; 82 | } 83 | 84 | /* Get the DirectHW driver service */ 85 | iokit_uc = IOServiceGetMatchingService(kIOMasterPortDefault, 86 | IOServiceMatching("DirectHWService")); 87 | 88 | if (!iokit_uc) { 89 | fprintf(stderr, "DirectHW.kext not loaded.\n"); 90 | errno = ENOSYS; 91 | return -1; 92 | } 93 | 94 | /* Create an instance */ 95 | err = IOServiceOpen(iokit_uc, mach_task_self(), 0, &connect); 96 | 97 | /* Should not go further if error with service open */ 98 | if (err != KERN_SUCCESS) { 99 | fprintf(stderr, "Could not create DirectHW instance.\n"); 100 | errno = ENOSYS; 101 | return -1; 102 | } 103 | 104 | return 0; 105 | } 106 | 107 | static void darwin_cleanup(void) 108 | { 109 | IOServiceClose(connect); 110 | } 111 | 112 | static int darwin_ioread(int pos, unsigned char * buf, int len) 113 | { 114 | 115 | kern_return_t err; 116 | size_t dataInLen = sizeof(iomem_t); 117 | size_t dataOutLen = sizeof(iomem_t); 118 | iomem_t in; 119 | iomem_t out; 120 | UInt32 tmpdata; 121 | 122 | in.width = len; 123 | in.offset = pos; 124 | 125 | if (len > 4) 126 | return 1; 127 | 128 | #if !defined(__LP64__) && defined(WANT_OLD_API) 129 | /* Check if OSX 10.5 API is available */ 130 | if (IOConnectCallStructMethod != NULL) { 131 | #endif 132 | err = IOConnectCallStructMethod(connect, kReadIO, &in, dataInLen, &out, &dataOutLen); 133 | #if !defined(__LP64__) && defined(WANT_OLD_API) 134 | } else { 135 | /* Use old API */ 136 | err = IOConnectMethodStructureIStructureO(connect, kReadIO, dataInLen, &dataOutLen, &in, &out); 137 | } 138 | #endif 139 | 140 | if (err != KERN_SUCCESS) 141 | return 1; 142 | 143 | tmpdata = out.data; 144 | 145 | switch (len) { 146 | case 1: 147 | memcpy(buf, &tmpdata, 1); 148 | break; 149 | case 2: 150 | memcpy(buf, &tmpdata, 2); 151 | break; 152 | case 4: 153 | memcpy(buf, &tmpdata, 4); 154 | break; 155 | } 156 | 157 | return 0; 158 | } 159 | 160 | static int darwin_iowrite(int pos, unsigned char * buf, int len) 161 | { 162 | kern_return_t err; 163 | size_t dataInLen = sizeof(iomem_t); 164 | size_t dataOutLen = sizeof(iomem_t); 165 | iomem_t in; 166 | iomem_t out; 167 | 168 | in.width = len; 169 | in.offset = pos; 170 | memcpy(&in.data, buf, len); 171 | 172 | if (len > 4) 173 | return 1; 174 | 175 | #if !defined(__LP64__) && defined(WANT_OLD_API) 176 | /* Check if OSX 10.5 API is available */ 177 | if (IOConnectCallStructMethod != NULL) { 178 | #endif 179 | err = IOConnectCallStructMethod(connect, kWriteIO, &in, dataInLen, &out, &dataOutLen); 180 | #if !defined(__LP64__) && defined(WANT_OLD_API) 181 | } else { 182 | /* Use old API */ 183 | err = IOConnectMethodStructureIStructureO(connect, kWriteIO, dataInLen, &dataOutLen, &in, &out); 184 | } 185 | #endif 186 | 187 | if (err != KERN_SUCCESS) 188 | return 1; 189 | 190 | return 0; 191 | } 192 | 193 | 194 | /* Compatibility interface */ 195 | 196 | unsigned char inb(unsigned short addr) 197 | { 198 | unsigned char ret; 199 | darwin_ioread(addr, &ret, 1); 200 | return ret; 201 | } 202 | 203 | unsigned short inw(unsigned short addr) 204 | { 205 | unsigned short ret; 206 | darwin_ioread(addr, (unsigned char *)&ret, 2); 207 | return ret; 208 | } 209 | 210 | unsigned int inl(unsigned short addr) 211 | { 212 | unsigned int ret; 213 | darwin_ioread(addr, (unsigned char *)&ret, 4); 214 | return ret; 215 | } 216 | 217 | void outb(unsigned char val, unsigned short addr) 218 | { 219 | darwin_iowrite(addr, &val, 1); 220 | } 221 | 222 | void outw(unsigned short val, unsigned short addr) 223 | { 224 | darwin_iowrite(addr, (unsigned char *)&val, 2); 225 | } 226 | 227 | void outl(unsigned int val, unsigned short addr) 228 | { 229 | darwin_iowrite(addr, (unsigned char *)&val, 4); 230 | } 231 | 232 | int iopl(int level __attribute__((unused))) 233 | { 234 | atexit(darwin_cleanup); 235 | return darwin_init(); 236 | } 237 | 238 | void *map_physical(uint64_t phys_addr, size_t len) 239 | { 240 | kern_return_t err; 241 | #if __LP64__ 242 | mach_vm_address_t addr; 243 | mach_vm_size_t size; 244 | #else 245 | vm_address_t addr; 246 | vm_size_t size; 247 | #endif 248 | size_t dataInLen = sizeof(map_t); 249 | size_t dataOutLen = sizeof(map_t); 250 | map_t in, out; 251 | 252 | in.addr = phys_addr; 253 | in.size = len; 254 | 255 | if (debug) 256 | fprintf(stderr, "map_phys: phys %08"PRIx64", %08zx\n", phys_addr, len); 257 | 258 | #if !defined(__LP64__) && defined(WANT_OLD_API) 259 | /* Check if OSX 10.5 API is available */ 260 | if (IOConnectCallStructMethod != NULL) { 261 | #endif 262 | err = IOConnectCallStructMethod(connect, kPrepareMap, &in, dataInLen, &out, &dataOutLen); 263 | #if !defined(__LP64__) && defined(WANT_OLD_API) 264 | } else { 265 | /* Use old API */ 266 | err = IOConnectMethodStructureIStructureO(connect, kPrepareMap, dataInLen, &dataOutLen, &in, &out); 267 | } 268 | #endif 269 | 270 | if (err != KERN_SUCCESS) { 271 | fprintf(stderr, "\nError(kPrepareMap): system 0x%x subsystem 0x%x code 0x%x ", 272 | err_get_system(err), err_get_sub(err), err_get_code(err)); 273 | 274 | fprintf(stderr, "physical 0x%08"PRIx64"[0x%zx]\n", phys_addr, len); 275 | 276 | switch (err_get_code(err)) { 277 | case 0x2c2: fprintf(stderr, "Invalid argument.\n"); errno = EINVAL; break; 278 | case 0x2cd: fprintf(stderr, "Device not open.\n"); errno = ENOENT; break; 279 | } 280 | 281 | return MAP_FAILED; 282 | } 283 | 284 | err = IOConnectMapMemory(connect, 0, mach_task_self(), 285 | &addr, &size, kIOMapAnywhere | kIOMapInhibitCache); 286 | 287 | /* Now this is odd; The above connect seems to be unfinished at the 288 | * time the function returns. So wait a little bit, or the calling 289 | * program will just segfault. Bummer. Who knows a better solution? 290 | */ 291 | usleep(1000); 292 | 293 | if (err != KERN_SUCCESS) { 294 | fprintf(stderr, "\nError(IOConnectMapMemory): system 0x%x subsystem 0x%x code 0x%x ", 295 | err_get_system(err), err_get_sub(err), err_get_code(err)); 296 | 297 | fprintf(stderr, "physical 0x%08"PRIx64"[0x%zx]\n", phys_addr, len); 298 | 299 | switch (err_get_code(err)) { 300 | case 0x2c2: fprintf(stderr, "Invalid argument.\n"); errno = EINVAL; break; 301 | case 0x2cd: fprintf(stderr, "Device not open.\n"); errno = ENOENT; break; 302 | } 303 | 304 | return MAP_FAILED; 305 | } 306 | 307 | if (debug) 308 | fprintf(stderr, "map_phys: virt %08"PRIx64", %08zx\n", addr, (size_t) size); 309 | 310 | return (void *)addr; 311 | } 312 | 313 | void unmap_physical(void *virt_addr __attribute__((unused)), size_t len __attribute__((unused))) 314 | { 315 | // Nut'n Honey 316 | } 317 | 318 | static int current_logical_cpu = 0; 319 | 320 | msr_t rdmsr(int addr) 321 | { 322 | kern_return_t err; 323 | size_t dataInLen = sizeof(msrcmd_t); 324 | size_t dataOutLen = sizeof(msrcmd_t); 325 | msrcmd_t in, out; 326 | msr_t ret = { INVALID_MSR_HI, INVALID_MSR_LO }; 327 | 328 | in.core = current_logical_cpu; 329 | in.index = addr; 330 | 331 | #if !defined(__LP64__) && defined(WANT_OLD_API) 332 | /* Check if OSX 10.5 API is available */ 333 | if (IOConnectCallStructMethod != NULL) { 334 | #endif 335 | err = IOConnectCallStructMethod(connect, kReadMSR, &in, dataInLen, &out, &dataOutLen); 336 | #if !defined(__LP64__) && defined(WANT_OLD_API) 337 | } else { 338 | /* Use old API */ 339 | err = IOConnectMethodStructureIStructureO(connect, kReadMSR, dataInLen, &dataOutLen, &in, &out); 340 | } 341 | #endif 342 | 343 | if (err != KERN_SUCCESS) 344 | return ret; 345 | 346 | ret.lo = out.lo; 347 | ret.hi = out.hi; 348 | 349 | return ret; 350 | } 351 | 352 | int wrmsr(int addr, msr_t msr) 353 | { 354 | kern_return_t err; 355 | size_t dataInLen = sizeof(msrcmd_t); 356 | size_t dataOutLen = sizeof(msrcmd_t); 357 | msrcmd_t in, out; 358 | 359 | in.core = current_logical_cpu; 360 | in.index = addr; 361 | in.lo = msr.lo; 362 | in.hi = msr.hi; 363 | 364 | #if !defined(__LP64__) && defined(WANT_OLD_API) 365 | /* Check if OSX 10.5 API is available */ 366 | if (IOConnectCallStructMethod != NULL) { 367 | #endif 368 | err = IOConnectCallStructMethod(connect, kWriteMSR, &in, dataInLen, &out, &dataOutLen); 369 | #if !defined(__LP64__) && defined(WANT_OLD_API) 370 | } else { 371 | /* Use old API */ 372 | err = IOConnectMethodStructureIStructureO(connect, kWriteMSR, dataInLen, &dataOutLen, &in, &out); 373 | } 374 | #endif 375 | 376 | if (err != KERN_SUCCESS) 377 | return 1; 378 | 379 | return 0; 380 | } 381 | 382 | int logical_cpu_select(int cpu) 383 | { 384 | current_logical_cpu = cpu; 385 | return 0; 386 | } 387 | 388 | -------------------------------------------------------------------------------- /DirectHW.dmg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osresearch/rwmem/8b724147c456e49ad6915fe1dc02ab3e6f5b6a31/DirectHW.dmg -------------------------------------------------------------------------------- /DirectHW.h: -------------------------------------------------------------------------------- 1 | /* 2 | * DirectHW.h - userspace part for DirectHW 3 | * 4 | * Copyright © 2008-2010 coresystems GmbH 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef __DIRECTHW_H 20 | #define __DIRECTHW_H 21 | 22 | #include 23 | 24 | int iopl(int unused); 25 | 26 | unsigned char inb(unsigned short addr); 27 | unsigned short inw(unsigned short addr); 28 | unsigned int inl(unsigned short addr); 29 | 30 | void outb(unsigned char val, unsigned short addr); 31 | void outw(unsigned short val, unsigned short addr); 32 | void outl(unsigned int val, unsigned short addr); 33 | 34 | void *map_physical(uint64_t phys_addr, size_t len); 35 | void unmap_physical(void *virt_addr, size_t len); 36 | 37 | typedef struct { uint32_t hi, lo; } msr_t; 38 | msr_t rdmsr(int addr); 39 | int wrmsr(int addr, msr_t msr); 40 | int logical_cpu_select(int cpu); 41 | 42 | #define INVALID_MSR_LO 0x63744857 43 | #define INVALID_MSR_HI 0x44697265 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: rdmem wrmem rdpci 2 | 3 | rdmem: rdmem.o DirectHW.o 4 | $(CC) -o $@ $^ -framework IOKit 5 | wrmem: wrmem.o DirectHW.o 6 | $(CC) -o $@ $^ -framework IOKit 7 | 8 | rdpci: rdpci.o DirectHW.o 9 | $(CC) -o $@ $^ -framework IOKit 10 | 11 | clean: 12 | $(RM) *.o .*.d rdmem 13 | 14 | CFLAGS = \ 15 | -g \ 16 | -O3 \ 17 | -W \ 18 | -Wall \ 19 | -MMD \ 20 | -MF .$(notdir $@).d 21 | 22 | -include .*.d 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Dangerous Software!](https://upload.wikimedia.org/wikipedia/commons/thumb/0/09/Operation_Crossroads_Baker_Edit.jpg/640px-Operation_Crossroads_Baker_Edit.jpg) 2 | Read and Write physical memory on OS X 3 | === 4 | 5 | *This ~~can~~ _WILL_ crash your machine!* 6 | 7 | - [X] No safety checks 8 | - [X] No validation of content 9 | - [X] No restrictions on where things are written (other than SMM, etc) 10 | - [X] No warranty 11 | 12 | The purpose of this tool is to read and write physical memory addresses 13 | of the running system. It is possible to crash the machine by writing 14 | to arbitrary pages, corrupt the kernel, mess up memory mappings, etc. 15 | It is not recommended for novice users. This is probably not the 16 | chainsaw/sledgehammer/atomic-bomb that you're looking for. 17 | 18 | Loading the `DirectHW.kext` gives any root process the ability to 19 | poke anywhere on the system. It is basically a deliberate backdoor 20 | in the kernel. You can download it from Snare's site, if you trust him 21 | more than the one bundled in this repository: 22 | http://ho.ax/downloads/DirectHW.dmg 23 | 24 | Usage 25 | === 26 | 27 | After installing the `DirectHW.dmg` file, load the kernel extension 28 | as root: 29 | 30 | sudo kextutil /System/Library/Extensions/DirectHW.kext 31 | 32 | Read your machine's serial number: 33 | 34 | sudo ./rdmem 0xffffff00 256 | xxd -g 1 35 | 36 | Read the "BIOS Region" of your boot ROM for analysis (the flash descriptor, 37 | Intel management engine and gig-e sections show up as all 0xFF): 38 | 39 | sudo ./rdmem 0xff990000 0x670000 > mac-bios.bin 40 | 41 | 42 | NOTES 43 | === 44 | 45 | * Reading the SMM region will cause the kernel to panic. 46 | * Reading the PCI BAR regions byte at a time with `memcpy()` or `write()` 47 | will will generate all 0xFF since the byte-wise access is not defined. 48 | `rdmem` and `rdpci` will do the right thing with their copy routine. 49 | 50 | -------------------------------------------------------------------------------- /check-flockdn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Print the BIOS_CNTL and FLOCKDN registers on a Mac. 3 | # (c) 2015 Trammell Hudson 4 | # 5 | # Use at your own risk! 6 | # 7 | use warnings; 8 | use strict; 9 | use FindBin '$Bin'; 10 | 11 | my $flockdn_base = 0xfed1f800; 12 | my $bios_base = 0xe00f8000; 13 | 14 | my $mem = `$Bin/rdmem $flockdn_base 256` 15 | or die "Unable to read FLOCKDN\n"; 16 | my $bios = `$Bin/rdmem $bios_base 256` 17 | or die "Unable to read BIOS_CNTL\n"; 18 | 19 | sub u2 20 | { 21 | my ($data,$offset) = @_; 22 | return unpack("S", substr($data,$offset,2)); 23 | } 24 | 25 | sub u4 26 | { 27 | my ($data,$offset) = @_; 28 | return unpack("L", substr($data,$offset,4)); 29 | } 30 | 31 | sub prr 32 | { 33 | my $reg = shift; 34 | my $addr = shift; 35 | 36 | my $w = ($reg >> 31) & 1; 37 | my $res1 = ($reg >> 29) & 3; 38 | my $limit = ($reg >> 16) & 0x1FFF; 39 | my $r = ($reg >> 15) & 1; 40 | my $res2 = ($reg >> 13) & 3; 41 | my $base = ($reg >> 0) & 0x1FFF; 42 | 43 | return sprintf "%08x (%08x): %s%s %08x-%08x (%x %x)", 44 | $reg, $addr, 45 | $r ? "!R" : "R", 46 | $w ? "!W" : "W", 47 | $base << 12, 48 | $limit << 12, 49 | $res1, 50 | $res2, 51 | ; 52 | } 53 | 54 | printf "BIOS_CNTL: %04x (%08x)\n", u2($bios, 0xdc), $bios_base+0xdc; 55 | printf "FLOCKDN: %04x (%08x)\n", u2($mem, 0x04), $flockdn_base+0x04; 56 | printf "PR0: %s\n", prr(u4($mem, 0x70), $flockdn_base+0x70); 57 | printf "PR1: %s\n", prr(u4($mem, 0x74), $flockdn_base+0x74); 58 | printf "PR2: %s\n", prr(u4($mem, 0x78), $flockdn_base+0x78); 59 | printf "PR3: %s\n", prr(u4($mem, 0x7c), $flockdn_base+0x7c); 60 | 61 | -------------------------------------------------------------------------------- /rdmem.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Read arbitrary physical memory. 3 | * 4 | * This is not as dangerous as wrmem, but you should still be careful! 5 | * For instance, attempting to read from SMRAM will cause an immediate 6 | * kernel panic. 7 | * 8 | * (c) 2015 Trammell Hudson 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "DirectHW.h" 19 | 20 | static char 21 | printable( 22 | uint8_t c 23 | ) 24 | { 25 | if (isprint(c)) 26 | return (char) c; 27 | return '.'; 28 | } 29 | 30 | 31 | static void 32 | hexdump( 33 | const uintptr_t base_offset, 34 | const uint8_t * const buf, 35 | const size_t len 36 | ) 37 | { 38 | const size_t width = 16; 39 | 40 | for (size_t offset = 0 ; offset < len ; offset += width) 41 | { 42 | printf("%08"PRIxPTR":", base_offset + offset); 43 | for (size_t i = 0 ; i < width ; i++) 44 | { 45 | if (i + offset < len) 46 | printf(" %02x", buf[offset+i]); 47 | else 48 | printf(" "); 49 | } 50 | 51 | printf(" "); 52 | 53 | for (size_t i = 0 ; i < width ; i++) 54 | { 55 | if (i + offset < len) 56 | printf("%c", printable(buf[offset+i])); 57 | else 58 | printf(" "); 59 | } 60 | 61 | printf("\n"); 62 | } 63 | } 64 | 65 | 66 | /* 67 | * Copy four bytes at a time, even if it spills over. 68 | * This will read from the PCI space safely, unlike mempcy(). 69 | */ 70 | static void 71 | quad_memcpy( 72 | uint32_t * const out, 73 | const uint32_t * const in, 74 | size_t len 75 | ) 76 | { 77 | for (size_t i = 0 ; i < len ; i += 4) 78 | { 79 | out[i/4] = in[i/4]; 80 | } 81 | } 82 | 83 | 84 | int 85 | main( 86 | int argc, 87 | char ** argv 88 | ) 89 | { 90 | int do_ascii = 0; 91 | 92 | if (argc != 3 && argc != 4) 93 | { 94 | fprintf(stderr, "Usage: %s [-x] phys-address len\n", argv[0]); 95 | return EXIT_FAILURE; 96 | } 97 | 98 | if (strcmp(argv[1], "-x") == 0) 99 | { 100 | do_ascii = 1; 101 | argv++; 102 | } 103 | 104 | const uintptr_t addr = strtoul(argv[1], NULL, 0); 105 | const size_t len = strtoul(argv[2], NULL, 0); 106 | 107 | // align to a page boundary 108 | const uintptr_t page_mask = 0xFFF; 109 | const uintptr_t page_offset = addr & page_mask; 110 | const uintptr_t map_addr = addr & ~page_mask; 111 | 112 | const size_t map_len = (len + page_offset + page_mask) & ~page_mask; 113 | 114 | if (iopl(0) < 0) 115 | { 116 | perror("iopl"); 117 | return EXIT_FAILURE; 118 | } 119 | 120 | const uint8_t * const map_buf = map_physical(map_addr, map_len); 121 | if (map_buf == NULL) 122 | { 123 | perror("mmap"); 124 | return EXIT_FAILURE; 125 | } 126 | 127 | const uint8_t * const buf = map_buf + page_offset; 128 | 129 | // because the PCIe space doesn't like being probed at anything 130 | // other than 4-bytes at a time, we force a copy of the region 131 | // into a local buffer. 132 | void * const out_buf = calloc(1, len); 133 | if (!out_buf) 134 | { 135 | perror("calloc"); 136 | return EXIT_FAILURE; 137 | } 138 | 139 | quad_memcpy(out_buf, (const void*) buf, len); 140 | 141 | if (do_ascii) 142 | { 143 | hexdump(addr, out_buf, len); 144 | } else { 145 | for(size_t offset = 0 ; offset < len ; ) 146 | { 147 | const ssize_t rc = write( 148 | STDOUT_FILENO, 149 | out_buf + offset, 150 | len - offset 151 | ); 152 | 153 | if (rc <= 0) 154 | { 155 | perror("write"); 156 | return EXIT_FAILURE; 157 | } 158 | 159 | offset += rc; 160 | } 161 | } 162 | 163 | return EXIT_SUCCESS; 164 | } 165 | -------------------------------------------------------------------------------- /rdpci.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Poke the PCI port with a value and read back the data. 3 | * 4 | * Mapping defined here: http://wiki.osdev.org/PCI_Express#Enhanced_Configuration_Mechanism 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "DirectHW.h" 12 | 13 | int 14 | main( 15 | int argc, 16 | char ** argv 17 | ) 18 | { 19 | if (argc != 4) 20 | { 21 | fprintf(stderr, "Usage: %s bus slot func\n", argv[0]); 22 | return EXIT_FAILURE; 23 | } 24 | 25 | const uint32_t bus = strtoul(argv[1], NULL, 0); 26 | const uint32_t slot = strtoul(argv[2], NULL, 0); 27 | const uint32_t func = strtoul(argv[3], NULL, 0); 28 | const uint32_t reg = 0; //strtoul(argv[4], NULL, 16); 29 | 30 | const uint32_t addr = 0xe0000000 31 | | ((bus & 0xFF) << 20) // 8 bits 32 | | ((slot & 0x1F) << 15) // 5 bits 33 | | ((func & 0x07) << 12) // 3 bits 34 | | ((reg & 0xFFC) << 0) // 12 bits, minus bottom 2 35 | ; 36 | 37 | if (iopl(0) < 0) 38 | { 39 | perror("iopl"); 40 | return EXIT_FAILURE; 41 | } 42 | 43 | const uintptr_t page_mask = 0xFFF; 44 | const uintptr_t page_offset = addr & page_mask; 45 | const uintptr_t map_addr = addr & ~page_mask; 46 | const size_t map_len = (page_offset + 256 + page_mask) & ~page_mask; 47 | 48 | const uint8_t * const pcibuf = map_physical(map_addr, map_len); 49 | if (pcibuf == NULL) 50 | { 51 | perror("map"); 52 | return EXIT_FAILURE; 53 | } 54 | 55 | for (unsigned i = 0 ; i < 256 ; i+=4) 56 | { 57 | printf("%08x=%08x\n", addr+i, *(uint32_t*)(pcibuf + page_offset + i)); 58 | } 59 | 60 | return EXIT_SUCCESS; 61 | } 62 | -------------------------------------------------------------------------------- /unhex: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use warnings; 3 | use strict; 4 | 5 | print chr(hex $_) for @ARGV; 6 | -------------------------------------------------------------------------------- /wrmem.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Write arbitrary physical memory locations. 3 | * 4 | * WARNING: This is a dangerous tool. 5 | * It can/will crash or corrupt your system if you write 6 | * to the wrong locations. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "DirectHW.h" 15 | 16 | int 17 | main( 18 | int argc, 19 | char ** argv 20 | ) 21 | { 22 | if (argc != 3) 23 | { 24 | fprintf(stderr, "Usage: %s phys-address len\n", argv[0]); 25 | return EXIT_FAILURE; 26 | } 27 | 28 | uintptr_t addr = strtoul(argv[1], NULL, 0); 29 | size_t len = strtoul(argv[2], NULL, 0); 30 | 31 | // align to a page boundary 32 | const uintptr_t page_mask = 0xFFF; 33 | uintptr_t page_offset = addr & page_mask; 34 | addr &= ~page_mask; 35 | 36 | size_t map_len = (len + page_offset + page_mask) & ~page_mask; 37 | 38 | if (iopl(0) < 0) 39 | { 40 | perror("iopl"); 41 | return EXIT_FAILURE; 42 | } 43 | 44 | volatile uint8_t * const buf = map_physical(addr, map_len); 45 | if (buf == NULL) 46 | { 47 | perror("mmap"); 48 | return EXIT_FAILURE; 49 | } 50 | 51 | uint8_t * const inbuf = calloc(1, len); 52 | if (!inbuf) 53 | { 54 | perror("malloc"); 55 | return EXIT_FAILURE; 56 | } 57 | 58 | size_t offset = 0; 59 | while (offset < len) 60 | { 61 | ssize_t rc = read(STDIN_FILENO, inbuf + offset, len - offset); 62 | if (rc <= 0) 63 | { 64 | perror("read"); 65 | return EXIT_FAILURE; 66 | } 67 | 68 | offset += rc; 69 | } 70 | 71 | for (size_t i = 0 ; i < len ; i++) 72 | buf[i+page_offset] = inbuf[i]; 73 | 74 | return EXIT_SUCCESS; 75 | } 76 | --------------------------------------------------------------------------------