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