All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Add module for interacting with the android bootloader control block
@ 2016-01-31 23:01 Shea Levy
  2016-01-31 23:41 ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 6+ messages in thread
From: Shea Levy @ 2016-01-31 23:01 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Shea Levy

---
 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



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add module for interacting with the android bootloader control block
  2016-01-31 23:01 [PATCH] Add module for interacting with the android bootloader control block Shea Levy
@ 2016-01-31 23:41 ` Vladimir 'phcoder' Serbinenko
  2016-01-31 23:55   ` Shea Levy
  0 siblings, 1 reply; 6+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2016-01-31 23:41 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Shea Levy

[-- Attachment #1: Type: text/plain, Size: 7302 bytes --]

Sorry but I don't quite understand what this module is for. Can you please
give an example of how it's used both in original context and in GRUB. I
have couple of style comments as well but clarifying the usecase first is
important.

Le lun. 1 févr. 2016 00:01, Shea Levy <shea@shealevy.com> a écrit :

> ---
>  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
>

[-- Attachment #2: Type: text/html, Size: 8904 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add module for interacting with the android bootloader control block
  2016-01-31 23:41 ` Vladimir 'phcoder' Serbinenko
@ 2016-01-31 23:55   ` Shea Levy
  2016-02-01  4:18     ` Andrei Borzenkov
  0 siblings, 1 reply; 6+ messages in thread
From: Shea Levy @ 2016-01-31 23:55 UTC (permalink / raw)
  To: Vladimir 'phcoder' Serbinenko; +Cc: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 8867 bytes --]

 

Android systems use a so-called "bootloader control block" to
coordinate between the bootloader and the recovery system (which handles
factory resets, system updates, firmware updates, etc.). The BCB is
traditionally either an MTD device or an eMMC partition, and it contains
a struct bootloader_message directly on the device/partition. The
recovery system will write a message into the control block, which the
bootloader is then meant to check to see if it should boot into recovery
mode or normal mode (the idea being that the control block is only
cleared once recovery is finished, ensuring fault-tolerance; if the
device is powered off mid-update, it will boot back into the same
recovery mode). 

This module exports the bcb fields as env variables.
First the user sets android_bcb_disk to the partition containing the BCB
(I don't know how to support MTDs yet but I only deal with x86). Then
variables such as android_bcb_command and android_bcb_recovery can be
checked and used to determine which mode to boot into. They can also, if
necessary, be modified by setting the variables in question. The typical
use case will probably be to check if there is a recovery command
present and if so boot into recovery mode. 

Does that explain enough?


Thanks,
Shea 

On 2016-01-31 18:41, Vladimir 'phcoder' Serbinenko
wrote: 

> Sorry but I don't quite understand what this module is for.
Can you please give an example of how it's used both in original context
and in GRUB. I have couple of style comments as well but clarifying the
usecase first is important. 
> 
> Le lun. 1 févr. 2016 00:01, Shea Levy
<shea@shealevy.com> a écrit : 
> 
>> ---
>> 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/ [1]>.
>> + */
>> +
>> +#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
[2]
>> + * 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 [3]
>> + *
>> + * 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] =
''; 
>> + 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] = ''; 
>> +
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 [4]




Links:
------
[1] http://www.gnu.org/licenses/
[2]
https://android.googlesource.com/platform/bootable/recovery/+/9d72d4175b06a70c64c8867ff65b3c4c2181c9a9/bootloader.h#20
[3]
http://www.apache.org/licenses/LICENSE-2.0
[4]
https://lists.gnu.org/mailman/listinfo/grub-devel

[-- Attachment #2: Type: text/html, Size: 11474 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add module for interacting with the android bootloader control block
  2016-01-31 23:55   ` Shea Levy
@ 2016-02-01  4:18     ` Andrei Borzenkov
  2016-02-01 14:27       ` Shea Levy
  0 siblings, 1 reply; 6+ messages in thread
From: Andrei Borzenkov @ 2016-02-01  4:18 UTC (permalink / raw)
  To: The development of GNU GRUB,
	Vladimir 'phcoder' Serbinenko

01.02.2016 02:55, Shea Levy пишет:
>  
> 
> Android systems use a so-called "bootloader control block" to
> coordinate between the bootloader and the recovery system (which handles
> factory resets, system updates, firmware updates, etc.). The BCB is
> traditionally either an MTD device or an eMMC partition, and it contains
> a struct bootloader_message directly on the device/partition. The
> recovery system will write a message into the control block, which the
> bootloader is then meant to check to see if it should boot into recovery
> mode or normal mode (the idea being that the control block is only
> cleared once recovery is finished, ensuring fault-tolerance; if the
> device is powered off mid-update, it will boot back into the same
> recovery mode). 
> 
> This module exports the bcb fields as env variables.
> First the user sets android_bcb_disk to the partition containing the BCB
> (I don't know how to support MTDs yet but I only deal with x86). Then
> variables such as android_bcb_command and android_bcb_recovery can be
> checked and used to determine which mode to boot into. They can also, if
> necessary, be modified by setting the variables in question. The typical
> use case will probably be to check if there is a recovery command
> present and if so boot into recovery mode. 
> 
> Does that explain enough?
> 

How these variables are intended to be used? Could you provide example
of actual values in this block and example of grub code using them?

How BCB area is identified? Your code allows writing to arbitrary device
without any sanity check.

Is bootloader even *allowed* to make any choice here to remain
compliant? I.e. can bootloader ignore request stored in BCB?

> 
> Thanks,
> Shea 
> 
> On 2016-01-31 18:41, Vladimir 'phcoder' Serbinenko
> wrote: 
> 
>> Sorry but I don't quite understand what this module is for.
> Can you please give an example of how it's used both in original context
> and in GRUB. I have couple of style comments as well but clarifying the
> usecase first is important. 
>>
>> Le lun. 1 févr. 2016 00:01, Shea Levy
> <shea@shealevy.com> a écrit : 
>>
>>> ---
>>> 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/ [1]>.
>>> + */
>>> +
>>> +#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
> [2]
>>> + * 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 [3]
>>> + *
>>> + * 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] =
> ''; 
>>> + 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] = ''; 
>>> +
> 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 [4]
> 
> 
> 
> 
> Links:
> ------
> [1] http://www.gnu.org/licenses/
> [2]
> https://android.googlesource.com/platform/bootable/recovery/+/9d72d4175b06a70c64c8867ff65b3c4c2181c9a9/bootloader.h#20
> [3]
> http://www.apache.org/licenses/LICENSE-2.0
> [4]
> https://lists.gnu.org/mailman/listinfo/grub-devel
> 
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
> 



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add module for interacting with the android bootloader control block
  2016-02-01  4:18     ` Andrei Borzenkov
@ 2016-02-01 14:27       ` Shea Levy
  2016-02-01 14:59         ` shea
  0 siblings, 1 reply; 6+ messages in thread
From: Shea Levy @ 2016-02-01 14:27 UTC (permalink / raw)
  To: grub-devel

Hi Andrei,

There's no formal specification for any of this, all I have to go off 
of is the bits of the android codebase I've read, but I'll try to answer 
as best I can.

On 2016-01-31 23:18, Andrei Borzenkov wrote:
> 01.02.2016 02:55, Shea Levy пишет:
>>
>>
>> Android systems use a so-called "bootloader control block" to
>> coordinate between the bootloader and the recovery system (which 
>> handles
>> factory resets, system updates, firmware updates, etc.). The BCB is
>> traditionally either an MTD device or an eMMC partition, and it 
>> contains
>> a struct bootloader_message directly on the device/partition. The
>> recovery system will write a message into the control block, which 
>> the
>> bootloader is then meant to check to see if it should boot into 
>> recovery
>> mode or normal mode (the idea being that the control block is only
>> cleared once recovery is finished, ensuring fault-tolerance; if the
>> device is powered off mid-update, it will boot back into the same
>> recovery mode).
>>
>> This module exports the bcb fields as env variables.
>> First the user sets android_bcb_disk to the partition containing the 
>> BCB
>> (I don't know how to support MTDs yet but I only deal with x86). 
>> Then
>> variables such as android_bcb_command and android_bcb_recovery can 
>> be
>> checked and used to determine which mode to boot into. They can 
>> also, if
>> necessary, be modified by setting the variables in question. The 
>> typical
>> use case will probably be to check if there is a recovery command
>> present and if so boot into recovery mode.
>>
>> Does that explain enough?
>>
>
> How these variables are intended to be used? Could you provide 
> example
> of actual values in this block and example of grub code using them?
>

The recovery service that's started when booted into recovery mode 
reads values out of the BCB to determine its operation. For example, it 
checks that the first (newline-separated) string in the 'recovery' is 
field is "recovery", and then uses the rest to set its argv (e.g. a 
recovery field consisting of "recovery\n--wipe_data\0" would specify a 
factory reset). The app itself writes in "boot-recovery" into the 
"command" field and copies over its arguments, so that upon reboot the 
command will be started over again (until the command actually finishes, 
when it zeroes out the BCB).

>
> How BCB area is identified? Your code allows writing to arbitrary 
> device
> without any sanity check.
>

On the android userspace side there's only a recovery.fstab file, which 
just names a block device. The code simply reads a struct out of the 
block with no magic number or other kind of verification. Sometimes 
there's not even a real partition table, just a config file with an 
offset into a block.

>
> Is bootloader even *allowed* to make any choice here to remain
> compliant? I.e. can bootloader ignore request stored in BCB?
>

I have been unable to find any formal spec on the matter, but at least 
respecting the "boot-recovery" command would probably be a good idea for 
stock android. But this seems more like policy than mechanism, and IMO 
makes more sense to be determined at the grub.cfg level rather than the 
module level.

~Shea

>
>>
>> Thanks,
>> Shea
>>
>> On 2016-01-31 18:41, Vladimir 'phcoder' Serbinenko
>> wrote:
>>
>>> Sorry but I don't quite understand what this module is for.
>> Can you please give an example of how it's used both in original 
>> context
>> and in GRUB. I have couple of style comments as well but clarifying 
>> the
>> usecase first is important.
>>>
>>> Le lun. 1 févr. 2016 00:01, Shea Levy
>> <shea@shealevy.com> a écrit :
>>>
>>>> ---
>>>> 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/ [1]>.
>>>> + */
>>>> +
>>>> +#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
>> [2]
>>>> + * 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 [3]
>>>> + *
>>>> + * 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] =
>> '';
>>>> + 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] = '';
>>>> +
>> 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 [4]
>>
>>
>>
>>
>> Links:
>> ------
>> [1] http://www.gnu.org/licenses/
>> [2]
>> 
>> https://android.googlesource.com/platform/bootable/recovery/+/9d72d4175b06a70c64c8867ff65b3c4c2181c9a9/bootloader.h#20
>> [3]
>> http://www.apache.org/licenses/LICENSE-2.0
>> [4]
>> https://lists.gnu.org/mailman/listinfo/grub-devel
>>
>>
>>
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> https://lists.gnu.org/mailman/listinfo/grub-devel
>>
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add module for interacting with the android bootloader control block
  2016-02-01 14:27       ` Shea Levy
@ 2016-02-01 14:59         ` shea
  0 siblings, 0 replies; 6+ messages in thread
From: shea @ 2016-02-01 14:59 UTC (permalink / raw)
  To: Shea Levy, grub-devel

[-- Attachment #1: Type: text/plain, Size: 13047 bytes --]

Actually, upon review my current needs technically only require read
functionality (even though as I understand it the communication is
meant to be bidrectional), so if it would be easier to accept I can
resubmit a readonly version.

----- Original Message -----
From: "Shea Levy" <shea@shealevy.com>
To:<grub-devel@gnu.org>
Cc:
Sent:Mon, 01 Feb 2016 09:27:38 -0500
Subject:Re: [PATCH] Add module for interacting with the android
bootloader control block

 Hi Andrei,

 There's no formal specification for any of this, all I have to go off

 of is the bits of the android codebase I've read, but I'll try to
answer 
 as best I can.

 On 2016-01-31 23:18, Andrei Borzenkov wrote:
 > 01.02.2016 02:55, Shea Levy пишет:
 >>
 >>
 >> Android systems use a so-called "bootloader control block" to
 >> coordinate between the bootloader and the recovery system (which 
 >> handles
 >> factory resets, system updates, firmware updates, etc.). The BCB
is
 >> traditionally either an MTD device or an eMMC partition, and it 
 >> contains
 >> a struct bootloader_message directly on the device/partition. The
 >> recovery system will write a message into the control block, which

 >> the
 >> bootloader is then meant to check to see if it should boot into 
 >> recovery
 >> mode or normal mode (the idea being that the control block is only
 >> cleared once recovery is finished, ensuring fault-tolerance; if
the
 >> device is powered off mid-update, it will boot back into the same
 >> recovery mode).
 >>
 >> This module exports the bcb fields as env variables.
 >> First the user sets android_bcb_disk to the partition containing
the 
 >> BCB
 >> (I don't know how to support MTDs yet but I only deal with x86). 
 >> Then
 >> variables such as android_bcb_command and android_bcb_recovery can

 >> be
 >> checked and used to determine which mode to boot into. They can 
 >> also, if
 >> necessary, be modified by setting the variables in question. The 
 >> typical
 >> use case will probably be to check if there is a recovery command
 >> present and if so boot into recovery mode.
 >>
 >> Does that explain enough?
 >>
 >
 > How these variables are intended to be used? Could you provide 
 > example
 > of actual values in this block and example of grub code using them?
 >

 The recovery service that's started when booted into recovery mode 
 reads values out of the BCB to determine its operation. For example,
it 
 checks that the first (newline-separated) string in the 'recovery' is

 field is "recovery", and then uses the rest to set its argv (e.g. a 
 recovery field consisting of "recoveryn--wipe_data" would specify a 
 factory reset). The app itself writes in "boot-recovery" into the 
 "command" field and copies over its arguments, so that upon reboot
the 
 command will be started over again (until the command actually
finishes, 
 when it zeroes out the BCB).

 >
 > How BCB area is identified? Your code allows writing to arbitrary 
 > device
 > without any sanity check.
 >

 On the android userspace side there's only a recovery.fstab file,
which 
 just names a block device. The code simply reads a struct out of the 
 block with no magic number or other kind of verification. Sometimes 
 there's not even a real partition table, just a config file with an 
 offset into a block.

 >
 > Is bootloader even *allowed* to make any choice here to remain
 > compliant? I.e. can bootloader ignore request stored in BCB?
 >

 I have been unable to find any formal spec on the matter, but at
least 
 respecting the "boot-recovery" command would probably be a good idea
for 
 stock android. But this seems more like policy than mechanism, and
IMO 
 makes more sense to be determined at the grub.cfg level rather than
the 
 module level.

 ~Shea

 >
 >>
 >> Thanks,
 >> Shea
 >>
 >> On 2016-01-31 18:41, Vladimir 'phcoder' Serbinenko
 >> wrote:
 >>
 >>> Sorry but I don't quite understand what this module is for.
 >> Can you please give an example of how it's used both in original 
 >> context
 >> and in GRUB. I have couple of style comments as well but
clarifying 
 >> the
 >> usecase first is important.
 >>>
 >>> Le lun. 1 févr. 2016 00:01, Shea Levy
 >> <shea@shealevy.com> a écrit :
 >>>
 >>>> ---
 >>>> 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/ [1]>.
 >>>> + */
 >>>> +
 >>>> +#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
 >> [2]
 >>>> + * 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 [3]
 >>>> + *
 >>>> + * 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] =
 >> '';
 >>>> + 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] = '';
 >>>> +
 >> 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 [4]
 >>
 >>
 >>
 >>
 >> Links:
 >> ------
 >> [1] http://www.gnu.org/licenses/
 >> [2]
 >> 
 >>
https://android.googlesource.com/platform/bootable/recovery/+/9d72d4175b06a70c64c8867ff65b3c4c2181c9a9/bootloader.h#20
 >> [3]
 >> http://www.apache.org/licenses/LICENSE-2.0
 >> [4]
 >> https://lists.gnu.org/mailman/listinfo/grub-devel
 >>
 >>
 >>
 >> _______________________________________________
 >> Grub-devel mailing list
 >> Grub-devel@gnu.org
 >> https://lists.gnu.org/mailman/listinfo/grub-devel
 >>
 >
 >
 > _______________________________________________
 > Grub-devel mailing list
 > Grub-devel@gnu.org
 > https://lists.gnu.org/mailman/listinfo/grub-devel

 _______________________________________________
 Grub-devel mailing list
 Grub-devel@gnu.org
 https://lists.gnu.org/mailman/listinfo/grub-devel


[-- Attachment #2: Type: text/html, Size: 18344 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-02-01 14:59 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-31 23:01 [PATCH] Add module for interacting with the android bootloader control block Shea Levy
2016-01-31 23:41 ` Vladimir 'phcoder' Serbinenko
2016-01-31 23:55   ` Shea Levy
2016-02-01  4:18     ` Andrei Borzenkov
2016-02-01 14:27       ` Shea Levy
2016-02-01 14:59         ` shea

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.