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