#!/bin/bash

#
# Dump kernel memory from /dev/mem.
# Addresses can be numeric or symbolic.
# For example:
#
#   > dkmem die+0x14 12 4
#   0xffffffff8112118c+0000: ffb00008 03e0082d 00000000 67ac0028
#   0xffffffff8112118c+0010: 00a0802d 0080902d 0c44fbda 2411000b
#   0xffffffff8112118c+0020: 24040001 de080120 0240282d 0200302d
#

if [ "$#" = "0" ]; then
  echo "usage: $0 <address|symbol>[+offset] [ count [ num ] ]"
  exit 1
fi

if [ ! -r /dev/mem ]; then
   echo "$0: no /dev/mem"
   exit 2
fi

match="$(grep -e '[0-9a-f]* . '${1/+*}'[\s]*' /proc/kallsyms 2>/dev/null)"
if [ "0" = "$?" ]; then
  let addr=0x${match/ *}
else
  let addr=${1/+*}
fi

if [ "$1" != "${1/+*}" ]; then
  let addr+=${1/*+}
fi
hexaddr=$(printf "0x%08llx" $addr)

#
# Use the following virtual -> physical mappings defined in
# arch/mips/include/asm/addrspace.h:
#
# #define CPHYSADDR(a)            ((_ACAST32_(a)) & 0x1fffffff)
# #define XPHYSADDR(a)            ((_ACAST64_(a)) &                       \
#                                  _CONST64_(0x000000ffffffffff))
#
# Valid XKPHYS, XKSEG and CKSEG virtual addresses are:
#
# #define XKPHYS                  _CONST64_(0x8000000000000000)
# #define XKSEG                   _CONST64_(0xc000000000000000)
# #define CKSEG0                  _CONST64_(0xffffffff80000000)
# #define CKSEG1                  _CONST64_(0xffffffffa0000000)
# #define CKSSEG                  _CONST64_(0xffffffffc0000000)
# #define CKSEG3                  _CONST64_(0xffffffffe0000000)
#

case $hexaddr in

  0x[89ab][02468ace]0000[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])
    let addr=$hexaddr\&0x000000ffffffffff;;

  0xc00000[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])
    let addr=$hexaddr\&0x000000ffffffffff;;

  0xffffffff[89a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])
    let addr=$hexaddr\&0x1fffffff;;

  *)
    echo invalid kernel virtual address: $hexaddr
    exit 3

esac

let skip=$addr/${3:-4}

let nfmt=2*${3:-4}
if [ "$2" != "" ]; then
  let nfields=16/${3:-4}
  if [ $nfields -gt $2 ]; then
    nfields=$2
  fi
fi

fmt=-e\ '"'$hexaddr'+%04_ax: " '${nfields:-1}'/'${3:-4}' "%0'${nfmt}'x " "\n"'

dd count=${2:-1} bs=${3:-4} skip=$skip if=/dev/mem 2>/dev/null | hexdump -v "$fmt"
