Last active 1 month ago

Revision 83475f9c342d2f44bb655202dbff43ec56ab3ed4

get_macbook_ramcfg Raw
1#!/usr/bin/env python3
2#
3# get_macbook_ramcfg
4#
5# Decode Apple MacBook RAM configuration (RAMCFG) from Intel chipset GPIO
6# registers using output from `inteltool -g`.
7#
8# This script maps Apple’s undocumented GPIO-based RAM configuration
9# encoding to concrete memory vendor, size, and speed identifiers for
10# specific MacBook models.
11#
12# USAGE
13# sudo inteltool -g | get_macbook_ramcfg -m <MODEL>
14#
15# SUPPORTED MODELS
16# mbp101 - MacBook Pro 10,1
17# mba52 - MacBook Air 5,2
18# mba42 - MacBook Air 4,2
19#
20# NOTES
21# - Reads GPIO68–GPIO71 from the GPIO_LVL3 register
22# - Reverses bit order to match Apple’s wiring
23# - Uses RAMCFG value as an index into model-specific lookup tables
24#
25# CREDITS
26# Original implementation by ch1p (https://ch1p.io/)
27#
28# LICENSE
29# BSD-2-Clause
30#
31# EXTENSIONS & MAINTENANCE
32# Extended and maintained by Kris Yotam
33#
34
35#!/usr/bin/env python3
36import sys
37import argparse
38
39
40ramconfigs = {
41 'mba42': (
42 '2b_hynix',
43 None,
44 '4g_hynix',
45 None,
46 '2g_samsung',
47 None,
48 '4g_samsung',
49 None,
50 '2g_micron',
51 None,
52 None,
53 None,
54 None,
55 None,
56 '4g_elpida',
57 ),
58 'mba52': (
59 '4g_hynix',
60 '4g_micron',
61 '8g_hynix',
62 None,
63 '4g_samsung',
64 None,
65 '8g_samsung',
66 None,
67 None,
68 None,
69 None,
70 None,
71 '4g_elpida',
72 None,
73 '8g_elpida',
74 ),
75 'mbp101': (
76 '4g_hynix_1600s',
77 '1g_samsung_1600',
78 '4g_samsung_1600s',
79 '1g_hynix_1600',
80 '4g_elpida_1600s',
81 '2g_samsung_1600',
82 '2g_samsung_1333',
83 '2g_hynix_1600',
84 '4g_samsung_1600',
85 '4g_hynix_1600',
86 '2g_elpida_1600s',
87 '2g_elpida_1600',
88 '4g_elpida_1600',
89 '2g_samsung_1600s',
90 '2g_hynix_1600s'
91 )
92}
93
94
95def main():
96 parser = argparse.ArgumentParser()
97 parser.add_argument('-m', '--model',
98 choices=list(ramconfigs.keys()),
99 help='MacBook model',
100 required=True)
101
102 args = parser.parse_args()
103
104 configs = ramconfigs[args.model]
105
106 reg = None
107 for line in sys.stdin:
108 line = line.strip()
109 if not line.endswith('(GPIO_LVL3)'):
110 continue
111
112 reg = int(line.split(' ')[1], 16)
113 break
114
115 if reg is None:
116 raise Exceptions("failed to parse gpio registers")
117
118 # GPIO68..GPIO71
119 ramcfg = (reg >> 4) & 0xf
120
121 # reverse bit order
122 ramcfg = int('{:04b}'.format(ramcfg)[::-1], 2)
123
124 if ramcfg >= len(configs) or configs[ramcfg] is None:
125 print("unsupported memory configuration %d" % ramcfg)
126 else:
127 print("%s (RAMCFG=%01x)" % (configs[ramcfg], ramcfg))
128
129
130if __name__ == '__main__':
131 main()
132