1*8617a60dSAndroid Build Coastguard Worker /* Copyright 2012 The ChromiumOS Authors
2*8617a60dSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
3*8617a60dSAndroid Build Coastguard Worker * found in the LICENSE file.
4*8617a60dSAndroid Build Coastguard Worker */
5*8617a60dSAndroid Build Coastguard Worker
6*8617a60dSAndroid Build Coastguard Worker #include <string.h>
7*8617a60dSAndroid Build Coastguard Worker
8*8617a60dSAndroid Build Coastguard Worker #include "cgpt.h"
9*8617a60dSAndroid Build Coastguard Worker #include "cgptlib_internal.h"
10*8617a60dSAndroid Build Coastguard Worker #include "vboot_host.h"
11*8617a60dSAndroid Build Coastguard Worker
12*8617a60dSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
13*8617a60dSAndroid Build Coastguard Worker // We need a sorted list of priority groups, where each element in the list
14*8617a60dSAndroid Build Coastguard Worker // contains an unordered list of GPT partition numbers.
15*8617a60dSAndroid Build Coastguard Worker
16*8617a60dSAndroid Build Coastguard Worker #define MAX_GROUPS 17 // 0-15, plus one "higher"
17*8617a60dSAndroid Build Coastguard Worker
18*8617a60dSAndroid Build Coastguard Worker typedef struct {
19*8617a60dSAndroid Build Coastguard Worker int priority; // priority of this group
20*8617a60dSAndroid Build Coastguard Worker int num_parts; // number of partitions in this group
21*8617a60dSAndroid Build Coastguard Worker uint32_t *part; // array of partitions in this group
22*8617a60dSAndroid Build Coastguard Worker } group_t;
23*8617a60dSAndroid Build Coastguard Worker
24*8617a60dSAndroid Build Coastguard Worker typedef struct {
25*8617a60dSAndroid Build Coastguard Worker int max_parts; // max number of partitions in any group
26*8617a60dSAndroid Build Coastguard Worker int num_groups; // number of non-empty groups
27*8617a60dSAndroid Build Coastguard Worker group_t group[MAX_GROUPS]; // array of groups
28*8617a60dSAndroid Build Coastguard Worker } group_list_t;
29*8617a60dSAndroid Build Coastguard Worker
30*8617a60dSAndroid Build Coastguard Worker
NewGroupList(int max_p)31*8617a60dSAndroid Build Coastguard Worker static group_list_t *NewGroupList(int max_p) {
32*8617a60dSAndroid Build Coastguard Worker int i;
33*8617a60dSAndroid Build Coastguard Worker group_list_t *gl = (group_list_t *)malloc(sizeof(group_list_t));
34*8617a60dSAndroid Build Coastguard Worker require(gl);
35*8617a60dSAndroid Build Coastguard Worker gl->max_parts = max_p;
36*8617a60dSAndroid Build Coastguard Worker gl->num_groups = 0;
37*8617a60dSAndroid Build Coastguard Worker // reserve space for the maximum number of partitions in every group
38*8617a60dSAndroid Build Coastguard Worker for (i=0; i<MAX_GROUPS; i++) {
39*8617a60dSAndroid Build Coastguard Worker gl->group[i].priority = -1;
40*8617a60dSAndroid Build Coastguard Worker gl->group[i].num_parts = 0;
41*8617a60dSAndroid Build Coastguard Worker gl->group[i].part = (uint32_t *)malloc(sizeof(uint32_t) * max_p);
42*8617a60dSAndroid Build Coastguard Worker require(gl->group[i].part);
43*8617a60dSAndroid Build Coastguard Worker }
44*8617a60dSAndroid Build Coastguard Worker
45*8617a60dSAndroid Build Coastguard Worker return gl;
46*8617a60dSAndroid Build Coastguard Worker }
47*8617a60dSAndroid Build Coastguard Worker
FreeGroups(group_list_t * gl)48*8617a60dSAndroid Build Coastguard Worker static void FreeGroups(group_list_t *gl) {
49*8617a60dSAndroid Build Coastguard Worker int i;
50*8617a60dSAndroid Build Coastguard Worker for (i=0; i<MAX_GROUPS; i++)
51*8617a60dSAndroid Build Coastguard Worker free(gl->group[i].part);
52*8617a60dSAndroid Build Coastguard Worker free(gl);
53*8617a60dSAndroid Build Coastguard Worker }
54*8617a60dSAndroid Build Coastguard Worker
AddToGroup(group_list_t * gl,int priority,int partition)55*8617a60dSAndroid Build Coastguard Worker static void AddToGroup(group_list_t *gl, int priority, int partition) {
56*8617a60dSAndroid Build Coastguard Worker int i;
57*8617a60dSAndroid Build Coastguard Worker // See if I've already got a group with this priority
58*8617a60dSAndroid Build Coastguard Worker for (i=0; i<gl->num_groups; i++)
59*8617a60dSAndroid Build Coastguard Worker if (gl->group[i].priority == priority)
60*8617a60dSAndroid Build Coastguard Worker break;
61*8617a60dSAndroid Build Coastguard Worker if (i == gl->num_groups) {
62*8617a60dSAndroid Build Coastguard Worker // no, add a group
63*8617a60dSAndroid Build Coastguard Worker require(i < MAX_GROUPS);
64*8617a60dSAndroid Build Coastguard Worker gl->num_groups++;
65*8617a60dSAndroid Build Coastguard Worker gl->group[i].priority = priority;
66*8617a60dSAndroid Build Coastguard Worker }
67*8617a60dSAndroid Build Coastguard Worker // add the partition to it
68*8617a60dSAndroid Build Coastguard Worker int j = gl->group[i].num_parts;
69*8617a60dSAndroid Build Coastguard Worker gl->group[i].part[j] = partition;
70*8617a60dSAndroid Build Coastguard Worker gl->group[i].num_parts++;
71*8617a60dSAndroid Build Coastguard Worker }
72*8617a60dSAndroid Build Coastguard Worker
ChangeGroup(group_list_t * gl,int old_priority,int new_priority)73*8617a60dSAndroid Build Coastguard Worker static void ChangeGroup(group_list_t *gl, int old_priority, int new_priority) {
74*8617a60dSAndroid Build Coastguard Worker int i;
75*8617a60dSAndroid Build Coastguard Worker for (i=0; i<gl->num_groups; i++)
76*8617a60dSAndroid Build Coastguard Worker if (gl->group[i].priority == old_priority) {
77*8617a60dSAndroid Build Coastguard Worker gl->group[i].priority = new_priority;
78*8617a60dSAndroid Build Coastguard Worker break;
79*8617a60dSAndroid Build Coastguard Worker }
80*8617a60dSAndroid Build Coastguard Worker }
81*8617a60dSAndroid Build Coastguard Worker
SortGroups(group_list_t * gl)82*8617a60dSAndroid Build Coastguard Worker static void SortGroups(group_list_t *gl) {
83*8617a60dSAndroid Build Coastguard Worker int i, j;
84*8617a60dSAndroid Build Coastguard Worker group_t tmp;
85*8617a60dSAndroid Build Coastguard Worker
86*8617a60dSAndroid Build Coastguard Worker // straight insertion sort is fast enough
87*8617a60dSAndroid Build Coastguard Worker for (i=1; i<gl->num_groups; i++) {
88*8617a60dSAndroid Build Coastguard Worker tmp = gl->group[i];
89*8617a60dSAndroid Build Coastguard Worker for (j=i; j && (gl->group[j-1].priority < tmp.priority); j--)
90*8617a60dSAndroid Build Coastguard Worker gl->group[j] = gl->group[j-1];
91*8617a60dSAndroid Build Coastguard Worker gl->group[j] = tmp;
92*8617a60dSAndroid Build Coastguard Worker }
93*8617a60dSAndroid Build Coastguard Worker }
94*8617a60dSAndroid Build Coastguard Worker
CgptPrioritize(CgptPrioritizeParams * params)95*8617a60dSAndroid Build Coastguard Worker int CgptPrioritize(CgptPrioritizeParams *params) {
96*8617a60dSAndroid Build Coastguard Worker struct drive drive;
97*8617a60dSAndroid Build Coastguard Worker
98*8617a60dSAndroid Build Coastguard Worker int priority;
99*8617a60dSAndroid Build Coastguard Worker
100*8617a60dSAndroid Build Coastguard Worker int gpt_retval;
101*8617a60dSAndroid Build Coastguard Worker uint32_t index;
102*8617a60dSAndroid Build Coastguard Worker uint32_t max_part;
103*8617a60dSAndroid Build Coastguard Worker int num_kernels;
104*8617a60dSAndroid Build Coastguard Worker int i,j;
105*8617a60dSAndroid Build Coastguard Worker group_list_t *groups;
106*8617a60dSAndroid Build Coastguard Worker
107*8617a60dSAndroid Build Coastguard Worker if (params == NULL)
108*8617a60dSAndroid Build Coastguard Worker return CGPT_FAILED;
109*8617a60dSAndroid Build Coastguard Worker
110*8617a60dSAndroid Build Coastguard Worker if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR,
111*8617a60dSAndroid Build Coastguard Worker params->drive_size))
112*8617a60dSAndroid Build Coastguard Worker return CGPT_FAILED;
113*8617a60dSAndroid Build Coastguard Worker
114*8617a60dSAndroid Build Coastguard Worker if (GPT_SUCCESS != (gpt_retval = GptValidityCheck(&drive.gpt))) {
115*8617a60dSAndroid Build Coastguard Worker Error("GptValidityCheck() returned %d: %s\n",
116*8617a60dSAndroid Build Coastguard Worker gpt_retval, GptError(gpt_retval));
117*8617a60dSAndroid Build Coastguard Worker goto bad;
118*8617a60dSAndroid Build Coastguard Worker }
119*8617a60dSAndroid Build Coastguard Worker
120*8617a60dSAndroid Build Coastguard Worker if (CGPT_OK != CheckValid(&drive)) {
121*8617a60dSAndroid Build Coastguard Worker Error("please run 'cgpt repair' before reordering the priority.\n");
122*8617a60dSAndroid Build Coastguard Worker (void) DriveClose(&drive, 0);
123*8617a60dSAndroid Build Coastguard Worker return CGPT_OK;
124*8617a60dSAndroid Build Coastguard Worker }
125*8617a60dSAndroid Build Coastguard Worker
126*8617a60dSAndroid Build Coastguard Worker max_part = GetNumberOfEntries(&drive);
127*8617a60dSAndroid Build Coastguard Worker
128*8617a60dSAndroid Build Coastguard Worker if (params->set_partition) {
129*8617a60dSAndroid Build Coastguard Worker if (params->set_partition < 1 || params->set_partition > max_part) {
130*8617a60dSAndroid Build Coastguard Worker Error("invalid partition number: %d (must be between 1 and %d\n",
131*8617a60dSAndroid Build Coastguard Worker params->set_partition, max_part);
132*8617a60dSAndroid Build Coastguard Worker goto bad;
133*8617a60dSAndroid Build Coastguard Worker }
134*8617a60dSAndroid Build Coastguard Worker index = params->set_partition - 1;
135*8617a60dSAndroid Build Coastguard Worker // it must be a kernel
136*8617a60dSAndroid Build Coastguard Worker if (!IsKernel(&drive, PRIMARY, index)) {
137*8617a60dSAndroid Build Coastguard Worker Error("partition %d is not a ChromeOS kernel\n", params->set_partition);
138*8617a60dSAndroid Build Coastguard Worker goto bad;
139*8617a60dSAndroid Build Coastguard Worker }
140*8617a60dSAndroid Build Coastguard Worker }
141*8617a60dSAndroid Build Coastguard Worker
142*8617a60dSAndroid Build Coastguard Worker // How many kernel partitions do I have?
143*8617a60dSAndroid Build Coastguard Worker num_kernels = 0;
144*8617a60dSAndroid Build Coastguard Worker for (i = 0; i < max_part; i++) {
145*8617a60dSAndroid Build Coastguard Worker if (IsKernel(&drive, PRIMARY, i))
146*8617a60dSAndroid Build Coastguard Worker num_kernels++;
147*8617a60dSAndroid Build Coastguard Worker }
148*8617a60dSAndroid Build Coastguard Worker
149*8617a60dSAndroid Build Coastguard Worker if (num_kernels) {
150*8617a60dSAndroid Build Coastguard Worker // Determine the current priority groups
151*8617a60dSAndroid Build Coastguard Worker groups = NewGroupList(num_kernels);
152*8617a60dSAndroid Build Coastguard Worker for (i = 0; i < max_part; i++) {
153*8617a60dSAndroid Build Coastguard Worker if (!IsKernel(&drive, PRIMARY, i))
154*8617a60dSAndroid Build Coastguard Worker continue;
155*8617a60dSAndroid Build Coastguard Worker
156*8617a60dSAndroid Build Coastguard Worker priority = GetPriority(&drive, PRIMARY, i);
157*8617a60dSAndroid Build Coastguard Worker
158*8617a60dSAndroid Build Coastguard Worker // Is this partition special?
159*8617a60dSAndroid Build Coastguard Worker if (params->set_partition && (i+1 == params->set_partition)) {
160*8617a60dSAndroid Build Coastguard Worker params->orig_priority = priority; // remember the original priority
161*8617a60dSAndroid Build Coastguard Worker if (params->set_friends)
162*8617a60dSAndroid Build Coastguard Worker AddToGroup(groups, priority, i); // we'll move them all later
163*8617a60dSAndroid Build Coastguard Worker else
164*8617a60dSAndroid Build Coastguard Worker AddToGroup(groups, 99, i); // move only this one
165*8617a60dSAndroid Build Coastguard Worker } else {
166*8617a60dSAndroid Build Coastguard Worker AddToGroup(groups, priority, i); // just remember
167*8617a60dSAndroid Build Coastguard Worker }
168*8617a60dSAndroid Build Coastguard Worker }
169*8617a60dSAndroid Build Coastguard Worker
170*8617a60dSAndroid Build Coastguard Worker // If we're including friends, then change the original group priority
171*8617a60dSAndroid Build Coastguard Worker if (params->set_partition && params->set_friends) {
172*8617a60dSAndroid Build Coastguard Worker ChangeGroup(groups, params->orig_priority, 99);
173*8617a60dSAndroid Build Coastguard Worker }
174*8617a60dSAndroid Build Coastguard Worker
175*8617a60dSAndroid Build Coastguard Worker // Sorting gives the new order. Now we just need to reassign the
176*8617a60dSAndroid Build Coastguard Worker // priorities.
177*8617a60dSAndroid Build Coastguard Worker SortGroups(groups);
178*8617a60dSAndroid Build Coastguard Worker
179*8617a60dSAndroid Build Coastguard Worker // We'll never lower anything to zero, so if the last group is priority zero
180*8617a60dSAndroid Build Coastguard Worker // we can ignore it.
181*8617a60dSAndroid Build Coastguard Worker i = groups->num_groups;
182*8617a60dSAndroid Build Coastguard Worker if (groups->group[i-1].priority == 0)
183*8617a60dSAndroid Build Coastguard Worker groups->num_groups--;
184*8617a60dSAndroid Build Coastguard Worker
185*8617a60dSAndroid Build Coastguard Worker // Where do we start?
186*8617a60dSAndroid Build Coastguard Worker if (params->max_priority)
187*8617a60dSAndroid Build Coastguard Worker priority = params->max_priority;
188*8617a60dSAndroid Build Coastguard Worker else
189*8617a60dSAndroid Build Coastguard Worker priority = groups->num_groups > 15 ? 15 : groups->num_groups;
190*8617a60dSAndroid Build Coastguard Worker
191*8617a60dSAndroid Build Coastguard Worker // Figure out what the new values should be
192*8617a60dSAndroid Build Coastguard Worker for (i=0; i<groups->num_groups; i++) {
193*8617a60dSAndroid Build Coastguard Worker groups->group[i].priority = priority;
194*8617a60dSAndroid Build Coastguard Worker if (priority > 1)
195*8617a60dSAndroid Build Coastguard Worker priority--;
196*8617a60dSAndroid Build Coastguard Worker }
197*8617a60dSAndroid Build Coastguard Worker
198*8617a60dSAndroid Build Coastguard Worker // Now apply the ranking to the GPT
199*8617a60dSAndroid Build Coastguard Worker for (i=0; i<groups->num_groups; i++)
200*8617a60dSAndroid Build Coastguard Worker for (j=0; j<groups->group[i].num_parts; j++)
201*8617a60dSAndroid Build Coastguard Worker SetPriority(&drive, PRIMARY,
202*8617a60dSAndroid Build Coastguard Worker groups->group[i].part[j], groups->group[i].priority);
203*8617a60dSAndroid Build Coastguard Worker
204*8617a60dSAndroid Build Coastguard Worker FreeGroups(groups);
205*8617a60dSAndroid Build Coastguard Worker }
206*8617a60dSAndroid Build Coastguard Worker
207*8617a60dSAndroid Build Coastguard Worker // Write it all out
208*8617a60dSAndroid Build Coastguard Worker UpdateAllEntries(&drive);
209*8617a60dSAndroid Build Coastguard Worker
210*8617a60dSAndroid Build Coastguard Worker return DriveClose(&drive, 1);
211*8617a60dSAndroid Build Coastguard Worker
212*8617a60dSAndroid Build Coastguard Worker bad:
213*8617a60dSAndroid Build Coastguard Worker (void) DriveClose(&drive, 0);
214*8617a60dSAndroid Build Coastguard Worker return CGPT_FAILED;
215*8617a60dSAndroid Build Coastguard Worker }
216