"Das U-Boot" Source Tree
at master 547 lines 18 kB view raw
1.. SPDX-License-Identifier: GPL-2.0+ 2 3Expo menu 4========= 5 6U-Boot provides a menu implementation for use with selecting bootflows and 7changing U-Boot settings. This is in early stages of development. 8 9Motivation 10---------- 11 12U-Boot already has a text-based menu system accessed via the 13:doc:`../usage/cmd/bootmenu`. This works using environment variables, or via 14some EFI-specific hacks. 15 16The command makes use of a lower-level `menu` implementation, which is quite 17flexible and can be used to make menu hierarchies. 18 19However this system is not flexible enough for use with standard boot. It does 20not support a graphical user interface and cannot currently support anything 21more than a very simple list of items. While it does support multiple menus in 22hierarchies, these are implemented by the caller. See for example `eficonfig.c`. 23 24Another challenge with the current menu implementation is that it controls 25the event loop, such that bootmenu_loop() does not return until a key is 26pressed. This makes it difficult to implement dynamic displays or to do other 27things while the menu is running, such as searching for more bootflows. 28 29For these reasons an attempt has been made to develop a more flexible system 30which can handle menus as well as other elements. This is called 'expo', short 31for exposition, in an attempt to avoid common words like display, screen, menu 32and the like. The primary goal is to support Verified Boot for Embedded (VBE), 33although it is available to any boot method, using the 'bootflow menu' command. 34 35Efforts have been made to use common code with the existing menu, including 36key processing in particular. 37 38Previous work looked at integrating Nuklear into U-Boot. This works fine and 39could provide a way to provide a more flexible UI, perhaps with expo dealing 40with the interface to Nuklear. But this is quite a big step and it may be years 41before this becomes desirable, if at all. For now, U-Boot only needs a fairly 42simple set of menus and options, so rendering them directly is fairly 43straightforward. 44 45Concepts 46-------- 47 48The creator of the expo is here called a `controller` and it controls most 49aspects of the expo. This is the code that you must write to use expo. 50 51An `expo` is a set of scenes which can be presented to the user one at a time, 52to show information and obtain input from the user. 53 54A `scene` is a collection of objects which are displayed together on the screen. 55Only one scene is visible at a time and scenes do not share objects. 56 57A `scene object` is something that appears in the scene, such as some text, an 58image or a menu. Objects can be positioned and hidden. 59 60A `menu object` contains a title, a set of `menu items` and a pointer to the 61current item. Menu items consist of a keypress (indicating what to press to 62select the item), label and description. All three are shown in a single line 63within the menu. Items can also have a preview image, which is shown when the 64item is highlighted. 65 66A `textline object` contains a label and an editable string. 67 68All components have a name. This is mostly for debugging, so it is easy to see 69what object is referred to, although the name is also used for saving values. 70Of course the ID numbers can help as well, but they are less easy to 71distinguish. 72 73While the expo implementation provides support for handling keypresses and 74rendering on the display or serial port, it does not actually deal with reading 75input from the user, nor what should be done when a particular menu item is 76selected. This is deliberate since having the event loop outside the expo is 77more flexible, particularly in a single-threaded environment like U-Boot. 78 79Everything within an expo has a unique ID number. This is done so that it is 80easy to refer to things after the expo has been created. The expectation is that 81the controller declares an enum containing all of the elements in the expo, 82passing the ID of each object as it is created. When a menu item is selected, 83its ID is returned. When a object's font or position needs to change, the ID is 84passed to expo functions to indicate which object it is. It is possible for expo 85to auto-allocate IDs, but this is not recommended. The use of IDs is a 86convenience, removing the need for the controller to store pointers to objects, 87or even the IDs of objects. Programmatic creation of many items in a loop can be 88handled by allocating space in the enum for a maximum number of items, then 89adding the loop count to the enum values to obtain unique IDs. 90 91Some standard IDs are reserved for certain purposes. These are defined by 92`enum expo_id_t` and start at 1. `EXPOID_BASE_ID` defines the first ID which 93can be used for an expo. 94 95An ID of 0 is invalid. If this is specified in an expo call then a valid 96'dynamic IDs is allocated. Use expo_set_dynamic_start() to set the start 97value, so that they are allocated above the starting (enum) IDs. 98 99All text strings are stored in a structure attached to the expo, referenced by 100a text ID. This makes it easier at some point to implement multiple languages or 101to support Unicode strings. 102 103Menu objects do not have their own text and image objects. Instead they simply 104refer to objects which have been created. So a menu item is just a collection 105of IDs of text and image objects. When adding a menu item you must create these 106objects first, then create the menu item, passing in the relevant IDs. 107 108Creating an expo 109---------------- 110 111To create an expo programmatically, use `expo_new()` followed by `scene_new()` 112to create a scene. Then add objects to the scene, using functions like 113`scene_txt_str()` and `scene_menu()`. For every menu item, add text and image 114objects, then create the menu item with `scene_menuitem()`, referring to those 115objects. 116 117To create an expo using a description file, see :ref:`expo_format` below. 118 119Layout 120------ 121 122Individual objects can be positioned using `scene_obj_set_pos()`. Menu items 123cannot be positioned manually: this is done by `scene_arrange()` which is called 124automatically when something changes. The menu itself determines the position of 125its items. 126 127Rendering 128--------- 129 130Rendering is performed by calling `expo_render()`. This uses either the 131vidconsole, if present, or the serial console in `text mode`. Expo handles 132presentation automatically in either case, without any change in how the expo is 133created. 134 135For the vidconsole, Truetype fonts can be used if enabled, to enhance the 136quality of the display. For text mode, each menu item is shown in a single line, 137allowing easy selection using arrow keys. 138 139Input 140----- 141 142The controller is responsible for collecting keyboard input. A good way to do 143this is to use `cli_ch_process()`, since it handles conversion of escape 144sequences into keys. However, expo has some special menu-key codes for 145navigating the interface. These are defined in `enum bootmenu_key` and include 146`BKEY_UP` for moving up and `BKEY_SELECT` for selecting an item. You can use 147`bootmenu_conv_key()` to convert an ASCII key into one of these, but if it 148returns a value >= `BKEY_FIRST_EXTRA` then you should pass the unmodified ASCII 149key to the expo, since it may be used by textline objects. 150 151Once a keypress is decoded, call `expo_send_key()` to send it to the expo. This 152may cause an update to the expo state and may produce an action. 153 154Actions 155------- 156 157Call `expo_action_get()` in the event loop to check for any actions that the 158expo wants to report. These can include selecting a particular menu item, or 159quitting the menu. Processing of these is the responsibility of your controller. 160 161Event loop 162---------- 163 164Expo is intended to be used in an event loop. For an example loop, see 165`bootflow_menu_run()`. It is possible to perform other work in your event loop, 166such as scanning devices for more bootflows. 167 168Themes 169------ 170 171Expo supports simple themes, for setting the font size, for example. Use the 172expo_apply_theme() function to load a theme, passing a node with the required 173properties: 174 175font-size 176 Font size to use for all text (type: u32) 177 178menu-inset 179 Number of pixels to inset the menu on the sides and top (type: u32) 180 181menuitem-gap-y 182 Number of pixels between menu items 183 184menu-title-margin-x 185 Number of pixels between right side of menu title to the left size of the 186 menu labels 187 188Pop-up mode 189----------- 190 191Expos support two modes. The simple mode is used for selecting from a single 192menu, e.g. when choosing with OS to boot. In this mode the menu items are shown 193in a list (label, > pointer, key and description) and can be chosen using arrow 194keys and enter:: 195 196 U-Boot Boot Menu 197 198 UP and DOWN to choose, ENTER to select 199 200 mmc1 > 0 Fedora-Workstation-armhfp-31-1.9 201 mmc3 1 Armbian 202 203The popup mode allows multiple menus to be present in a scene. Each is shown 204just as its title and label, as with the `CPU Speed` and `AC Power` menus here:: 205 206 Test Configuration 207 208 209 CPU Speed <2 GHz> (highlighted) 210 211 AC Power Always Off 212 213 214 UP and DOWN to choose, ENTER to select 215 216 217.. _expo_format: 218 219Expo Format 220----------- 221 222It can be tedious to create a complex expo using code. Expo supports a 223data-driven approach, where the expo description is in a devicetree file. This 224makes it easier and faster to create and edit the description. An expo builder 225is provided to convert this format into an expo structure. 226 227Layout of the expo scenes is handled automatically, based on a set of simple 228rules. The :doc:`../usage/cmd/cedit` can be used to load a configuration 229and create an expo from it. 230 231Top-level node 232~~~~~~~~~~~~~~ 233 234The top-level node has the following properties: 235 236dynamic-start 237 type: u32, optional 238 239 Specifies the start of the dynamically allocated objects. This results in 240 a call to expo_set_dynamic_start(). 241 242The top-level node has the following subnodes: 243 244scenes 245 Specifies the scenes in the expo, each one being a subnode 246 247strings 248 Specifies the strings in the expo, each one being a subnode 249 250`scenes` node 251~~~~~~~~~~~~~ 252 253Contains a list of scene subnodes. The name of each subnode is passed as the 254name to `scene_new()`. 255 256`strings` node 257~~~~~~~~~~~~~~ 258 259Contains a list of string subnodes. The name of each subnode is ignored. 260 261`strings` subnodes 262~~~~~~~~~~~~~~~~~~ 263 264Each subnode defines a string which can be used by scenes and objects. Each 265string has an ID number which is used to refer to it. 266 267The `strings` subnodes have the following properties: 268 269id 270 type: u32, required 271 272 Specifies the ID number for the string. 273 274value: 275 type: string, required 276 277 Specifies the string text. For now only a single value is supported. Future 278 work may add support for multiple languages by using a value for each 279 language. 280 281Scene nodes (`scenes` subnodes) 282~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 283 284Each subnode of the `scenes` node contains a scene description. 285 286Most properties can use either a string or a string ID. For example, a `title` 287property can be used to provide the title for a menu; alternatively a `title-id` 288property can provide the string ID of the title. If both are present, the 289ID takes preference, except that if a string with that ID does not exist, it 290falls back to using the string from the property (`title` in this example). The 291description below shows these are alternative properties with the same 292description. 293 294The scene nodes have the following properties: 295 296id 297 type: u32, required 298 299 Specifies the ID number for the string. 300 301title / title-id 302 type: string / u32, required 303 304 Specifies the title of the scene. This is shown at the top of the scene. 305 306prompt / prompt-id 307 type: string / u32, required 308 309 Specifies a prompt for the scene. This is shown at the bottom of the scene. 310 311The scene nodes have a subnode for each object in the scene. 312 313Object nodes 314~~~~~~~~~~~~ 315 316The object-node name is used as the name of the object, e.g. when calling 317`scene_menu()` to create a menu. 318 319Object nodes have the following common properties: 320 321type 322 type: string, required 323 324 Specifies the type of the object. Valid types are: 325 326 "menu" 327 Menu containing items which can be selected by the user 328 329 "textline" 330 A line of text which can be edited 331 332id 333 type: u32, required 334 335 Specifies the ID of the object. This is used when referring to the object. 336 337Where CMOS RAM is used for reading and writing settings, the following 338additional properties are required: 339 340start-bit 341 Specifies the first bit in the CMOS RAM to use for this setting. For a RAM 342 with 0x100 bytes, there are 0x800 bit locations. For example, register 0x80 343 holds bits 0x400 to 0x407. 344 345bit-length 346 Specifies the number of CMOS RAM bits to use for this setting. The bits 347 extend from `start-bit` to `start-bit + bit-length - 1`. Note that the bits 348 must be contiguous. 349 350Menu nodes have the following additional properties: 351 352title / title-id 353 type: string / u32, required 354 355 Specifies the title of the menu. This is shown to the left of the area for 356 this menu. 357 358item-id 359 type: u32 list, required 360 361 Specifies the ID for each menu item. These are used for checking which item 362 has been selected. 363 364item-value 365 type: u32 list, optional 366 367 Specifies the value for each menu item. These are used for saving and 368 loading. If this is omitted the value is its position in the menu (0..n-1). 369 Valid values are positive and negative integers INT_MIN...(INT_MAX - 1). 370 371item-label / item-label-id 372 type: string list / u32 list, required 373 374 Specifies the label for each item in the menu. These are shown to the user. 375 In 'popup' mode these form the items in the menu. 376 377key-label / key-label-id 378 type: string list / u32 list, optional 379 380 Specifies the key for each item in the menu. These are currently only 381 intended for use in simple mode. 382 383desc-label / desc-label-id 384 type: string list / u32 list, optional 385 386 Specifies the description for each item in the menu. These are currently 387 only intended for use in simple mode. 388 389Textline nodes have the following additional properties: 390 391label / label-id 392 type: string / u32, required 393 394 Specifies the label of the textline. This is shown to the left of the area 395 for this textline. 396 397edit-id 398 type: u32, required 399 400 Specifies the ID of the of the editable text object. This can be used to 401 obtain the text from the textline 402 403max-chars: 404 type: u32, required 405 406 Specifies the maximum number of characters permitted to be in the textline. 407 The user will be prevented from adding more. 408 409 410Expo layout 411~~~~~~~~~~~ 412 413The `expo_arrange()` function can be called to arrange the expo objects in a 414suitable manner. For each scene it puts the title at the top, the prompt at the 415bottom and the objects in order from top to bottom. 416 417 418.. _expo_example: 419 420Expo format example 421~~~~~~~~~~~~~~~~~~~ 422 423This example shows an expo with a single scene consisting of two menus. The 424scene title is specified using a string from the strings table, but all other 425strings are provided inline in the nodes where they are used. 426 427:: 428 429 /* this comment is parsed by the expo.py tool to insert the values below 430 431 enum { 432 ID_PROMPT = EXPOID_BASE_ID, 433 ID_SCENE1, 434 ID_SCENE1_TITLE, 435 436 ID_CPU_SPEED, 437 ID_CPU_SPEED_TITLE, 438 ID_CPU_SPEED_1, 439 ID_CPU_SPEED_2, 440 ID_CPU_SPEED_3, 441 442 ID_POWER_LOSS, 443 ID_AC_OFF, 444 ID_AC_ON, 445 ID_AC_MEMORY, 446 447 ID_MACHINE_NAME, 448 ID_MACHINE_NAME_EDIT, 449 450 ID_DYNAMIC_START, 451 */ 452 453 &cedit { 454 dynamic-start = <ID_DYNAMIC_START>; 455 456 scenes { 457 main { 458 id = <ID_SCENE1>; 459 460 /* value refers to the matching id in /strings */ 461 title-id = <ID_SCENE1_TITLE>; 462 463 /* simple string is used as it is */ 464 prompt = "UP and DOWN to choose, ENTER to select"; 465 466 /* defines a menu within the scene */ 467 cpu-speed { 468 type = "menu"; 469 id = <ID_CPU_SPEED>; 470 471 /* 472 * has both string and ID. The string is ignored 473 * if the ID is present and points to a string 474 */ 475 title = "CPU speed"; 476 title-id = <ID_CPU_SPEED_TITLE>; 477 478 /* menu items as simple strings */ 479 item-label = "2 GHz", "2.5 GHz", "3 GHz"; 480 481 /* IDs for the menu items */ 482 item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2 483 ID_CPU_SPEED_3>; 484 485 /* values for the menu items */ 486 item-value = <(-1) 3 6>; 487 }; 488 489 power-loss { 490 type = "menu"; 491 id = <ID_POWER_LOSS>; 492 493 title = "AC Power"; 494 item-label = "Always Off", "Always On", 495 "Memory"; 496 497 item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>; 498 }; 499 500 machine-name { 501 id = <ID_MACHINE_NAME>; 502 type = "textline"; 503 max-chars = <20>; 504 title = "Machine name"; 505 edit-id = <ID_MACHINE_NAME_EDIT>; 506 }; 507 }; 508 509 strings { 510 title { 511 id = <ID_SCENE1_TITLE>; 512 value = "Test Configuration"; 513 value-es = "configuración de prueba"; 514 }; 515 }; 516 }; 517 518 519API documentation 520----------------- 521 522.. kernel-doc:: include/expo.h 523 524Future ideas 525------------ 526 527Some ideas for future work: 528 529- Default menu item and a timeout 530- Image formats other than BMP 531- Use of ANSI sequences to control a serial terminal 532- Colour selection 533- Support for more widgets, e.g. numeric, radio/option 534- Mouse support 535- Integrate Nuklear, NxWidgets or some other library for a richer UI 536- Optimise rendering by only updating the display with changes since last render 537- Use expo to replace the existing menu implementation 538- Add a Kconfig option to drop the names to save code / data space 539- Add a Kconfig option to disable vidconsole support to save code / data space 540- Support both graphical and text menus at the same time on different devices 541- Support unicode 542- Support curses for proper serial-terminal menus 543- Add support for large menus which need to scroll 544- Update expo.py tool to check for overlapping names and CMOS locations 545 546.. Simon Glass <sjg@chromium.org> 547.. 7-Oct-22