Last active
August 3, 2025 21:36
-
-
Save joevt/4f6d4d97b560efab9603ac509bf00122 to your computer and use it in GitHub Desktop.
Revisions
-
joevt revised this gist
Dec 5, 2024 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ #! /bin/zsh # ThunderboltUtil.sh v1.7 # by joevt Dec 5, 2024 #========================================================================================= # @@ -1101,8 +1101,8 @@ loadoneioregfile () { elsif ( $inhex ) { $inhex = 0; print "" . (lc ($thehex =~ s/ //gr)) . ">\n" } if ( /^([ |]*)\+\-o (.+) </ ) { $indent = (length $1) / 2; $name = $2; $thepath =~ s|^((/[^/]*){$indent}).*|$1/$name| } elsif ( /^[ |]*"(ThunderboltDROM|thunderbolt-drom|DROM)" = <(.*)>/i ) { print "'"${thesource}"'" . ":" . $thepath . "/" . $1 . " = <" . $2 . ">\n" } elsif ( /^[ |]*"(ThunderboltDROM|thunderbolt-drom|DROM)" = $/i ) { print "'"${thesource}"'" . ":" . $thepath . "/" . $1 . " = <"; $inhex=1; $thehex="" } } ' < "${thefilename}" ); do -
joevt revised this gist
Apr 4, 2024 . 1 changed file with 248 additions and 79 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,6 @@ #! /bin/zsh # ThunderboltUtil.sh v1.6 # by joevt Apr 2, 2024 #========================================================================================= # @@ -229,6 +231,34 @@ crc32c () { } CRCTABLE=00000000F26B8303E13B70F71350F3F4C79A971F35F1141C26A1E7E8D4CA64EB8AD958CF78B2DBCC6BE228389989AB3B4D43CFD0BF284CD3AC78BF275E133C24105EC76FE235446CF165B798030E349BD7C4507025AFD37336FF2087C494A3849A879FA068EC1CA37BBCEF5789D76C545D1D08BFAF768BBCBC2678484E4DFB4B20BD8EDED2D60DDDC186FE2933ED7D2AE72719C1154C9AC2061C6936F477EA35AA64D611580F55124B5FA6E6B93425E56DFE410E9F95C20D8CC531F97EAEB2FA30E349B1C288CAB2D1D8394623B3BA45F779DEAE05125DAD1642AE59E4292D5ABA3A117E4851927D5B016189A96AE28A7DA086618FCB05629C9BF6966EF07595417B1DBCB3109EBFA0406D4B522BEE4886E18AA3748A09A067DAFA5495B17957CBA2457339C9C6702A993584D8F2B6870C38D26CFE53516FED03A29B1F6821985125DAD3A34E59D0B01EAA244275292796BF4DCC64D4CECF77843D3B85EFBE38DBFC821C2997011F3AC7F2EBC8AC71E81C661503EE0D9600FD5D65F40F36E6F761C6936293AD106180FDE39572966096A65C047D5437877E4767748AB50CF789EB1FCBAD197448AE0A24BB5AF84F38592C855CB2DEEEDFB1CDBE2C453FD5AF467198540D83F3D70E90A324FA62C8A7F9B602C312446940115739B3E5A55230E6FB410CC2092A8FC11A7A7C35E811FF363CDB9BDDCEB018DEDDE0EB2A2F8B682982F63B78709DB87B63CD4B8F91A6C88C456CAC67B7072F64A457DC90563C5F93082F63B7FA44E0B4E91413401B7F9043CFB5F4A83DDE77AB2E8E845FDCE5075C92A8FC1760C37F1473938CE081F80FE355326B08A759E80BB4091BFF466298FC1871A4D8EA1A27DBF94AD42F0B21572CDFEB33C72D80B0C43ED04330CCBBC033A24BB5A6502036A54370C551B11B465265D122B997BAA1BA84EA524E7681D14D2892ED69DAF96E6AC9A99D9E3BC21E9DEF087A761D63F9750E330A81FC588982B21572C9407EF1CA532E023EA145813D758FE5D687E466D594B4952166DF162238CC2A06CAA7A905D9F75AF12B9CD9F2FF56BD190D3D3E1A1E6DCDEEEC064EEDC38D26C431E6A5C722B65633D0DDD5300417B1DBF67C32D8E52CC12C1747422F49547E0BBB3FFD08A86F0EFC5A048DFF8ECEE9147CA56A176FF599E39D9E1AE0D3D3E1AB21B862A832E8915CC083125F144976B4E622F5B7F572064307198540590AB964AB613A67B831C9934A5A4A909E902E7B6CFBAD787FAB5E8C8DC0DD8FE330A81A115B2B19020BD8EDF0605BEE24AA3F05D6C1BC06C5914FF237FACCF169E9F0D59B8273D688D280227AB90321AE7367CA5C18E4C94F48173DBD23943EF36E6F750105EC7612551F82E03E9C8134F4F86AC69F7B69D5CF889D27A40B9E79B737BA8BDCB4B9988C474D6AE7C44EBE2DA0A54C4623A65F16D052AD7D5351 CRC32_8 () { local crc=$1 local b=$2 local ndx=$(( (crc ^ b) & 0xFF )) printf $(( (crc >> 8) ^ 0x${CRCTABLE:$ndx*8:8} )) } # same as crc32c but faster CRC32 () { local crc=$(( 0xFFFFFFFF )); for bp in $(xxd -p -c 1); do ((crc = $(CRC32_8 $crc 0x$bp) )) done printf "%08x" $((crc ^ 0xFFFFFFFF)) } # same as CRC32 but faster CRC32b () { local crc=$(( 0xFFFFFFFF )); for bp in $(xxd -p -c 1); do (( crc = (crc >> 8) ^ 0x${CRCTABLE:$(( ((crc ^ 0x$bp) & 0xFF) * 8 )):8} )) done printf "%08x" $((crc ^ 0xFFFFFFFF)) } replacebytes () { local bytepos=$(($1*2)) local thebytes=$2 @@ -287,7 +317,13 @@ processdrom () { theuid=$dotheuid fi if [[ $theuid == 0000000000000000 ]]; then isusb4=1 theexpectedcrc8=0 else isusb4=0 theexpectedcrc8=$((0x$(xxd -p -r <<< "$theuid" | crc8uid))) fi (( theexpectedcrc8 != thecrc8 )) && { if (( dorepairchecksums )); then replacebytes 0 "$(printf "%02x" $theexpectedcrc8)" @@ -297,8 +333,8 @@ processdrom () { fi } (( dodump && !isusb4 )) && { printf "0x01) UID: 0x%s // Vendor ID (USB-IF):0x%s Component ID:0x%s Router ID:0x%s" "$theuidnum" "${theuidnum:0:4}" "${theuidnum:4:11}" "${theuidnum:15:1}" if [[ $dosetuid = 1 && $theuidnum != "$douuidnum" ]]; then printf " (changed: 0x%s)" "$douuidnum" fi @@ -308,86 +344,213 @@ processdrom () { thecrc32=$((0x${thedrom:24:2}${thedrom:22:2}${thedrom:20:2}${thedrom:18:2})) thedatalen=$((0x${thedrom:30:2}${thedrom:28:2} & 0x3ff)) theversion=$((0x${thedrom:26:2})) (( dodump )) && { printf "0x0d) Version: %d" $theversion # Device ROM Revision if (( isusb4 )); then (( theversion == 3 )) && printf " // USB4" || printf " (expected 3)" else (( theversion == 1 )) && printf " // TBT3" || printf " (expected 1)" fi printf "\n" } thereserved=$(((0x${thedrom:30:2}${thedrom:28:2} & ~0x3ff) >> 10)) (( dodump && thereserved )) && printf "0x0e) Reserved: %d (expected 0)\n" $thereserved thevendorid=0 themodelid=0 themodelrev=0 theeepromrev=0 local startentryoffset=16 if (( !isusb4 )); then thevendorid=$((0x${thedrom:34:2}${thedrom:32:2})) (( dodump )) && printf "0x10) TBT3-Vendor ID: 0x%X\n" $thevendorid themodelid=$((0x${thedrom:38:2}${thedrom:36:2})) (( dodump )) && printf "0x12) TBT3-Device ID: 0x%X\n" $themodelid themodelrev=$((0x${thedrom:40:2})) (( dodump )) && printf "0x14) TBT3-Model Revision: 0x%X\n" $themodelrev theeepromrev=$((0x${thedrom:42:2})) (( dodump )) && printf "0x15) TBT3-NVM Revision: %d\n" $theeepromrev startentryoffset=22 fi while ((1)); do local entryoffset=$startentryoffset ((thedataend = 13 + thedatalen)) # Keep a list of ports and strings and generic data Ports=() while (( entryoffset <= thedataend )); do [[ -z ${thedrom:$entryoffset*2:2} ]] && break local entrylen=$((0x${thedrom:$entryoffset*2:2})) if ((entrylen < 2)); then (( dodump && (entryoffset != thedataend) )) && echo "Unexpected error: port length is < 2: $entryoffset + $entrylen <= $thedataend" break fi (( entryoffset == thedataend )) && { (( dodump )) && echo " ============== (following bytes are unexpected)" ((thedataend += entrylen)) } local theentrytype=$((0x${thedrom:$entryoffset*2+2:2} >> 7)) # 0=generic,1=Adapter Entry local theadapterdisabled=$(((0x${thedrom:$entryoffset*2+2:2} >> 6) & 1)) # 0=enabled,1=disabled local theadapternumber=$((0x${thedrom:$entryoffset*2+2:2} & 0x3f)) # 1..9,a..d local theadapterbytes=${thedrom:$entryoffset*2+4:$entrylen*2 - 4} local actualentrylen=$((${#theadapterbytes} / 2 + 2)) if (( dodump )); then printf "0x%02x) %s %X: " $entryoffset "$( ((theadapterdisabled)) && printf "-" || printf " ")" $theadapternumber if (( theentrytype || theadapternumber < 1 || theadapternumber > 2 )); then printf "%s" "$theadapterbytes" else printf "\"%s\"" "$(perl -pE "s/(00)+$//" <<< "${theadapterbytes}" | xxd -p -r)" if [[ $(perl -pE "s/.*?((00)+)$/\1/" <<< "${theadapterbytes}") != "00" ]]; then printf " (expected single terminating null character: %s)" "$theadapterbytes" fi fi if (( theentrytype )); then if (( theadapterdisabled && entrylen != 2 )); then printf " (unexpectedly disabled)" fi else if (( theadapterdisabled )); then printf " (unexpectedly disabled)" fi fi fi if ((theadapternumber <= 0)); then (( dodump )) && printf " (expected port number > 0)" elif ((theadapternumber == (theentrytype ? doportnumber : dostringnumber))); then ((dodump)) && { ((dosetport || dosetstring)) && printf " (replaced)" || printf " (removed)" } else Ports+=("$(printf "%d %02x %02x %s %s" $((1 - theentrytype)) $theadapternumber $entryoffset $theadapterdisabled "$theadapterbytes")") fi if (( entryoffset + entrylen > thedataend )); then (( dodump )) && printf " (unexpected error: bytes exceeds expected end: 0x%02x + %d = 0x%02x > 0x%02x)" $entryoffset $entrylen $((entryoffset + entrylen)) "$thedataend" fi if (( entrylen != actualentrylen )); then (( dodump )) && printf " (unexpected error: too few remaining bytes: %d > %d)" $entrylen $actualentrylen fi if (( dodump )); then case ${isusb4}_${theentrytype}_$(printf "%02X" $theadapternumber)_${theadapterbytes} in ?_1_??_??????) local thePreferredLaneAdapter=$(( 0x0${theadapterbytes:4:2} & 0x3f )) local thePreferenceValid=$(( (0x0${theadapterbytes:4:2} >> 6) & 1 )) local theReserved=$(( (0x0${theadapterbytes:4:2} >> 7) & 1 )) printf " // DP {" ((0x${theadapterbytes:0:4})) && printf " Unknown:0x%s," "${theadapterbytes:0:4}" printf " Preferred Lane Adapter:%d, Preference Valid:%d }" "$thePreferredLaneAdapter" "$thePreferenceValid" (( theReserved )) && printf ", Reserved:%d (expected 0)" $theReserved ;; 0_1_??_????????????) printf " // TBT3-Lane Adapter { Lane:%d" "$(( (0x0${theadapterbytes:0:2} >> 4) & 1 ))" printf ", Dual-Lane Link Capable:" case $(( (0x0${theadapterbytes:0:2} >> 7) & 1 )) in 0) printf "No" ;; 1) printf "Yes" ;; esac printf ", 2nd Adapter Num:%d" "$(( (0x0${theadapterbytes:2:2} >> 0) & 0x3f ))" ((0x${theadapterbytes:4:8})) && printf ", Unknown:0x%s" "${theadapterbytes:4:8}" printf " }" ;; 0_1_??_??????????????????) printf " // TBT3-PCIe Upstream Adapter { xx:%02x.%d" \ $(( (0x0${theadapterbytes:0:2} & 0x18) | (0x0${theadapterbytes:0:2} >> 5) )) \ $(( 0x0${theadapterbytes:0:2} & 7 )) ((0x${theadapterbytes:2:16})) && printf ", Unknown:0x%s" "${theadapterbytes:2:16}" printf " }" ;; 0_1_??_??) printf " // TBT3-PCIe Downstream Adapter { xx:%02x.%d }" \ $(( (0x0${theadapterbytes:0:2} & 0x18) | (0x0${theadapterbytes:0:2} >> 5) )) \ $(( 0x0${theadapterbytes:0:2} & 7 )) ;; ?_0_01_*) printf " // ASCII Vendor Name" ;; ?_0_02_*) printf " // ASCII Model Name" ;; ?_0_08_*) local theTMUMode=$(( 0x0${theadapterbytes:0:2} & 3 )) local theTMURefresh=$(( (0x0${theadapterbytes:0:2} >> 2) & 3 )) local theReserved=$(( (0x0${theadapterbytes:0:2} >> 4) & 15 )) printf " // TMU Minimum Requested Mode { TMU Mode:" case $theTMUMode in 0) printf "Off" ;; 1) printf "Unidirectional" ;; 2) printf "Bidirectional" ;; *) printf "Reserved" ;; esac printf ", TMU Refresh Rate:" case $theTMURefresh in 1) printf "HiFi" ;; 2) printf "LowRes" ;; *) printf "Reserved" ;; esac (( theReserved )) && printf ", Reserved:%d (expected 0)" $theReserved printf " }" ;; ?_0_09_*) local theBcdUSBSpec="$(( 0x0${theadapterbytes:2:1} * 10 + 0x0${theadapterbytes:3:1} )).${theadapterbytes:0:1}.${theadapterbytes:1:1}" local theIdVendor=$((0x${theadapterbytes:6:2}${theadapterbytes:4:2})) local theIdProduct=$((0x${theadapterbytes:10:2}${theadapterbytes:8:2})) local theBcdProductFWRevision="$(( 0x0${theadapterbytes:14:1} * 10 + 0x0${theadapterbytes:15:1} )).${theadapterbytes:12:1}.${theadapterbytes:13:1}" local theTID=$((0x${theadapterbytes:22:2}${theadapterbytes:20:2}${theadapterbytes:18:2}${theadapterbytes:16:2})) local theProductHWRevision=$((0x${theadapterbytes:24:2})) printf " // Product Descriptor { USB Spec:%s, Vendor ID:0x%04x, Product ID:0x%04x, Product FW Revision:%s, TID:0x%08x, Product HW Revision:%d }" \ "$theBcdUSBSpec" "$theIdVendor" "$theIdProduct" "$theBcdProductFWRevision" "$theTID" "$theProductHWRevision" ;; ?_0_0[ACD]_*) local theLANGID=$((0x${theadapterbytes:2:2}${theadapterbytes:0:2})) # https://docs.microsoft.com/en-us/windows/win32/intl/language-identifier-constants-and-strings local theUTF16="$( xxd -p -r <<< ${theadapterbytes:4} | iconv -f UTF-16LE )" printf " // " case $(printf "0x%X" $theadapternumber) in 0xA) printf "Serial Number" ;; 0xC) printf "UTF16 Vendor Name" ;; 0xD) printf "UTF16 Model Name" ;; esac printf " { LANGID:0x%04X, _:\"%s\" }" "$theLANGID" "$theUTF16" ;; ?_0_0B_*) printf " // USB Port Mapping {" for (( usb=0; usb < ${#theadapterbytes} / 6; usb++ )); do local theUSB=${theadapterbytes:$((usb*6)):6} (( usb )) && printf "," printf " { USB3 Port Number:%d, PD Port Number:%d, xHCI Index:%d, USB Type-C:%d, USB3 Adapter Number:%d, Tunnelling Support:%d }" \ $(( (0x${theUSB:0:2} >> 0) & 0x0f )) \ $(( (0x${theUSB:2:2} >> 0) & 0x1f )) \ $(( (0x${theUSB:2:2} >> 5) & 3 )) \ $(( (0x${theUSB:2:2} >> 7) & 1 )) \ $(( (0x${theUSB:4:2} >> 0) & 0x3f )) \ $(( (0x${theUSB:4:2} >> 7) & 1 )) done printf " }" ;; ?_0_3F_*) printf " // Reserved" ;; ?_0_3*) printf " // Vendor Specific Type" ;; ?_0_*) printf " // Reserved" ;; esac echo fi ((entryoffset += actualentrylen)) done if (( doportnumber >= 0 || dostringnumber >= 0 )); then @@ -396,12 +559,12 @@ processdrom () { local allportbytes="" allportbytes=$( IFS=$'\n' for theentrystring in $(sort <<< "${Ports[*]}"); do printf "%02x%02x%s" $(( (${#theentrystring} - 10) / 2 + 2 )) $(( ((1 - ${theentrystring:0:1}) << 7) | (${theentrystring:8:1} << 6) | (0x${theentrystring:2:2} & 0x3f) )) "${theentrystring:10}" done ) replacebytes $startentryoffset "$allportbytes" ${#thedrom} ((thedatalen = ${#allportbytes}/2 + $startentryoffset - 13 )) replacebytes 14 "$(printf "%04x" "$thedatalen" | sed -E 's/(..)(..)/\2\1/')" doportnumber=-1 @@ -412,7 +575,7 @@ processdrom () { fi done theexpectedcrc32=$((0x$(xxd -p -r <<< "${thedrom:26:$thedatalen*2}" | CRC32b))) (( theexpectedcrc32 != thecrc32 )) && { if (( dorepairchecksums )); then replacebytes 9 "$(printf "%08x" $theexpectedcrc32 | sed -E 's/(..)(..)(..)(..)/\4\3\2\1/')" @@ -423,20 +586,20 @@ processdrom () { } (( dodump )) && { printf "0x%02x) End" "$entryoffset" if [[ -n $(tr -d '0' <<< "${thedrom:$entryoffset*2}") ]]; then printf " (unexpected bytes: %s)" "${thedrom:$entryoffset*2}" fi echo } if (( domake )); then IFS=$'\n' entryoffset=$startentryoffset for theentrystring in $(sort <<< "${Ports[*]}"); do entrylen=$(( (${#theentrystring} - 10) / 2 + 2 )) ((entryoffset += entrylen)) done printf ' @@ -453,42 +616,42 @@ processdrom () { /* 0x14 */ 0x%s, // Device Revision: 0x%X /* 0x15 */ 0x%s, // EEPROM Revision: %d ' \ $entryoffset \ "${thedrom:0:2}" $thecrc8 \ "${thedrom:2:2}" "${thedrom:4:2}" "${thedrom:6:2}" "${thedrom:8:2}" "${thedrom:10:2}" "${thedrom:12:2}" "${thedrom:14:2}" "${thedrom:16:2}" $((0x${thedrom:2:2})) "$theuidnum" \ "${thedrom:18:2}" "${thedrom:20:2}" "${thedrom:22:2}" "${thedrom:24:2}" $thecrc32 \ "${thedrom:26:2}" $theversion \ "${thedrom:28:2}" "${thedrom:30:2}" "$thedatalen" \ "${thedrom:32:2}" "${thedrom:34:2}" $thevendorid \ "${thedrom:36:2}" "${thedrom:38:2}" $themodelid \ "${thedrom:40:2}" $themodelrev \ "${thedrom:42:2}" $theeepromrev IFS=$'\n' entryoffset=$startentryoffset for theentrystring in $(sort <<< "${Ports[*]}"); do entrylen=$(( (${#theentrystring} - 10) / 2 + 2 )) theadapternumber=$((0x${theentrystring:2:2} & 0x3f)) theadapterdisabled=${theentrystring:8:1} theentrytype=$((1 - ${theentrystring:0:1})) printf " /* 0x%02X %s %X */ 0x%02x, 0x%02x, %s" $entryoffset "$( ((theadapterdisabled)) && printf "-" || printf " " )" $theadapternumber $entrylen \ $(( (theentrytype << 7) | (theadapterdisabled << 6) | theadapternumber )) \ "$( perl -pE 's/(..)/0x\1, /g' <<< "${theentrystring:10}" )" if (( theentrytype == 0 )); then local thestring="" thestring="$(perl -pE "s/(00)+$//" <<< "${theentrystring:10}" | xxd -p -r)" if (( theadapternumber == 1 )); then printf '// Vendor Name: "%s"' "$thestring" elif (( theadapternumber == 2 )); then printf '// Device Name: "%s"' "$thestring" else printf '// "%s"' "${theentrystring:10}" fi elif (( ${#theentrystring} == 12 )); then printf '// PCIe xx:%02x.%x' $((0x${theentrystring:10} >> 5)) $((0x${theentrystring:10} & 0x1f)) #### fix this - function should only be 3 bits - therefore there are 2 unknown bits? fi printf "\n" ((entryoffset += entrylen)) done printf " },\n" fi @@ -639,7 +802,7 @@ loadstring () { ((numstrings++)) sourcename="string:$numstrings" fi adddrom "$sourcename" $(xxd -p -r <<< "$1" | xxd -p -c 99999) } @@ -932,12 +1095,18 @@ loadoneioregfile () { IFS=$'\n' for dromitem in $( perl -e ' $inhex=0; $thepath=""; while (<>) { if ( $inhex && /^[ |]*[0-9A-F]+:((?: [0-9A-F]{2}){1,32})/ ) { $thehex .= $1 } elsif ( $inhex ) { $inhex = 0; print "" . (lc ($thehex =~ s/ //gr)) . ">\n" } if ( /^([ |]*)\+\-o (.+) </ ) { $indent = (length $1) / 2; $name = $2; $thepath =~ s|^((/[^/]*){$indent}).*|$1/$name| } elsif ( /^[ |]*"(ThunderboltDROM|thunderbolt-drom)" = <(.*)>/i ) { print "'"${thesource}"'" . ":" . $thepath . "/" . $1 . " = <" . $2 . ">\n" } elsif ( /^[ |]*"(ThunderboltDROM|thunderbolt-drom)" = $/i ) { print "'"${thesource}"'" . ":" . $thepath . "/" . $1 . " = <"; $inhex=1; $thehex="" } } ' < "${thefilename}" ); do #echo "«${dromitem}»" loadonedromitem "${dromitem}" done } -
joevt revised this gist
Dec 31, 2020 . 1 changed file with 0 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,3 @@ # by joevt Jul 7, 2020 #========================================================================================= -
joevt revised this gist
Jul 7, 2020 . 1 changed file with 63 additions and 43 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ #! /bin/zsh # ThunderboltUtil.sh v1.5 # by joevt Jul 7, 2020 #========================================================================================= # @@ -739,32 +739,32 @@ loadonedslfile () { local thesource="$2" [[ -z $thesource ]] && thesource="$thefilename" # # LeadNameChar := [A-Za-z_] # DigitChar := [0-9] # NameChar := [A-Za-z_0-9] # RootChar := \ # ParentPrefixChar := ^ # PathSeparatorChar := . # # // Names and paths # # NameSeg := [A-Za-z_][A-Za-z_0-9]{0,3} # # PrefixPath := \^* # # NamePathTail := ([.][A-Za-z_][A-Za-z_0-9]{0,3})* # # NamePath := (([A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})*)|) # # NonEmptyNamePath := [A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})* # # NameString := ([\\]|\^+|)(([A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})*)|) # | [A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})* # IFS=$'\n' for dromitem in $( perl -e ' use strict; @@ -791,10 +791,20 @@ loadonedslfile () { my $dodump = 0; my $buffersize = 0; if ( $line2 =~ /"ThunderboltDROM",\s*$/) { $dodump = 1; if ( $line1 =~ /^\s*Buffer\s*\(0x([0-9A-F]+)\)/ ) { $buffersize = hex($1); } elsif ( $line1 =~ /^\s*Buffer\s*\(One\)/ ) { $buffersize = 1; } elsif ( $line1 =~ /^\s*Buffer\s*\(Zero\)/ ) { $buffersize = 0; } else { $dodump = 0; } } if ( $dodump == 1 ) { @@ -827,31 +837,40 @@ loadonedslfile () { addline($_); if ( /(External|Device|Field|Method|Name|Scope)\s*\(\s*([\\]|\^+|)(([A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})*)|)/ ) { my $command = $1; my $prefix = $2; # \ or ^+ or empty my $nameparts = $3; $nameparts =~ s/([A-Za-z0-9])_+/\1/g; # remove trailing spaces #print "nameparts:" . $nameparts . "\n"; if ( $prefix =~ /\\/ ) { # absolute path $nextacpipath = $prefix . $nameparts; } elsif ( $prefix =~ /\^+/ ) { # parent path - remove from the current path a number of parents equal to the number of ^ characters my $pattern = "(.*?)([\\\\.][^.]+){0," . length($prefix) . "}\$"; # empty path means root "\" $nextacpipath = ($acpipath =~ s/$pattern/\1/r =~ s/^$/\\/r) . "$nameparts"; } else { # assume path is current path appended with name $nextacpipath = (($acpipath . "." . $nameparts) =~ s/^\\\./\\/r); # "\." is "\" if ( ($command eq "Scope") && ($nameparts =~ /[^.]+/) && !($paths{$nextacpipath}) ) { # For Scope, if path does not exist... if ( ($acpipath . ".") =~ /(.*[.\\]$nameparts)[.].*/ ) { # if current path includes names then set scope to parent that ends at name $nextacpipath = (($acpipath . ".") =~ s/(.*[.\\]$nameparts)[.].*/\1/r) } else { # unknown path - assume it exists print STDERR "unknown path " . $nextacpipath . "\n"; #print STDERR "$_\n" for keys %paths; } } } # code path is just current path appended with entire prefix/nameparts (no interpretation of prefix characters or scoping) $nextcodepath = (($codepath . "." . $prefix . $nameparts) =~ s/^\\\./\\/r =~ s/\\\\/\\/r); # "\." is "\" and "\\" is "\" if ( !$paths{$nextacpipath} ) { # keep a list of all paths $paths{$nextacpipath} = 1; } } @@ -870,6 +889,7 @@ loadonedslfile () { } group("", "\\", "\\"); # print "$_\n" for keys %paths; ' < "$thefilename" ); do (( debug )) && echo ":" loadonedromitem "${dromitem}" 1>&2 -
joevt revised this gist
Jul 5, 2020 . No changes.There are no files selected for viewing
-
joevt revised this gist
Jul 5, 2020 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,5 @@ #! /bin/zsh # ThunderboltUtil.sh v1.4 # by joevt Jul 5, 2020 #========================================================================================= @@ -398,7 +398,7 @@ processdrom () { local allportbytes="" allportbytes=$( IFS=$'\n' for theportstring in $(sort <<< "${Ports[*]}"); do printf "%02x%02x%s" $(( (${#theportstring} - 10) / 2 + 2 )) $(( ((1 - ${theportstring:0:1}) << 7) | (${theportstring:8:1} << 6) | (0x${theportstring:2:2} & 0x3f) )) "${theportstring:10}" done ) @@ -436,7 +436,7 @@ processdrom () { IFS=$'\n' portoffset=22 for theportstring in $(sort <<< "${Ports[*]}"); do portlen=$(( (${#theportstring} - 10) / 2 + 2 )) ((portoffset += portlen)) done @@ -468,7 +468,7 @@ processdrom () { IFS=$'\n' portoffset=22 for theportstring in $(sort <<< "${Ports[*]}"); do portlen=$(( (${#theportstring} - 10) / 2 + 2 )) theportnumber=$((0x${theportstring:2:2} & 0x3f)) theportdisabled=${theportstring:8:1} -
joevt revised this gist
Jul 5, 2020 . 1 changed file with 6 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ #! /bin/zsh # ThunderboltUtil.sh v1.3 # by joevt Jul 5, 2020 #========================================================================================= # @@ -683,7 +683,10 @@ loadfwfile () { $thedrom =~ s/(ff )*$//g; $thedrom =~ s/ //g; $version = "vers_unknown"; if ($X == hex(200)) { $version = "v" . substr($_, (10) * 3, 2); $partition = "linux"; } elsif ($X < hex(4000)) { $partition = "missing header"; } elsif ($X < hex(82000)) { $version = "v" . substr($_, (hex(4000) + 10) * 3, 2); -
joevt revised this gist
Jul 4, 2020 . 1 changed file with 5 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ #! /bin/zsh # ThunderboltUtil.sh v1.2 # by joevt Jul 4, 2020 #========================================================================================= # @@ -250,7 +250,9 @@ processdrom () { while (( $# )); do local param="$1"; shift if [[ $param != '-' ]]; then eval "local $param=1" fi case "$param" in dosetuid) local douuidnum="" -
joevt created this gist
Jun 30, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,1042 @@ #! /bin/zsh # ThunderboltUtil.sh v1.1 # by joevt Jun 29, 2020 #========================================================================================= # # # Thunderbolt DROM Notes: # # # https://lore.kernel.org/patchwork/patch/714766/ # # Macs with Thunderbolt 1 do not have a unit-specific DROM: The DROM is # empty with uid 0x1000000000000. (Apple started factory-burning a unit- # specific DROM with Thunderbolt 2.) # # Instead, the NHI EFI driver supplies a DROM in a device property. Use # it if available. It's only available when booting with the efistub. # If it's not available, silently fall back to our hardcoded DROM. # # The size of the DROM is always 256 bytes. The number is hardcoded into # the NHI EFI driver. This commit can deal with an arbitrary size however, # just in case they ever change that. # # A modification is needed in the resume code where we currently read the # uid of all switches in the hierarchy to detect plug events that occurred # during sleep. On Thunderbolt 1 root switches this will now lead to a # mismatch between the uid of the empty DROM and the EFI DROM. Exempt the # root switch from this check: It's built in, so the uid should never # change. However we continue to *read* the uid of the root switch, this # seems like a good way to test its reachability after resume. # # Background information: The EFI firmware volume contains ROM files for # the NHI, GMUX and several other chips as well as key material. This # strategy allows Apple to deploy ROM or key updates by simply publishing # an EFI firmware update on their website. Drivers do not access those # files directly but rather through a file server via EFI protocol # AC5E4829-A8FD-440B-AF33-9FFE013B12D8. Files are identified by GUID, the # NHI DROM has 339370BD-CFC6-4454-8EF7-704653120818. # # The NHI EFI driver amends that file with a unit-specific uid. The uid # has 64 bit but its entropy is much lower: 24 bit represent the model, # 24 bit are taken from a serial number, 16 bit are fixed. The NHI EFI # driver obtains the serial number via the DataHub protocol, copies it # into the DROM, calculates the CRC and submits the result as a device # property. # # # https://github.com/torvalds/linux/blob/master/drivers/thunderbolt/eeprom.c # # #define TB_DROM_DATA_START 13 # struct tb_drom_header { # /* BYTE 0 */ # u8 uid_crc8; /* checksum for uid */ # /* BYTES 1-8 */ # u64 uid; # /* BYTES 9-12 */ # u32 data_crc32; /* checksum for data_len bytes starting at byte 13 */ # /* BYTE 13 */ # u8 device_rom_revision; /* should be <= 1 */ # u16 data_len:10; # u8 __unknown1:6; # /* BYTES 16-21 */ # u16 vendor_id; # u16 model_id; # u8 model_rev; # u8 eeprom_rev; # } __packed; # # enum tb_drom_entry_type { # /* force unsigned to prevent "one-bit signed bitfield" warning */ # TB_DROM_ENTRY_GENERIC = 0U, # TB_DROM_ENTRY_PORT, # }; # # struct tb_drom_entry_header { # u8 len; # u8 index:6; # bool port_disabled:1; /* only valid if type is TB_DROM_ENTRY_PORT */ # enum tb_drom_entry_type type:1; # } __packed; # # struct tb_drom_entry_generic { # struct tb_drom_entry_header header; # u8 data[]; # } __packed; # # struct tb_drom_entry_port { # /* BYTES 0-1 */ # struct tb_drom_entry_header header; # /* BYTE 2 */ # u8 dual_link_port_rid:4; // "Dual-Link Port RID" 0 for the first Thunderbolt controller, 1 for the second Thunderbolt controller, 2 for ? # u8 link_nr:1; // "Lane" 0 for Lane 1, 1 for Lane 2 # u8 unknown1:2; // 0 # bool has_dual_link_port:1; // 1 # # /* BYTE 3 */ # u8 dual_link_port_nr:6; // "Dual-Link Port" 2,1,4,3 for ports 1,2,3,4 # u8 unknown2:2; // 0 # # /* BYTES 4 - 5 TODO decode */ # u8 micro2:4; // 0 0,1,2 (0 for first controller, 1 for second controller) # u8 micro1:4; // 4 8 # u8 micro3; // "Micro Address" 26,24 00,01 # // or "HPM Address"? # # /* BYTES 6-7, TODO: verify (find hardware that has these set) */ # u8 peer_port_rid:4; // 0 # u8 unknown3:3; // 0 # bool has_peer_port:1; // 0 # u8 peer_port_nr:6; // 0 # u8 unknown4:2; // 0 # } __packed; # # # # # # Macmini8,1 # # 0x00) CRC8: 0x.. # 0x01) UID: 0x000115CE05397601 Least significant byte is Thunderbolt Bus number (0,1,...) # 0x09) CRC32c: 0x........ # 0x0d) Device ROM Revision: 1 # 0x0e) Length: 0x.... # 0x10) Vendor ID: 0x1 two bytes; # 1 = Apple # 0x12) Device ID: 0xD two bytes; # 16=MacPro7,1 # 13=iMac19,1 or Macmini8,1 # 12=iMac18,3 or iMacPro1,1 # 11=MacBookPro11,5 // Thunderbolt 2 # 0x14) Device Revision: 0x1 # 0x15) EEPROM Revision: 0 # 0x16) 1: 8 1 0 2 8 1 00 0000 Thunderbolt Port # 0x1e) 2: 9 1 0 1 8 1 00 0000 Thunderbolt Port # 0x26) 3: 8 1 0 4 8 1 01 0000 Thunderbolt Port # 0x2e) 4: 9 1 0 3 8 1 01 0000 Thunderbolt Port # 0x36) 5: 0 9 0 1 0 0 DP or HDMI Adapter (DP In Adapter) Sink 0 # 0x3b) 6: 0 9 0 1 0 0 DP or HDMI Adapter (DP In Adapter) Sink 1 # 0x40) 7: Thunderbolt NHI Adapter # 0x42) 8: 2 0 PCIe Adapter (PCI Down Adapter) @1 (3 bits PCI Device, 5 bits for ???) # 0x45) 9: 8 0 PCIe Adapter (PCI Down Adapter) @4 # 0x48) - A: # 0x4a) - B: # 0x4c) 1: "Apple Inc." # 0x59) 2: "Macintosh" # 0x65) End # # # MacBookPro11,5 # # 0x01) UID: 0x0001001701C9F100 # 0x0d) Device ROM Revision: 1 # 0x10) Vendor ID: 0x1 # 0x12) Device ID: 0xB # 0x14) Device Revision: 0x1 # 0x15) EEPROM Revision: 1 # 0x16) 1: 8 0 0 2 8 0 00 0000 Thunderbolt Port 1, Dual Link Port, Lane 0, Dual-Link Port 2, Micro Address 0 # 0x1e) 2: 9 0 0 1 8 0 00 0000 Thunderbolt Port 2, Dual Link Port, Lane 1, Dual-Link Port 1, Micro Address 0 # 0x26) 3: 8 0 0 4 8 0 01 0000 Thunderbolt Port 3, Dual Link Port, Lane 0, Dual-Link Port 4, Micro Address 1 # 0x2e) 4: 9 0 0 3 8 0 01 0000 Thunderbolt Port 4, Dual Link Port, Lane 1, Dual-Link Port 3, Micro Address 1 # 0x36) 5: 000000000000 Thunderbolt NHI Adapter # 0x3e) 6: 6 0 PCIe Adapter (PCI Down Adapter) @3 (3 bits PCI Device, 5 bits for ???) # 0x41) 7: 8 0 PCIe Adapter (PCI Down Adapter) @4 # 0x44) 8: a 0 PCIe Adapter (PCI Down Adapter) @5 # 0x47) 9: c 0 PCIe Adapter (PCI Down Adapter) @6 # 0x4a) - A: # 0x4c) B: 500082 DP or HDMI Adapter (DP In Adapter) Sink 0, Port Affinity 1,2, Preferred Null Port 2 # 0x51) C: 500084 DP or HDMI Adapter (DP In Adapter) Sink 1, Port Affinity 3,4, Preferred Null Port 4 # 0x56) 1: "Apple Inc." # 0x63) 2: "Macintosh" # 0x6f) End # #========================================================================================= # Modify DROM iasl_location=/Applications/MaciASL.app/Contents/MacOS/iasl-stable getarrstart () { # bash arrays start at 0 # zsh arrays start at 1 (applies only to [] syntax) but this can be changed with "setopt ksh_arrays" # zsh arrays start at 0 when using ${arr:x:x} syntax local arr=(1 0) arrstart=${arr[1]} } getarrstart crc () { local bits=$(($1)) local inputreflected=$(($2)) local outputreflected=$(($3)) local polynomial=$(($4)) local crc=$(($5)) local finalxor=$(($6)) for data in $(xxd -p -c 1 | { if (( inputreflected )); then rev | tr '0123456789abcdef' '084c2a6e195d3b7f' else cat fi }); do ((crc ^= (0x$data << (bits-8)))) for ((i=0;i<8;i++)); do if ((crc >> (bits-1))); then ((crc = (crc << 1) ^ polynomial)) else ((crc <<= 1)) fi ((crc &= ((1 << $bits)-1))) done done printf "%0$(((bits+3) / 4))x" $((crc ^ finalxor)) | { if (( outputreflected )); then rev | tr '0123456789abcdef' '084c2a6e195d3b7f' else cat fi } } crc8uid () { crc 8 0 0 7 0 0xdb } crc32c () { crc 32 1 1 0x1edc6f41 0xffffffff 0xffffffff } replacebytes () { local bytepos=$(($1*2)) local thebytes=$2 local thelen=${#thebytes} [[ -n $3 ]] && thelen=$(($3*2)) thedrom=${thedrom:0:$bytepos}${thebytes}${thedrom:$bytepos+thelen} } processdrom () { (( debug )) && echo ": processdrom " "$@" 1>&2 local dosetuid=0 local dosetport=0 local dosetstring=0 local doportnumber=-1 local dostringnumber=-1 while (( $# )); do local param="$1"; shift eval "local $param=1" case "$param" in dosetuid) local douuidnum="" douuidnum=$(perl -pe '$_="0000000000000000" . $_;s/[^A-Fa-f0-9]//g;s/.*(.{16})$/\1/' <<< "$1" | tr 'a-f' 'A-F') # make UID uppercase like Apple does shift local dotheuid="" dotheuid=$(tr 'A-F' 'a-f' <<< "${douuidnum:14:2}${douuidnum:12:2}${douuidnum:10:2}${douuidnum:8:2}${douuidnum:6:2}${douuidnum:4:2}${douuidnum:2:2}${douuidnum:0:2}") ;; dosetport) local doportnumber="$(($1))"; shift local doportcontents="$1"; shift local doportdisable="$1" [[ $doportdisable = "-" || $doportdisable = "1" ]] && doportdisable=1 || doportdisable=0 ;; dodeleteport) local doportnumber="$(($1))"; shift ;; dosetstring) local dostringnumber="$(($1))"; shift local dostringcontents="$1"; shift ;; dodeletestring) local dostringnumber="$(($1))"; shift ;; esac done thecrc8=$((0x${thedrom:0:2})) theuid=${thedrom:2:16} theuidnum=$(tr 'a-f' 'A-F' <<< "${thedrom:16:2}${thedrom:14:2}${thedrom:12:2}${thedrom:10:2}${thedrom:8:2}${thedrom:6:2}${thedrom:4:2}${thedrom:2:2}") # make UID uppercase like Apple does if [[ $dosetuid = 1 && $theuidnum != "$douuidnum" ]]; then replacebytes 1 "$dotheuid" theuid=$dotheuid fi theexpectedcrc8=$((0x$(xxd -p -r <<< "$theuid" | crc8uid))) (( theexpectedcrc8 != thecrc8 )) && { if (( dorepairchecksums )); then replacebytes 0 "$(printf "%02x" $theexpectedcrc8)" (( dodump )) && printf "0x00) CRC8: 0x%02x (changed: 0x%02x)\n" $thecrc8 $theexpectedcrc8 else (( dodump )) && printf "0x00) CRC8: 0x%02x (expected: 0x%02x)\n" $thecrc8 $theexpectedcrc8 fi } (( dodump )) && { printf "0x01) UID: 0x%s" "$theuidnum" if [[ $dosetuid = 1 && $theuidnum != "$douuidnum" ]]; then printf " (changed: 0x%s)" "$douuidnum" fi echo } thecrc32=$((0x${thedrom:24:2}${thedrom:22:2}${thedrom:20:2}${thedrom:18:2})) thedatalen=$((0x${thedrom:30:2}${thedrom:28:2} & 0x3ff)) thedeviceromrevision=$((0x${thedrom:26:2})) (( dodump )) && printf "0x0d) Device ROM Revision: %d\n" $thedeviceromrevision theunknown=$(((0x${thedrom:30:2}${thedrom:28:2} & 0x3ff) >> 10)) (( dodump && theunknown )) && printf "0x0e) Unknown: %d (expected 0)\n" $theunknown thevendorid=$((0x${thedrom:34:2}${thedrom:32:2})) (( dodump )) && printf "0x10) Vendor ID: 0x%X\n" $thevendorid themodelid=$((0x${thedrom:38:2}${thedrom:36:2})) (( dodump )) && printf "0x12) Device ID: 0x%X\n" $themodelid themodelrev=$((0x${thedrom:40:2})) (( dodump )) && printf "0x14) Device Revision: 0x%X\n" $themodelrev theeepromrev=$((0x${thedrom:42:2})) (( dodump )) && printf "0x15) EEPROM Revision: %d\n" $theeepromrev while ((1)); do local portoffset=22 ((thedataend = 13 + thedatalen)) # Keep a list of ports and strings and generic data Ports=() while (( portoffset <= thedataend )); do [[ -z ${thedrom:$portoffset*2:2} ]] && break local portlen=$((0x${thedrom:$portoffset*2:2})) if ((portlen < 2)); then (( dodump && (portoffset != thedataend) )) && echo "Unexpected error: port length is < 2: $portoffset + $portlen <= $thedataend" break fi (( portoffset == thedataend )) && { (( dodump )) && echo " ============== (following bytes are unexpected)" ((thedataend += portlen)) } local theporttype=$((0x${thedrom:$portoffset*2+2:2} >> 7)) # 0=generic,1=port local theportdisabled=$(((0x${thedrom:$portoffset*2+2:2} >> 6) & 1)) # 0=enabled,1=disabled local theportnumber=$((0x${thedrom:$portoffset*2+2:2} & 0x3f)) # 1..9,a..d local theportbytes=${thedrom:$portoffset*2+4:$portlen*2 - 4} local actualportlen=$((${#theportbytes} / 2 + 2)) if (( dodump )); then printf "0x%02x) %s %X: " $portoffset "$( ((theportdisabled)) && printf "-" || printf " ")" $theportnumber if (( theporttype || theportnumber < 1 || theportnumber > 2 )); then printf "%s" "$theportbytes" else printf "\"%s\"" "$(perl -pE "s/(00)+$//" <<< "${theportbytes}" | xxd -p -r)" if [[ $(perl -pE "s/.*?((00)+)$/\1/" <<< "${theportbytes}") != "00" ]]; then printf " (expected single terminating null character: %s)" "$theportbytes" fi fi if (( !theporttype && theportdisabled )); then printf " (unexpectedly disabled)" fi fi if ((theportnumber <= 0)); then (( dodump )) && printf " (expected port number > 0)" elif ((theportnumber == (theporttype ? doportnumber : dostringnumber))); then ((dodump)) && { ((dosetport || dosetstring)) && printf " (replaced)" || printf " (removed)" } else Ports+=("$(printf "%d %02x %02x %s %s" $((1 - theporttype)) $theportnumber $portoffset $theportdisabled "$theportbytes")") fi if (( portoffset + portlen > thedataend )); then (( dodump )) && printf " (unexpected error: bytes exceeds expected end: 0x%02x + %d = 0x%02x > 0x%02x)" $portoffset $portlen $((portoffset + portlen)) "$thedataend" fi if (( portlen != actualportlen )); then (( dodump )) && printf " (unexpected error: too few remaining bytes: %d > %d)" $portlen $actualportlen fi (( dodump )) && echo ((portoffset += actualportlen)) done if (( doportnumber >= 0 || dostringnumber >= 0 )); then (( dosetport )) && Ports+=( "$( printf "%d %02x %02x %s %s" 0 $doportnumber 0 "$doportdisable" "$doportcontents" )" ) (( dosetstring )) && Ports+=( "$( printf "%d %02x %02x %s %s" 1 $dostringnumber 0 "0" "$(printf "%s\0" "$dostringcontents" | xxd -p -c 9999)" )" ) local allportbytes="" allportbytes=$( IFS=$'\n' for theportstring in $(sort <<< "${Ports[@]}"); do printf "%02x%02x%s" $(( (${#theportstring} - 10) / 2 + 2 )) $(( ((1 - ${theportstring:0:1}) << 7) | (${theportstring:8:1} << 6) | (0x${theportstring:2:2} & 0x3f) )) "${theportstring:10}" done ) replacebytes 22 "$allportbytes" ${#thedrom} ((thedatalen = ${#allportbytes}/2 + 22 - 13 )) replacebytes 14 "$(printf "%04x" "$thedatalen" | sed -E 's/(..)(..)/\2\1/')" doportnumber=-1 dostringnumber=-1 (( dodump )) && echo " after changes:" else break fi done theexpectedcrc32=$((0x$(xxd -p -r <<< "${thedrom:26:$thedatalen*2}" | crc32c))) (( theexpectedcrc32 != thecrc32 )) && { if (( dorepairchecksums )); then replacebytes 9 "$(printf "%08x" $theexpectedcrc32 | sed -E 's/(..)(..)(..)(..)/\4\3\2\1/')" (( dodump )) && printf "0x09) CRC32: 0x%08x (changed: 0x%08x)\n" $thecrc32 $theexpectedcrc32 else (( dodump )) && printf "0x09) CRC32: 0x%08x (expected: 0x%08x)\n" $thecrc32 $theexpectedcrc32 fi } (( dodump )) && { printf "0x%02x) End" "$portoffset" if [[ -n $(tr -d '0' <<< "${thedrom:$portoffset*2}") ]]; then printf " (unexpected bytes: %s)" "${thedrom:$portoffset*2}" fi echo } if (( domake )); then IFS=$'\n' portoffset=22 for theportstring in $(sort <<< "${Ports[@]}"); do portlen=$(( (${#theportstring} - 10) / 2 + 2 )) ((portoffset += portlen)) done printf ' "ThunderboltDROM", Buffer (0x%X) { /* 0x00 */ 0x%s, // CRC8 checksum: 0x%02X /* 0x01 */ 0x%s, 0x%s, 0x%s, 0x%s, 0x%s, 0x%s, 0x%s, 0x%s, // Thunderbolt Bus %d, UID: 0x%s /* 0x09 */ 0x%s, 0x%s, 0x%s, 0x%s, // CRC32c checksum: 0x%08X /* 0x0D */ 0x%s, // Device ROM Revision: %d /* 0x0E */ 0x%s, 0x%s, // Length: %d (starting from previous byte) /* 0x10 */ 0x%s, 0x%s, // Vendor ID: 0x%X /* 0x12 */ 0x%s, 0x%s, // Device ID: 0x%X /* 0x14 */ 0x%s, // Device Revision: 0x%X /* 0x15 */ 0x%s, // EEPROM Revision: %d ' \ $portoffset \ "${thedrom:0:2}" $thecrc8 \ "${thedrom:2:2}" "${thedrom:4:2}" "${thedrom:6:2}" "${thedrom:8:2}" "${thedrom:10:2}" "${thedrom:12:2}" "${thedrom:14:2}" "${thedrom:16:2}" $((0x${thedrom:2:2})) "$theuidnum" \ "${thedrom:18:2}" "${thedrom:20:2}" "${thedrom:22:2}" "${thedrom:24:2}" $thecrc32 \ "${thedrom:26:2}" $thedeviceromrevision \ "${thedrom:28:2}" "${thedrom:30:2}" "$thedatalen" \ "${thedrom:32:2}" "${thedrom:34:2}" $thevendorid \ "${thedrom:36:2}" "${thedrom:38:2}" $themodelid \ "${thedrom:40:2}" $themodelrev \ "${thedrom:42:2}" $theeepromrev IFS=$'\n' portoffset=22 for theportstring in $(sort <<< "${Ports[@]}"); do portlen=$(( (${#theportstring} - 10) / 2 + 2 )) theportnumber=$((0x${theportstring:2:2} & 0x3f)) theportdisabled=${theportstring:8:1} theporttype=$((1 - ${theportstring:0:1})) printf " /* 0x%02X %s %X */ 0x%02x, 0x%02x, %s" $portoffset "$( ((theportdisabled)) && printf "-" || printf " " )" $theportnumber $portlen \ $(( (theporttype << 7) | (theportdisabled << 6) | theportnumber )) \ "$( perl -pE 's/(..)/0x\1, /g' <<< "${theportstring:10}" )" if (( theporttype == 0 )); then local thestring="" thestring="$(perl -pE "s/(00)+$//" <<< "${theportstring:10}" | xxd -p -r)" if (( theportnumber == 1 )); then printf '// Vendor Name: "%s"' "$thestring" elif (( theportnumber == 2 )); then printf '// Device Name: "%s"' "$thestring" else printf '// "%s"' "${theportstring:10}" fi elif (( ${#theportstring} == 12 )); then printf '// PCIe xx:%02x.%x' $((0x${theportstring:10} >> 5)) $((0x${theportstring:10} & 0x1f)) #### fix this - function should only be 3 bits - therefore there are 2 unknown bits? fi printf "\n" ((portoffset += portlen)) done printf " },\n" fi } repairchecksums () { processdrom dorepairchecksums } setuid () { processdrom dorepairchecksums dosetuid "$1" } setport () { processdrom dorepairchecksums dosetport "$@" } deleteport () { processdrom dorepairchecksums dodeleteport "$1" } setstring () { processdrom dorepairchecksums dosetstring "$@" } deletestring () { processdrom dorepairchecksums dodeletestring "$1" } #========================================================================================= # Files from DROM dumpdrom () { processdrom dodump } makedromdsl () { processdrom domake } makedromdslall () { local savedrom="$thedrom" local thefolderpath="$1" local i="" for ((i = 1 ; i <= ${#droms[@]} ; i++)); do usedromnum "$i" makedromdsl > "${thefolderpath:=.}/${thefilenamebase}_makedromdsl.txt" done usedromstring "$savedrom" } dumpdromall () { local i="" for ((i = 1 ; i <= ${#droms[@]} ; i++)); do echo "=======================================" echo "$i)" usedromnum "$i" dumpdrom done } dumpdromalltofiles () { local savedrom="$thedrom" local thefolderpath="$1" local i="" for ((i = 1 ; i <= ${#droms[@]} ; i++)); do usedromnum "$i" dumpdrom > "${thefolderpath:=.}/${thefilenamebase}_dumpdrom.txt" done usedromstring "$savedrom" } #========================================================================================= # Use DROM cleardrominfo () { # clear anything here that is not cleared by processdrom : } usedromstring () { cleardrominfo (( debug )) && echo ": usedromstring $1" 1>&2 thedrom="$1" processdrom } usedromnum () { cleardrominfo thedrom=${droms[arrstart - 1 + $1]} processdrom thefilenamebase="${thefilenamebase}_$i" } #========================================================================================= # DROM List cleardroms () { droms=() paths=() } cleardroms adddrom () { local savedrom="$thedrom" local thepath="$1" usedromstring "$2" (( ignoreuid )) && replacebytes 0 188877665544332211 local isnew=1 local i="" for ((i = 0 ; i < ${#droms[@]} ; i++)); do if [[ $thedrom = "${droms[i+arrstart]}" ]]; then if [[ ! "$(printf "_\n%s\n_" "${paths[i+arrstart]}")" =~ $(printf ".*\n%s\n.*" "${thepath}") ]]; then paths[i+arrstart]="$(printf "%s\n%s" "${paths[i+arrstart]}" "$thepath")" fi isnew=0 break fi done if (( isnew )); then (( debug )) && echo ": isnew" 1>&2 droms+=("$thedrom") paths+=("$thepath") fi usedromstring "$savedrom" } numstrings=0 loadstring () { local sourcename="$2" if [[ -z $sourcename ]]; then ((numstrings++)) sourcename="string:$numstrings" fi adddrom "$sourcename" "$1" } loadhexfile () { adddrom "$1" "$(xxd -r "$1" | xxd -p -c 99999)" } loadonedromitem () { local dromitem="$1" local thepath="${dromitem% = <*}" local thedrom="${dromitem##* = <}" local thedrom="${thedrom%>}" (( debug )) && echo ":" adddrom "${thepath}" "${thedrom}" 1>&2 adddrom "${thepath}" "${thedrom}" } loadfwfile () { while (( $# )); do local thefilename="$1" shift IFS=$'\n' for dromitem in $( xxd -p -c 9999999999 "$thefilename" | perl -e ' while (<>) { s/(..)/\1 /g; $start = 0; foreach my $offset (0, 4096 * 3) { $start = hex(substr($_, $offset, 11) =~ s/(..) (..) (..) (..)/$4$3$2$1/r); last if ($start != hex("ffffffff")); } # look for DROM while ( /(?{$X=pos()})44 52 4f 4d 20 20 20 20 ff ff ff ff ff ff ff ff ((.. ){1008})(?{$Y=pos()})/g ) { $X /= 3; $thedrom=$1; $thedrom =~ s/(ff )*$//g; $thedrom =~ s/ //g; $version = "vers_unknown"; if ($X < hex(4000)) { $partition = "missing header"; } elsif ($X < hex(82000)) { $version = "v" . substr($_, (hex(4000) + 10) * 3, 2); if ($start == hex(4000)) { $partition = "active"; } elsif ($start == hex(82000)) { $partition = "inactive"; } else { $partition = "unknown start"; } } elsif ($X < hex(100000)) { $version = "v" . substr($_, (hex(82000) + 10) * 3, 2); if ($start == hex(4000)) { $partition = "inactive"; } elsif ($start == hex(82000)) { $partition = "active"; } else { $partition = "unknown start"; } } else { $partition = "rom too large"; } pos() = $Y; $nvmversion = "nvm_unknown"; # get nvm version from after EE_PCIE if ( /(?{$Z=pos()})45 45 5f 50 43 49 45 20 (?:ff ){8}(?:.. )*?(..) (..) (..) (..) (?:.. ){4}(?:ff ){8}(?{$W=pos()})/g ) { pos() = $W; # need to find out what all the digits are for - I am just guessing here: $nvmversion="nvm_v" . (( $2 . $1 . "." . $3 . $4 ) =~ s/0*([^.]*.)\.0*(.+)/\1.\2/r ); } else { pos() = $Y; } printf ("%s:%s:%s:%s:0x%x = <%s>\n", "'"${thefilename}"'", $partition, $version, $nvmversion, $X, $thedrom); } } ' ); do (( debug )) && echo ":" loadonedromitem "${dromitem}" 1>&2 loadonedromitem "${dromitem}" done done } loadonedslfile () { local thefilename="$1" local thesource="$2" [[ -z $thesource ]] && thesource="$thefilename" IFS=$'\n' for dromitem in $( # # LeadNameChar := [A-Za-z_] # DigitChar := [0-9] # NameChar := [A-Za-z_0-9] # RootChar := \ # ParentPrefixChar := ^ # PathSeparatorChar := . # # // Names and paths # # NameSeg := [A-Za-z_][A-Za-z_0-9]{0,3} # # PrefixPath := \^* # # NamePathTail := ([.][A-Za-z_][A-Za-z_0-9]{0,3})* # # NamePath := (([A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})*)|) # # NonEmptyNamePath := [A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})* # # NameString := ([\\]|\^+|)(([A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})*)|) # | [A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})* # perl -e ' use strict; my $line3 = ""; my $line2 = ""; my $line1 = ""; my %paths = ( "\\" => 1 ); sub addline { $line3 = $line2; $line2 = $line1; $line1 = $_[0]; } sub group { my $indent = $_[0]; my $codepath = $_[1]; my $acpipath = $_[2]; my $nextacpipath = $acpipath; my $nextcodepath = $codepath; my $dodump = 0; my $buffersize = 0; if ( ($line2 . $line1) =~ /"ThunderboltDROM",\s*Buffer\s*\(0x([0-9A-F]+)\)/ ) { # print "gotpattern «" . $line2 . "»«" . $line1 . "»\n"; $dodump = 1; $buffersize = hex($1); } if ( $dodump == 1 ) { print "'"$thesource"':" . $acpipath . ":ThunderboltDROM = <"; } while (<>) { s/\s*\/\/.*//; # single line // comment s/\s*\/\*.*?\*\/\s*//g; # single line /* */ comment s/\s*(.*?)\s*$/\1/g; # remove indents and trailing spaces if (/^\/\*.*/ .. /^.*?\*\/.*/) { } # multi line comment elsif ( /^$/ ) { } # skip blank lines elsif ( /^{$/ ) { group($indent . "\t", $nextcodepath, $nextacpipath); } elsif ( /^}/ ) { if ( $dodump == 1 ) { if ($buffersize < 0) { print STDERR "Buffer size is too small\n"; } elsif ($buffersize > 0) { print "00"x$buffersize; } print ">\n"; $dodump = 0; } last; } else { addline($_); if ( /(External|Device|Field|Method|Name|Scope)\s*\(\s*([\\]|\^+|)(([A-Za-z_][A-Za-z_0-9]{0,3}([.][A-Za-z_][A-Za-z_0-9]{0,3})*)|)/ ) { my $command = $1; my $prefix = $2; my $nameparts = $3; if ( $prefix =~ /\\/ ) { $nextacpipath = $prefix . $nameparts; } elsif ( $prefix =~ /\^+/ ) { my $pattern = "(.*?)([\\\\.][^.]+){0," . length($prefix) . "}\$"; $nextacpipath = ($acpipath =~ s/$pattern/\1/r =~ s/^$/\\/r) . "$nameparts"; } elsif ( ($command eq "Scope") && ($nameparts =~ /[^.]+/) ) { if ( $paths{$acpipath . "." . $nameparts} ) { $nextacpipath = (($acpipath . "." . $nameparts) =~ s/^\\\./\\/r =~ s/([A-Za-z0-9])_+/\1/gr); } elsif ( ($acpipath . ".") =~ /(.*[.\\]$nameparts)[.].*/ ) { $nextacpipath = (($acpipath . ".") =~ s/(.*[.\\]$nameparts)[.].*/\1/r) } else { $nextacpipath = (($acpipath . "." . $nameparts) =~ s/^\\\./\\/r =~ s/([A-Za-z0-9])_+/\1/gr); print STDERR "unknown path " . $nextacpipath . "\n"; } } else { $nextacpipath = (($acpipath . "." . $nameparts) =~ s/^\\\./\\/r =~ s/([A-Za-z0-9])_+/\1/gr); } $nextcodepath = (($codepath . "." . $prefix . $nameparts) =~ s/^\\\./\\/r =~ s/([A-Za-z0-9])_+/\1/gr =~ s/\\\\/\\/r); if ( !$paths{$nextacpipath} ) { $paths{$nextacpipath} = 1; } } else { $nextacpipath = $acpipath; $nextcodepath = $codepath; if ( $dodump == 1 ) { my $outline = ($line1 =~ s/0x//gr =~ s/[, ]//gr); print $outline; $buffersize -= length($outline) / 2; } } } } } group("", "\\", "\\"); ' < "$thefilename" ); do (( debug )) && echo ":" loadonedromitem "${dromitem}" 1>&2 loadonedromitem "${dromitem}" done } loaddslfile () { while (( $# )); do local thefilename="$1" shift loadonedslfile "$thefilename" done } loadamlfile () { [[ -f $iasl_location ]] || { echo "# Update iasl_location" 1>&2 exit 1 } thedirname=$(mktemp -d /tmp/aml.XXXXXX) || exit 1 while (( $# )); do local thefilename="$1" shift if "$iasl_location" -p "$thedirname/xxx" "$thefilename" > /dev/null 2> "$thedirname/out.txt"; then loadonedslfile "$thedirname/xxx.dsl" "$thefilename" else cat "$thedirname/out.txt" 1>&2 fi done } loadoneioregfile () { local thefilename="$1" local thesource="$2" [[ -z $thesource ]] && thesource="$thefilename" IFS=$'\n' for dromitem in $( perl -e ' $thepath=""; while (<>) { if ( /^([ |]*)\+\-o (.+) </ ) { $indent = (length $1) / 2; $name = $2; $thepath =~ s|^((/[^/]*){$indent}).*|$1/$name| } if ( /^[ |]*"(ThunderboltDROM)" = <(.*)>/i ) { print "'"${thesource}"'" . ":" . $thepath . "/" . $1 . " = <" . $2 . ">\n" } } ' < "${thefilename}" ); do loadonedromitem "${dromitem}" done } loadioregfile () { while (( $# )); do local thefilename="$1" shift loadoneioregfile "$thefilename" done } loadioreg () { local tmpfilename="" tmpfilename=$(mktemp /tmp/local_ioreg.XXXXXX) || exit 1 ioreg -lw0 > "$tmpfilename" loadoneioregfile "$tmpfilename" "ioreg" } listdroms () { local savedrom="$thedrom" local i="" for ((i = 1 ; i <= ${#droms[@]} ; i++)); do usedromnum "$i" echo "$i)" echo "thedrom=$thedrom" echo "sources:" echo "${paths[i+arrstart-1]}" echo done usedromstring "$savedrom" } #========================================================================================= # Misc extractfwfromexe () { while (( $# )); do local thefilename="$1" shift perl -0777 -e ' while (<>) { #printf "file:%s\n", $ARGV; @files = ( /\0([^\0]+.bin)(?=\0)/g ); $filenum = 0; while ( /(?{$x=pos()})DROM(?{$y=pos()})/g ) { $sb = substr $_, $x - 0x4200 - 4, 4; $size = (ord(substr $sb, 3, 1) << 24) | (ord(substr $sb, 2, 1) << 16) | (ord(substr $sb, 1, 1) << 8) | ord (substr $sb, 0, 1); $filename = @files[$filenum]; if ( $filename =~ /^$/ ) { $filename = "fw.bin"; } $dir = sprintf "%s/%02d", `dirname "$ARGV"` =~ s/\n$//r, $filenum; `mkdir -p "$dir"`; open(FH, ">", "$dir/$filename") or die $!; print FH substr $_, $x - 0x4200, $size; close(FH); pos() = $y; $filenum++; } } ' "$thefilename" done } #========================================================================================= # Help dromhelp () { echo $' Commands: Get DROM loadioreg loadstring hexstring [sourcename] loadfwfile filepath... loadamlfile filepath... loaddslfile filepath... loadioregfile filepath... loadhexfile filepath # for reverses xxd listdroms cleardroms Use DROM usedromnum numberfromlist usedromstring lowercasehexstring Modify DROM repairchecksums replacebytes bytepos lowercasehexstring [numbytestoreplace] setuid newuid setport 0xportnumber portcontents [-] deleteport 0xportnumber setstring 0xstringnumber stringvalue deletestring 0xstringnumber Files from DROM dumpdrom makedromdsl makedromdslall [folderpath] dumpdromall dumpdromalltofiles [folderpath] Misc extractfwfromexe exepath... # $(grep -l --include \'*.exe\' -R \'DROM\' . ) Variables dodump # Set to 1 to dump the DROM while changes are made to the DROM. debug # Set to 1 to output debugging info (uses stderr) ignoreuid # Set to 1 to replace all uids with 0x1122334455667788. # DROMs with the same contents except UID will be considered identical. Help dromhelp ' } #dromhelp #=========================================================================================