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