--- grub-core/Makefile.core.def | 5 ++ grub-core/android/android_bcb.c | 163 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 grub-core/android/android_bcb.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 0cc40bb..b045ea4 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2327,3 +2327,8 @@ module = { common = loader/i386/xen_file64.c; extra_dist = loader/i386/xen_fileXX.c; }; + +module = { + name = android_bcb; + common = android/android_bcb.c; +}; diff --git a/grub-core/android/android_bcb.c b/grub-core/android/android_bcb.c new file mode 100644 index 0000000..db49446 --- /dev/null +++ b/grub-core/android/android_bcb.c @@ -0,0 +1,163 @@ +/* android_bcb.c - module for interacting with the android bootloader control block */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2016 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stddef.h> + +#include <grub/dl.h> +#include <grub/env.h> +#include <grub/disk.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* Definition of struct bootloader message from https://android.googlesource.com/platform/bootable/recovery/+/9d72d4175b06a70c64c8867ff65b3c4c2181c9a9/bootloader.h#20 + * Available under the following copyright and terms: + * + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +struct bootloader_message +{ + char command[32]; + char status[32]; + char recovery[768]; + // The 'recovery' field used to be 1024 bytes. It has only ever + // been used to store the recovery command line, so 768 bytes + // should be plenty. We carve off the last 256 bytes to store the + // stage string (for multistage packages) and possible future + // expansion. + char stage[32]; + char slot_suffix[32]; + char reserved[192]; +} GRUB_PACKED; + +struct bcb_state +{ + grub_disk_t disk; + char internal_write; + struct bootloader_message msg; +}; + +static struct bcb_state state = { 0 }; + +#define SET_FIELD(field) \ + state.msg. field[sizeof state.msg. field - 1] = '\0'; \ + grub_env_set ("android_bcb_" #field, state.msg. field) + +static void open_disk (const char *name) { + if (state.disk) { + grub_disk_close (state.disk); + } + + state.disk = grub_disk_open (name); + if (state.disk) { + grub_err_t err = grub_disk_read (state.disk, 0, 0, sizeof state.msg, + &state.msg); + if (err) { + grub_disk_close (state.disk); + state.disk = 0; + } else { + state.internal_write = 1; + SET_FIELD (command); + SET_FIELD (status); + SET_FIELD (recovery); + SET_FIELD (stage); + SET_FIELD (slot_suffix); + state.internal_write = 0; + } + } +} + +#define MAYBE_UPDATE_FIELD(field) \ + do { if (!grub_strcmp (var->name, "android_bcb_" #field)) \ + { \ + grub_memcpy (state.msg. field, val, sizeof state.msg. field - 1); \ + state.msg. field[sizeof state.msg. field - 1] = '\0'; \ + grub_disk_write (state.disk, 0, \ + offsetof (struct bootloader_message, field), \ + sizeof state.msg. field, state.msg. field); \ + } } while (0) + +static char *handle_write (struct grub_env_var *var, + const char *val) +{ + if (!grub_strcmp (var->name, "android_bcb_disk")) + { + open_disk (val); + if (!state.disk) + grub_print_error (); + } + else if (state.disk && !state.internal_write) + { + MAYBE_UPDATE_FIELD (command); + MAYBE_UPDATE_FIELD (status); + MAYBE_UPDATE_FIELD (recovery); + MAYBE_UPDATE_FIELD (stage); + MAYBE_UPDATE_FIELD (slot_suffix); + } + + return grub_strdup (val); +} + +GRUB_MOD_INIT(android_bcb) +{ + const char *disk = grub_env_get ("android_bcb_disk"); + if (disk) + { + open_disk (disk); + if (!state.disk) + grub_print_error (); + } + + if (!grub_register_variable_hook ("android_bcb_disk", 0, handle_write)) + grub_print_error (); + if (grub_register_variable_hook ("android_bcb_command", 0, handle_write)) + grub_print_error (); + if (grub_register_variable_hook ("android_bcb_status", 0, handle_write)) + grub_print_error (); + if (grub_register_variable_hook ("android_bcb_recovery", 0, handle_write)) + grub_print_error (); + if (grub_register_variable_hook ("android_bcb_stage", 0, handle_write)) + grub_print_error (); + if (grub_register_variable_hook ("android_bcb_slot_suffix", 0, handle_write)) + grub_print_error (); +} + +GRUB_MOD_FINI(android_bcb) +{ + grub_register_variable_hook ("android_bcb_disk", 0, 0); + grub_register_variable_hook ("android_bcb_command", 0, 0); + grub_register_variable_hook ("android_bcb_status", 0, 0); + grub_register_variable_hook ("android_bcb_recovery", 0, 0); + grub_register_variable_hook ("android_bcb_stage", 0, 0); + grub_register_variable_hook ("android_bcb_slot_suffix", 0, 0); + + if (state.disk) + grub_disk_close (state.disk); +} -- 2.7.0 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel