-
Notifications
You must be signed in to change notification settings - Fork 10
/
disable_cpu_cores.py
executable file
·131 lines (107 loc) · 4.33 KB
/
disable_cpu_cores.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/python
import struct
import argparse
import gzip
import io
from collections import namedtuple
# See system/core/mkbootimg/bootimg.h
BOOT_MAGIC_SIZE = 8
BOOT_NAME_SIZE = 16
BOOT_ARGS_SIZE = 512
BOOT_EXTRA_ARGS_SIZE = 1024
HEADER_STRUCT = '<8sIIIIIIIIII16s512s32s1024s'
ImageHeader = namedtuple('ImageHeader', 'magic, kernel_size, kernel_addr, ramdisk_size, ramdisk_addr, second_size, second_addr, tags_addr, page_size, unused, os_version, name, cmdline, id, extra_cmdline')
Image = namedtuple('Image', 'header, kernel, ramdisk, second')
# Strings to replace inside ramdisk (each pair must have equal size because we do not parse the cpio format)
REPLACE_STRINGS = [
(
b'write /dev/cpuset/foreground/cpus 0-2,4-5',
b'write /dev/cpuset/foreground/cpus 0-3 '
),
(
b'write /dev/cpuset/foreground/boost/cpus 4-5',
b'write /dev/cpuset/foreground/boost/cpus 0-3'
),
(
b'write /dev/cpuset/background/cpus 0',
b'write /dev/cpuset/background/cpus 3'
),
(
b'write /dev/cpuset/system-background/cpus 0-2',
b'write /dev/cpuset/system-background/cpus 2-3'
),
(
b'write /dev/cpuset/top-app/cpus 0-5',
b'write /dev/cpuset/top-app/cpus 0-3'
)
]
REPLACE_ENCRYPTION = [
(
b',verify=/dev/block/platform/soc.0/f9824900.sdhci/by-name/metadata',
b' '
),
(
b',forcefdeorfbe=/dev/block/platform/soc.0/f9824900.sdhci/by-name/metadata',
b' '
)
]
def main():
parser = argparse.ArgumentParser(description='Modifies a Nexus 5X boot or recovery image to disable big cores.')
parser.add_argument('input', type=str, help='input file')
parser.add_argument('output', type=str, help='output file')
parser.add_argument('--disable-encryption', action='store_true', help='disable encryption and verified boot')
args = parser.parse_args()
with open(args.input, 'rb') as infile:
original_content = infile.read()
header = ImageHeader._make(struct.unpack_from(HEADER_STRUCT, original_content))
# Round up to nearest page size
def pad_size(original_size):
return ((original_size + header.page_size - 1) // header.page_size) * header.page_size
image_struct = '<%ds%ds%ds%ds' % (header.page_size, pad_size(header.kernel_size), pad_size(header.ramdisk_size), pad_size(header.second_size))
image = Image._make(struct.unpack_from(image_struct, original_content))
# Modify cmdline
header = header._replace(cmdline=modify_cmdline(header.cmdline))
# Modify ramdisk
replace_strings = REPLACE_STRINGS
if args.disable_encryption:
replace_strings = replace_strings + REPLACE_ENCRYPTION
image = image._replace(ramdisk=compress(modify_ramdisk(uncompress(image.ramdisk), replace_strings)))
header = header._replace(ramdisk_size=len(image.ramdisk))
# Generate new header
image = image._replace(header=struct.pack(HEADER_STRUCT, *header))
# Generate new image
image_struct = '<%ds%ds%ds%ds' % (header.page_size, pad_size(header.kernel_size), pad_size(header.ramdisk_size), pad_size(header.second_size))
new_image = struct.pack(image_struct, *image)
with open(args.output, 'wb') as outfile:
outfile.write(new_image)
# Strip garbage from null-terminated string
def strip(input):
return input.partition(b'\0')[0]
# Modify cmdline to use 4 CPUs
def modify_cmdline(cmdline):
original_cmdline = strip(cmdline)
new_cmdline = cmdline.replace(b'boot_cpus=0-5', b'boot_cpus=0-3 maxcpus=4')
print("Original cmdline: " + cmdline.decode('ascii'))
print("Modified cmdline: " + new_cmdline.decode('ascii'))
return new_cmdline
# Modify ramdisk which will override cmdline when booted
def modify_ramdisk(ramdisk, replace_strings):
for (search, replace) in replace_strings:
if ramdisk.find(search) >= 0:
print("Found : " + search.decode('ascii'))
print("Replaced: " + replace.decode('ascii'))
ramdisk = ramdisk.replace(search, replace)
else:
print("Not Found: " + search.decode('ascii'))
return ramdisk
# Gunzip string
def uncompress(gzip_string):
with gzip.GzipFile(fileobj=io.BytesIO(gzip_string)) as f:
return f.read()
def compress(plain_string):
out = io.BytesIO()
with gzip.GzipFile(fileobj=out, mode='wb', mtime=0) as f:
f.write(plain_string)
return out.getvalue()
if __name__ == "__main__":
main()