xref: /aosp_15_r20/external/vboot_reference/cgpt/cgpt_prioritize.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
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