aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/common
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/common
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/common')
-rw-r--r--roms/u-boot/common/Kconfig762
-rw-r--r--roms/u-boot/common/Kconfig.boot970
-rw-r--r--roms/u-boot/common/Makefile143
-rw-r--r--roms/u-boot/common/android_ab.c305
-rw-r--r--roms/u-boot/common/autoboot.c397
-rw-r--r--roms/u-boot/common/avb_verify.c1023
-rw-r--r--roms/u-boot/common/bedbug.c1254
-rw-r--r--roms/u-boot/common/bloblist.c361
-rw-r--r--roms/u-boot/common/board_f.c1016
-rw-r--r--roms/u-boot/common/board_info.c52
-rw-r--r--roms/u-boot/common/board_r.c837
-rw-r--r--roms/u-boot/common/boot_fit.c80
-rw-r--r--roms/u-boot/common/bootm.c1038
-rw-r--r--roms/u-boot/common/bootm_os.c646
-rw-r--r--roms/u-boot/common/bootretry.c60
-rw-r--r--roms/u-boot/common/bootstage.c542
-rw-r--r--roms/u-boot/common/bouncebuf.c95
-rw-r--r--roms/u-boot/common/cli.c249
-rw-r--r--roms/u-boot/common/cli_hush.c3705
-rw-r--r--roms/u-boot/common/cli_readline.c659
-rw-r--r--roms/u-boot/common/cli_simple.c348
-rw-r--r--roms/u-boot/common/command.c656
-rw-r--r--roms/u-boot/common/common_fit.c86
-rw-r--r--roms/u-boot/common/console.c1097
-rw-r--r--roms/u-boot/common/cros_ec.c28
-rw-r--r--roms/u-boot/common/ddr_spd.c158
-rw-r--r--roms/u-boot/common/dfu.c117
-rw-r--r--roms/u-boot/common/dlmalloc.c2549
-rw-r--r--roms/u-boot/common/dlmalloc.src3265
-rw-r--r--roms/u-boot/common/edid.c507
-rw-r--r--roms/u-boot/common/eeprom/eeprom_field.c249
-rw-r--r--roms/u-boot/common/eeprom/eeprom_layout.c124
-rw-r--r--roms/u-boot/common/exports.c35
-rw-r--r--roms/u-boot/common/fdt_region.c671
-rw-r--r--roms/u-boot/common/fdt_support.c1952
-rw-r--r--roms/u-boot/common/flash.c220
-rw-r--r--roms/u-boot/common/hash.c639
-rw-r--r--roms/u-boot/common/hwconfig.c287
-rw-r--r--roms/u-boot/common/image-android-dt.c157
-rw-r--r--roms/u-boot/common/image-android.c539
-rw-r--r--roms/u-boot/common/image-cipher.c176
-rw-r--r--roms/u-boot/common/image-fdt.c634
-rw-r--r--roms/u-boot/common/image-fit-sig.c483
-rw-r--r--roms/u-boot/common/image-fit.c2407
-rw-r--r--roms/u-boot/common/image-sig.c187
-rw-r--r--roms/u-boot/common/image.c1753
-rw-r--r--roms/u-boot/common/init/Makefile8
-rw-r--r--roms/u-boot/common/init/board_init.c172
-rw-r--r--roms/u-boot/common/init/handoff.c41
-rw-r--r--roms/u-boot/common/iomux.c179
-rw-r--r--roms/u-boot/common/iotrace.c184
-rw-r--r--roms/u-boot/common/kallsyms.c44
-rw-r--r--roms/u-boot/common/kgdb.c599
-rw-r--r--roms/u-boot/common/kgdb_stubs.c67
-rw-r--r--roms/u-boot/common/lcd.c772
-rw-r--r--roms/u-boot/common/lcd_console.c261
-rw-r--r--roms/u-boot/common/lcd_console_rotation.c194
-rw-r--r--roms/u-boot/common/lcd_simplefb.c91
-rw-r--r--roms/u-boot/common/log.c432
-rw-r--r--roms/u-boot/common/log_console.c53
-rw-r--r--roms/u-boot/common/log_syslog.c113
-rw-r--r--roms/u-boot/common/lynxkdi.c23
-rw-r--r--roms/u-boot/common/main.c68
-rw-r--r--roms/u-boot/common/malloc_simple.c83
-rw-r--r--roms/u-boot/common/memsize.c104
-rw-r--r--roms/u-boot/common/menu.c420
-rw-r--r--roms/u-boot/common/miiphyutil.c561
-rw-r--r--roms/u-boot/common/qfw.c104
-rw-r--r--roms/u-boot/common/s_record.c178
-rw-r--r--roms/u-boot/common/scp03.c53
-rw-r--r--roms/u-boot/common/spl/Kconfig1639
-rw-r--r--roms/u-boot/common/spl/Makefile35
-rw-r--r--roms/u-boot/common/spl/spl.c895
-rw-r--r--roms/u-boot/common/spl/spl_atf.c297
-rw-r--r--roms/u-boot/common/spl/spl_bootrom.c27
-rw-r--r--roms/u-boot/common/spl/spl_dfu.c56
-rw-r--r--roms/u-boot/common/spl/spl_ext.c146
-rw-r--r--roms/u-boot/common/spl/spl_fat.c172
-rw-r--r--roms/u-boot/common/spl/spl_fit.c810
-rw-r--r--roms/u-boot/common/spl/spl_legacy.c133
-rw-r--r--roms/u-boot/common/spl/spl_mmc.c448
-rw-r--r--roms/u-boot/common/spl/spl_nand.c189
-rw-r--r--roms/u-boot/common/spl/spl_net.c97
-rw-r--r--roms/u-boot/common/spl/spl_nor.c122
-rw-r--r--roms/u-boot/common/spl/spl_onenand.c40
-rw-r--r--roms/u-boot/common/spl/spl_opensbi.c99
-rw-r--r--roms/u-boot/common/spl/spl_optee.S12
-rw-r--r--roms/u-boot/common/spl/spl_ram.c85
-rw-r--r--roms/u-boot/common/spl/spl_sata.c105
-rw-r--r--roms/u-boot/common/spl/spl_sdp.c48
-rw-r--r--roms/u-boot/common/spl/spl_spi.c171
-rw-r--r--roms/u-boot/common/spl/spl_ubi.c88
-rw-r--r--roms/u-boot/common/spl/spl_usb.c73
-rw-r--r--roms/u-boot/common/spl/spl_xip.c30
-rw-r--r--roms/u-boot/common/spl/spl_ymodem.c181
-rw-r--r--roms/u-boot/common/splash.c184
-rw-r--r--roms/u-boot/common/splash_source.c436
-rw-r--r--roms/u-boot/common/stackprot.c20
-rw-r--r--roms/u-boot/common/stdio.c401
-rw-r--r--roms/u-boot/common/system_map.c8
-rw-r--r--roms/u-boot/common/update.c410
-rw-r--r--roms/u-boot/common/usb.c1293
-rw-r--r--roms/u-boot/common/usb_hub.c977
-rw-r--r--roms/u-boot/common/usb_kbd.c717
-rw-r--r--roms/u-boot/common/usb_storage.c1570
-rw-r--r--roms/u-boot/common/xyzModem.c711
106 files changed, 51047 insertions, 0 deletions
diff --git a/roms/u-boot/common/Kconfig b/roms/u-boot/common/Kconfig
new file mode 100644
index 000000000..26496f9a2
--- /dev/null
+++ b/roms/u-boot/common/Kconfig
@@ -0,0 +1,762 @@
+source "common/Kconfig.boot"
+
+menu "Console"
+
+config MENU
+ bool
+ help
+ This is the library functionality to provide a text-based menu of
+ choices for the user to make choices with.
+
+config CONSOLE_RECORD
+ bool "Console recording"
+ help
+ This provides a way to record console output (and provide console
+ input) through circular buffers. This is mostly useful for testing.
+ Console output is recorded even when the console is silent.
+ To enable console recording, call console_record_reset_enable()
+ from your code.
+
+config CONSOLE_RECORD_INIT_F
+ bool "Enable console recording during pre-relocation init"
+ depends on CONSOLE_RECORD && SYS_MALLOC_F
+ default y
+ help
+ This option enables console recording during pre-relocation init.
+ CONFIG_SYS_MALLOC_F must be enabled to use this feature.
+
+config CONSOLE_RECORD_OUT_SIZE
+ hex "Output buffer size"
+ depends on CONSOLE_RECORD
+ default 0x400 if CONSOLE_RECORD
+ help
+ Set the size of the console output buffer. When this fills up, no
+ more data will be recorded until some is removed. The buffer is
+ allocated immediately after the malloc() region is ready.
+
+config CONSOLE_RECORD_IN_SIZE
+ hex "Input buffer size"
+ depends on CONSOLE_RECORD
+ default 0x100 if CONSOLE_RECORD
+ help
+ Set the size of the console input buffer. When this contains data,
+ tstc() and getc() will use this in preference to real device input.
+ The buffer is allocated immediately after the malloc() region is
+ ready.
+
+config DISABLE_CONSOLE
+ bool "Add functionality to disable console completely"
+ help
+ Disable console (in & out).
+
+config IDENT_STRING
+ string "Board specific string to be added to uboot version string"
+ help
+ This options adds the board specific name to u-boot version.
+
+config LOGLEVEL
+ int "loglevel"
+ default 4
+ range 0 10
+ help
+ All Messages with a loglevel smaller than the console loglevel will
+ be compiled in. The loglevels are defined as follows:
+
+ 0 - emergency
+ 1 - alert
+ 2 - critical
+ 3 - error
+ 4 - warning
+ 5 - note
+ 6 - info
+ 7 - debug
+ 8 - debug content
+ 9 - debug hardware I/O
+
+config SPL_LOGLEVEL
+ int
+ default LOGLEVEL
+
+config TPL_LOGLEVEL
+ int
+ default LOGLEVEL
+
+config SILENT_CONSOLE
+ bool "Support a silent console"
+ help
+ This option allows the console to be silenced, meaning that no
+ output will appear on the console devices. This is controlled by
+ setting the environment variable 'silent' to a non-empty value.
+ Note this also silences the console when booting Linux.
+
+ When the console is set up, the variable is checked, and the
+ GD_FLG_SILENT flag is set. Changing the environment variable later
+ will update the flag.
+
+config SILENT_U_BOOT_ONLY
+ bool "Only silence the U-Boot console"
+ depends on SILENT_CONSOLE
+ help
+ Normally when the U-Boot console is silenced, Linux's console is
+ also silenced (assuming the board boots into Linux). This option
+ allows the linux console to operate normally, even if U-Boot's
+ is silenced.
+
+config SILENT_CONSOLE_UPDATE_ON_SET
+ bool "Changes to the 'silent' environment variable update immediately"
+ depends on SILENT_CONSOLE
+ default y if SILENT_CONSOLE
+ help
+ When the 'silent' environment variable is changed, update the
+ console silence flag immediately. This allows 'setenv' to be used
+ to silence or un-silence the console.
+
+ The effect is that any change to the variable will affect the
+ GD_FLG_SILENT flag.
+
+config SILENT_CONSOLE_UPDATE_ON_RELOC
+ bool "Allow flags to take effect on relocation"
+ depends on SILENT_CONSOLE
+ help
+ In some cases the environment is not available until relocation
+ (e.g. NAND). This option makes the value of the 'silent'
+ environment variable take effect at relocation.
+
+config PRE_CONSOLE_BUFFER
+ bool "Buffer characters before the console is available"
+ help
+ Prior to the console being initialised (i.e. serial UART
+ initialised etc) all console output is silently discarded.
+ Defining CONFIG_PRE_CONSOLE_BUFFER will cause U-Boot to
+ buffer any console messages prior to the console being
+ initialised to a buffer. The buffer is a circular buffer, so
+ if it overflows, earlier output is discarded.
+
+ Note that this is not currently supported in SPL. It would be
+ useful to be able to share the pre-console buffer with SPL.
+
+config PRE_CON_BUF_SZ
+ int "Sets the size of the pre-console buffer"
+ depends on PRE_CONSOLE_BUFFER
+ default 4096
+ help
+ The size of the pre-console buffer affects how much console output
+ can be held before it overflows and starts discarding earlier
+ output. Normally there is very little output at this early stage,
+ unless debugging is enabled, so allow enough for ~10 lines of
+ text.
+
+ This is a useful feature if you are using a video console and
+ want to see the full boot output on the console. Without this
+ option only the post-relocation output will be displayed.
+
+config PRE_CON_BUF_ADDR
+ hex "Address of the pre-console buffer"
+ depends on PRE_CONSOLE_BUFFER
+ default 0x2f000000 if ARCH_SUNXI && MACH_SUN9I
+ default 0x4f000000 if ARCH_SUNXI && !MACH_SUN9I
+ default 0x0f000000 if ROCKCHIP_RK3288
+ default 0x0f200000 if ROCKCHIP_RK3399
+ help
+ This sets the start address of the pre-console buffer. This must
+ be in available memory and is accessed before relocation and
+ possibly before DRAM is set up. Therefore choose an address
+ carefully.
+
+ We should consider removing this option and allocating the memory
+ in board_init_f_init_reserve() instead.
+
+config CONSOLE_MUX
+ bool "Enable console multiplexing"
+ default y if DM_VIDEO || VIDEO || LCD
+ help
+ This allows multiple devices to be used for each console 'file'.
+ For example, stdout can be set to go to serial and video.
+ Similarly, stdin can be set to come from serial and keyboard.
+ Input can be provided from either source. Console multiplexing
+ adds a small amount of size to U-Boot. Changes to the environment
+ variables stdout, stdin and stderr will take effect immediately.
+
+config SYS_CONSOLE_IS_IN_ENV
+ bool "Select console devices from the environment"
+ default y if CONSOLE_MUX
+ help
+ This allows multiple input/output devices to be set at boot time.
+ For example, if stdout is set to "serial,video" then output will
+ be sent to both the serial and video devices on boot. The
+ environment variables can be updated after boot to change the
+ input/output devices.
+
+config SYS_CONSOLE_OVERWRITE_ROUTINE
+ bool "Allow board control over console overwriting"
+ help
+ If this is enabled, and the board-specific function
+ overwrite_console() returns 1, the stdin, stderr and stdout are
+ switched to the serial port, else the settings in the environment
+ are used. If this is not enabled, the console will not be switched
+ to serial.
+
+config SYS_CONSOLE_ENV_OVERWRITE
+ bool "Update environment variables during console init"
+ help
+ The console environment variables (stdout, stdin, stderr) can be
+ used to determine the correct console devices on start-up. This
+ option writes the console devices to these variables on console
+ start-up (after relocation). This causes the environment to be
+ updated to match the console devices actually chosen.
+
+config SYS_CONSOLE_INFO_QUIET
+ bool "Don't display the console devices on boot"
+ help
+ Normally U-Boot displays the current settings for stdout, stdin
+ and stderr on boot when the post-relocation console is set up.
+ Enable this option to suppress this output. It can be obtained by
+ calling stdio_print_current_devices() from board code.
+
+config SYS_STDIO_DEREGISTER
+ bool "Allow deregistering stdio devices"
+ default y if USB_KEYBOARD
+ help
+ Generally there is no need to deregister stdio devices since they
+ are never deactivated. But if a stdio device is used which can be
+ removed (for example a USB keyboard) then this option can be
+ enabled to ensure this is handled correctly.
+
+config SPL_SYS_STDIO_DEREGISTER
+ bool "Allow deregistering stdio devices in SPL"
+ help
+ Generally there is no need to deregister stdio devices since they
+ are never deactivated. But if a stdio device is used which can be
+ removed (for example a USB keyboard) then this option can be
+ enabled to ensure this is handled correctly. This is very rarely
+ needed in SPL.
+
+config SYS_DEVICE_NULLDEV
+ bool "Enable a null device for stdio"
+ default y if SPLASH_SCREEN || SYS_STDIO_DEREGISTER
+ help
+ Enable creation of a "nulldev" stdio device. This allows silent
+ operation of the console by setting stdout to "nulldev". Enable
+ this to use a serial console under board control.
+
+endmenu
+
+menu "Logging"
+
+config LOG
+ bool "Enable logging support"
+ depends on DM
+ help
+ This enables support for logging of status and debug messages. These
+ can be displayed on the console, recorded in a memory buffer, or
+ discarded if not needed. Logging supports various categories and
+ levels of severity.
+
+if LOG
+
+config LOG_MAX_LEVEL
+ int "Maximum log level to record"
+ default 6
+ range 0 9
+ help
+ This selects the maximum log level that will be recorded. Any value
+ higher than this will be ignored. If possible log statements below
+ this level will be discarded at build time. Levels:
+
+ 0 - emergency
+ 1 - alert
+ 2 - critical
+ 3 - error
+ 4 - warning
+ 5 - note
+ 6 - info
+ 7 - debug
+ 8 - debug content
+ 9 - debug hardware I/O
+
+config LOG_DEFAULT_LEVEL
+ int "Default logging level to display"
+ default LOG_MAX_LEVEL
+ range 0 LOG_MAX_LEVEL
+ help
+ This is the default logging level set when U-Boot starts. It can
+ be adjusted later using the 'log level' command. Note that setting
+ this to a value above LOG_MAX_LEVEL will be ineffective, since the
+ higher levels are not compiled in to U-Boot.
+
+ 0 - emergency
+ 1 - alert
+ 2 - critical
+ 3 - error
+ 4 - warning
+ 5 - note
+ 6 - info
+ 7 - debug
+ 8 - debug content
+ 9 - debug hardware I/O
+
+config LOG_CONSOLE
+ bool "Allow log output to the console"
+ default y
+ help
+ Enables a log driver which writes log records to the console.
+ Generally the console is the serial port or LCD display. Only the
+ log message is shown - other details like level, category, file and
+ line number are omitted.
+
+config LOGF_FILE
+ bool "Show source file name in log messages by default"
+ help
+ Show the source file name in log messages by default. This value
+ can be overridden using the 'log format' command.
+
+config LOGF_LINE
+ bool "Show source line number in log messages by default"
+ help
+ Show the source line number in log messages by default. This value
+ can be overridden using the 'log format' command.
+
+config LOGF_FUNC
+ bool "Show function name in log messages by default"
+ help
+ Show the function name in log messages by default. This value can
+ be overridden using the 'log format' command.
+
+config LOG_SYSLOG
+ bool "Log output to syslog server"
+ depends on NET
+ help
+ Enables a log driver which broadcasts log records via UDP port 514
+ to syslog servers.
+
+config SPL_LOG
+ bool "Enable logging support in SPL"
+ depends on LOG
+ help
+ This enables support for logging of status and debug messages. These
+ can be displayed on the console, recorded in a memory buffer, or
+ discarded if not needed. Logging supports various categories and
+ levels of severity.
+
+if SPL_LOG
+
+config SPL_LOG_MAX_LEVEL
+ int "Maximum log level to record in SPL"
+ depends on SPL_LOG
+ default 3
+ range 0 9
+ help
+ This selects the maximum log level that will be recorded. Any value
+ higher than this will be ignored. If possible log statements below
+ this level will be discarded at build time. Levels:
+
+ 0 - emergency
+ 1 - alert
+ 2 - critical
+ 3 - error
+ 4 - warning
+ 5 - note
+ 6 - info
+ 7 - debug
+ 8 - debug content
+ 9 - debug hardware I/O
+
+config SPL_LOG_CONSOLE
+ bool "Allow log output to the console in SPL"
+ default y
+ help
+ Enables a log driver which writes log records to the console.
+ Generally the console is the serial port or LCD display. Only the
+ log message is shown - other details like level, category, file and
+ line number are omitted.
+
+endif
+
+config TPL_LOG
+ bool "Enable logging support in TPL"
+ depends on LOG
+ help
+ This enables support for logging of status and debug messages. These
+ can be displayed on the console, recorded in a memory buffer, or
+ discarded if not needed. Logging supports various categories and
+ levels of severity.
+
+if TPL_LOG
+
+config TPL_LOG_MAX_LEVEL
+ int "Maximum log level to record in TPL"
+ depends on TPL_LOG
+ default 3
+ range 0 9
+ help
+ This selects the maximum log level that will be recorded. Any value
+ higher than this will be ignored. If possible log statements below
+ this level will be discarded at build time. Levels:
+
+ 0 - emergency
+ 1 - alert
+ 2 - critical
+ 3 - error
+ 4 - warning
+ 5 - note
+ 6 - info
+ 7 - debug
+ 8 - debug content
+ 9 - debug hardware I/O
+
+config TPL_LOG_CONSOLE
+ bool "Allow log output to the console in TPL"
+ default y
+ help
+ Enables a log driver which writes log records to the console.
+ Generally the console is the serial port or LCD display. Only the
+ log message is shown - other details like level, category, file and
+ line number are omitted.
+
+endif
+
+config LOG_ERROR_RETURN
+ bool "Log all functions which return an error"
+ help
+ When an error is returned in U-Boot it is sometimes difficult to
+ figure out the root cause. For example, reading from SPI flash may
+ fail due to a problem in the SPI controller or due to the flash part
+ not returning the expected information. This option changes
+ log_ret() to log any errors it sees. With this option disabled,
+ log_ret() is a nop.
+
+ You can add log_ret() to all functions which return an error code.
+
+config LOG_TEST
+ bool "Provide a test for logging"
+ depends on UNIT_TEST
+ default y if SANDBOX
+ help
+ This enables a 'log test' command to test logging. It is normally
+ executed from a pytest and simply outputs logging information
+ in various different ways to test that the logging system works
+ correctly with various settings.
+
+endif
+
+endmenu
+
+menu "Init options"
+
+config BOARD_TYPES
+ bool "Call get_board_type() to get and display the board type"
+ help
+ If this option is enabled, checkboard() will call get_board_type()
+ to get a string containing the board type and this will be
+ displayed immediately after the model is shown on the console
+ early in boot.
+
+config DISPLAY_CPUINFO
+ bool "Display information about the CPU during start up"
+ default y if ARC|| ARM || NIOS2 || X86 || XTENSA || M68K
+ help
+ Display information about the CPU that U-Boot is running on
+ when U-Boot starts up. The function print_cpuinfo() is called
+ to do this.
+
+config DISPLAY_BOARDINFO
+ bool "Display information about the board during early start up"
+ default y if ARC || ARM || M68K || MIPS || PPC || SANDBOX || XTENSA
+ help
+ Display information about the board that U-Boot is running on
+ when U-Boot starts up. The board function checkboard() is called
+ to do this.
+
+config DISPLAY_BOARDINFO_LATE
+ bool "Display information about the board during late start up"
+ help
+ Display information about the board that U-Boot is running on after
+ the relocation phase. The board function checkboard() is called to do
+ this.
+
+menu "Start-up hooks"
+
+config ARCH_EARLY_INIT_R
+ bool "Call arch-specific init soon after relocation"
+ help
+ With this option U-Boot will call arch_early_init_r() soon after
+ relocation. Driver model is running by this point, and the cache
+ is on. Note that board_early_init_r() is called first, if
+ enabled. This can be used to set up architecture-specific devices.
+
+config ARCH_MISC_INIT
+ bool "Call arch-specific init after relocation, when console is ready"
+ help
+ With this option U-Boot will call arch_misc_init() after
+ relocation to allow miscellaneous arch-dependent initialisation
+ to be performed. This function should be defined by the board
+ and will be called after the console is set up, after relocation.
+
+config BOARD_EARLY_INIT_F
+ bool "Call board-specific init before relocation"
+ help
+ Some boards need to perform initialisation as soon as possible
+ after boot. With this option, U-Boot calls board_early_init_f()
+ after driver model is ready in the pre-relocation init sequence.
+ Note that the normal serial console is not yet set up, but the
+ debug UART will be available if enabled.
+
+config BOARD_EARLY_INIT_R
+ bool "Call board-specific init after relocation"
+ help
+ Some boards need to perform initialisation as directly after
+ relocation. With this option, U-Boot calls board_early_init_r()
+ in the post-relocation init sequence.
+
+config BOARD_LATE_INIT
+ bool "Execute Board late init"
+ help
+ Sometimes board require some initialization code that might
+ require once the actual init done, example saving board specific env,
+ boot-modes etc. which eventually done at late.
+
+ So this config enable the late init code with the help of board_late_init
+ function which should defined on respective boards.
+
+config LAST_STAGE_INIT
+ bool "Call board-specific as last setup step"
+ help
+ Some boards need to perform initialisation immediately before control
+ is passed to the command-line interpreter (e.g. for initializations
+ that depend on later phases in the init sequence). With this option,
+ U-Boot calls last_stage_init() before the command-line interpreter is
+ started.
+
+config MISC_INIT_F
+ bool "Execute pre-relocation misc init"
+ help
+ Enabling this option calls the 'misc_init_f' function in the init
+ sequence just before DRAM is inited.
+
+config MISC_INIT_R
+ bool "Execute Misc Init"
+ default y if ARCH_KEYSTONE || ARCH_SUNXI || MPC85xx
+ default y if ARCH_OMAP2PLUS && !AM33XX
+ help
+ Enabling this option calls 'misc_init_r' function
+
+config PCI_INIT_R
+ bool "Enumerate PCI buses during init"
+ depends on PCI
+ default y if !DM_PCI
+ help
+ With this option U-Boot will call pci_init() soon after relocation,
+ which will enumerate PCI buses. This is needed, for instance, in the
+ case of DM PCI-based Ethernet devices, which will not be detected
+ without having the enumeration performed earlier.
+
+endmenu
+
+endmenu # Init options
+
+menu "Security support"
+
+config HASH
+ bool # "Support hashing API (SHA1, SHA256, etc.)"
+ help
+ This provides a way to hash data in memory using various supported
+ algorithms (such as SHA1, MD5, CRC32). The API is defined in hash.h
+ and the algorithms it supports are defined in common/hash.c. See
+ also CMD_HASH for command-line access.
+
+config AVB_VERIFY
+ bool "Build Android Verified Boot operations"
+ depends on LIBAVB
+ depends on MMC
+ depends on PARTITION_UUIDS
+ help
+ This option enables compilation of bootloader-dependent operations,
+ used by Android Verified Boot 2.0 library (libavb). Includes:
+ * Helpers to process strings in order to build OS bootargs.
+ * Helpers to access MMC, similar to drivers/fastboot/fb_mmc.c.
+ * Helpers to alloc/init/free avb ops.
+
+if AVB_VERIFY
+
+config AVB_BUF_ADDR
+ hex "Define AVB buffer address"
+ default FASTBOOT_BUF_ADDR
+ help
+ AVB requires a buffer for memory transactions. This variable defines the
+ buffer address.
+
+config AVB_BUF_SIZE
+ hex "Define AVB buffer SIZE"
+ default FASTBOOT_BUF_SIZE
+ help
+ AVB requires a buffer for memory transactions. This variable defines the
+ buffer size.
+
+endif # AVB_VERIFY
+
+config SCP03
+ bool "Build SCP03 - Secure Channel Protocol O3 - controls"
+ depends on OPTEE || SANDBOX
+ depends on TEE
+ help
+ This option allows U-Boot to enable and or provision SCP03 on an OPTEE
+ controlled Secured Element.
+
+config SPL_HASH
+ bool # "Support hashing API (SHA1, SHA256, etc.)"
+ help
+ This provides a way to hash data in memory using various supported
+ algorithms (such as SHA1, MD5, CRC32). The API is defined in hash.h
+ and the algorithms it supports are defined in common/hash.c. See
+ also CMD_HASH for command-line access.
+
+config TPL_HASH
+ bool # "Support hashing API (SHA1, SHA256, etc.)"
+ help
+ This provides a way to hash data in memory using various supported
+ algorithms (such as SHA1, MD5, CRC32). The API is defined in hash.h
+ and the algorithms it supports are defined in common/hash.c. See
+ also CMD_HASH for command-line access.
+
+config STACKPROTECTOR
+ bool "Stack Protector buffer overflow detection"
+ default n
+ help
+ Enable stack smash detection through compiler's stack-protector
+ canary logic
+
+config SPL_STACKPROTECTOR
+ bool "Stack Protector buffer overflow detection for SPL"
+ depends on STACKPROTECTOR && SPL
+ default n
+
+config TPL_STACKPROTECTOR
+ bool "Stack Protector buffer overflow detection for TPL"
+ depends on STACKPROTECTOR && TPL
+ default n
+
+endmenu
+
+menu "Update support"
+
+config UPDATE_COMMON
+ bool
+ default n
+ select DFU_WRITE_ALT
+
+config UPDATE_TFTP
+ bool "Auto-update using fitImage via TFTP"
+ depends on FIT
+ select UPDATE_COMMON
+ help
+ This option allows performing update of NOR with data in fitImage
+ sent via TFTP boot.
+
+config UPDATE_TFTP_CNT_MAX
+ int "The number of connection retries during auto-update"
+ default 0
+ depends on UPDATE_TFTP
+
+config UPDATE_TFTP_MSEC_MAX
+ int "Delay in mSec to wait for the TFTP server during auto-update"
+ default 100
+ depends on UPDATE_TFTP
+
+config UPDATE_FIT
+ bool "Firmware update using fitImage"
+ depends on FIT
+ depends on DFU
+ select UPDATE_COMMON
+ help
+ This option allows performing update of DFU-capable storage with
+ data in fitImage.
+
+config ANDROID_AB
+ bool "Android A/B updates"
+ default n
+ help
+ If enabled, adds support for the new Android A/B update model. This
+ allows the bootloader to select which slot to boot from based on the
+ information provided by userspace via the Android boot_ctrl HAL. This
+ allows a bootloader to try a new version of the system but roll back
+ to previous version if the new one didn't boot all the way.
+
+endmenu
+
+menu "Blob list"
+
+config BLOBLIST
+ bool "Support for a bloblist"
+ help
+ This enables support for a bloblist in U-Boot, which can be passed
+ from TPL to SPL to U-Boot proper (and potentially to Linux). The
+ blob list supports multiple binary blobs of data, each with a tag,
+ so that different U-Boot components can store data which can survive
+ through to the next stage of the boot.
+
+config SPL_BLOBLIST
+ bool "Support for a bloblist in SPL"
+ depends on BLOBLIST
+ default y if SPL
+ help
+ This enables a bloblist in SPL. If this is the first part of U-Boot
+ to run, then the bloblist is set up in SPL and passed to U-Boot
+ proper. If TPL also has a bloblist, then SPL uses the one from there.
+
+config TPL_BLOBLIST
+ bool "Support for a bloblist in TPL"
+ depends on BLOBLIST
+ default y if TPL
+ help
+ This enables a bloblist in TPL. The bloblist is set up in TPL and
+ passed to SPL and U-Boot proper.
+
+config BLOBLIST_SIZE
+ hex "Size of bloblist"
+ depends on BLOBLIST
+ default 0x400
+ help
+ Sets the size of the bloblist in bytes. This must include all
+ overhead (alignment, bloblist header, record header). The bloblist
+ is set up in the first part of U-Boot to run (TPL, SPL or U-Boot
+ proper), and this sane bloblist is used for subsequent stages.
+
+config BLOBLIST_ADDR
+ hex "Address of bloblist"
+ depends on BLOBLIST
+ default 0xe000 if SANDBOX
+ help
+ Sets the address of the bloblist, set up by the first part of U-Boot
+ which runs. Subsequent U-Boot stages typically use the same address.
+
+config BLOBLIST_SIZE_RELOC
+ hex "Size of bloblist after relocation"
+ depends on BLOBLIST
+ default BLOBLIST_SIZE
+ help
+ Sets the size of the bloblist in bytes after relocation. Since U-Boot
+ has a lot more memory available then, it is possible to use a larger
+ size than the one set up by SPL. This bloblist is set up during the
+ relocation process.
+
+endmenu
+
+source "common/spl/Kconfig"
+
+config IMAGE_SIGN_INFO
+ bool
+ select SHA1
+ select SHA256
+ help
+ Enable image_sign_info helper functions.
+
+if IMAGE_SIGN_INFO
+
+config SPL_IMAGE_SIGN_INFO
+ bool
+ select SHA1
+ select SHA256
+ help
+ Enable image_sign_info helper functions in SPL.
+
+endif
diff --git a/roms/u-boot/common/Kconfig.boot b/roms/u-boot/common/Kconfig.boot
new file mode 100644
index 000000000..89a3161f1
--- /dev/null
+++ b/roms/u-boot/common/Kconfig.boot
@@ -0,0 +1,970 @@
+menu "Boot options"
+
+menu "Boot images"
+
+config ANDROID_BOOT_IMAGE
+ bool "Enable support for Android Boot Images"
+ default y if FASTBOOT
+ help
+ This enables support for booting images which use the Android
+ image format header.
+
+config FIT
+ bool "Support Flattened Image Tree"
+ select MD5
+ select SHA1
+ help
+ This option allows you to boot the new uImage structure,
+ Flattened Image Tree. FIT is formally a FDT, which can include
+ images of various types (kernel, FDT blob, ramdisk, etc.)
+ in a single blob. To boot this new uImage structure,
+ pass the address of the blob to the "bootm" command.
+ FIT is very flexible, supporting compression, multiple images,
+ multiple configurations, verification through hashing and also
+ verified boot (secure boot using RSA).
+
+if FIT
+
+config FIT_EXTERNAL_OFFSET
+ hex "FIT external data offset"
+ default 0x0
+ help
+ This specifies a data offset in fit image.
+ The offset is from data payload offset to the beginning of
+ fit image header. When specifies a offset, specific data
+ could be put in the hole between data payload and fit image
+ header, such as CSF data on i.MX platform.
+
+config FIT_ENABLE_SHA256_SUPPORT
+ bool "Support SHA256 checksum of FIT image contents"
+ default y
+ select SHA256
+ help
+ Enable this to support SHA256 checksum of FIT image contents. A
+ SHA256 checksum is a 256-bit (32-byte) hash value used to check that
+ the image contents have not been corrupted.
+
+config FIT_ENABLE_SHA384_SUPPORT
+ bool "Support SHA384 checksum of FIT image contents"
+ default n
+ select SHA384
+ help
+ Enable this to support SHA384 checksum of FIT image contents. A
+ SHA384 checksum is a 384-bit (48-byte) hash value used to check that
+ the image contents have not been corrupted. Use this for the highest
+ security.
+
+config FIT_ENABLE_SHA512_SUPPORT
+ bool "Support SHA512 checksum of FIT image contents"
+ default n
+ select SHA512
+ help
+ Enable this to support SHA512 checksum of FIT image contents. A
+ SHA512 checksum is a 512-bit (64-byte) hash value used to check that
+ the image contents have not been corrupted.
+
+config FIT_FULL_CHECK
+ bool "Do a full check of the FIT before using it"
+ default y
+ help
+ Enable this do a full check of the FIT to make sure it is valid. This
+ helps to protect against carefully crafted FITs which take advantage
+ of bugs or omissions in the code. This includes a bad structure,
+ multiple root nodes and the like.
+
+config FIT_SIGNATURE
+ bool "Enable signature verification of FIT uImages"
+ depends on DM
+ select HASH
+ select RSA
+ select RSA_VERIFY
+ select IMAGE_SIGN_INFO
+ select FIT_FULL_CHECK
+ help
+ This option enables signature verification of FIT uImages,
+ using a hash signed and verified using RSA. If
+ CONFIG_SHA_PROG_HW_ACCEL is defined, i.e support for progressive
+ hashing is available using hardware, then the RSA library will use
+ it. See doc/uImage.FIT/signature.txt for more details.
+
+ WARNING: When relying on signed FIT images with a required signature
+ check the legacy image format is disabled by default, so that
+ unsigned images cannot be loaded. If a board needs the legacy image
+ format support in this case, enable it using
+ CONFIG_LEGACY_IMAGE_FORMAT.
+
+config FIT_SIGNATURE_MAX_SIZE
+ hex "Max size of signed FIT structures"
+ depends on FIT_SIGNATURE
+ default 0x10000000
+ help
+ This option sets a max size in bytes for verified FIT uImages.
+ A sane value of 256MB protects corrupted DTB structures from overlapping
+ device memory. Assure this size does not extend past expected storage
+ space.
+
+config FIT_ENABLE_RSASSA_PSS_SUPPORT
+ bool "Support rsassa-pss signature scheme of FIT image contents"
+ depends on FIT_SIGNATURE
+ default n
+ help
+ Enable this to support the pss padding algorithm as described
+ in the rfc8017 (https://tools.ietf.org/html/rfc8017).
+
+config FIT_CIPHER
+ bool "Enable ciphering data in a FIT uImages"
+ depends on DM
+ select AES
+ help
+ Enable the feature of data ciphering/unciphering in the tool mkimage
+ and in the u-boot support of the FIT image.
+
+config FIT_VERBOSE
+ bool "Show verbose messages when FIT images fail"
+ help
+ Generally a system will have valid FIT images so debug messages
+ are a waste of code space. If you are debugging your images then
+ you can enable this option to get more verbose information about
+ failures.
+
+config FIT_BEST_MATCH
+ bool "Select the best match for the kernel device tree"
+ help
+ When no configuration is explicitly selected, default to the
+ one whose fdt's compatibility field best matches that of
+ U-Boot itself. A match is considered "best" if it matches the
+ most specific compatibility entry of U-Boot's fdt's root node.
+ The order of entries in the configuration's fdt is ignored.
+
+config FIT_IMAGE_POST_PROCESS
+ bool "Enable post-processing of FIT artifacts after loading by U-Boot"
+ depends on TI_SECURE_DEVICE || SOCFPGA_SECURE_VAB_AUTH
+ help
+ Allows doing any sort of manipulation to blobs after they got extracted
+ from FIT images like stripping off headers or modifying the size of the
+ blob, verification, authentication, decryption etc. in a platform or
+ board specific way. In order to use this feature a platform or board-
+ specific implementation of board_fit_image_post_process() must be
+ provided. Also, anything done during this post-processing step would
+ need to be comprehended in how the images were prepared before being
+ injected into the FIT creation (i.e. the blobs would have been pre-
+ processed before being added to the FIT image).
+
+config FIT_PRINT
+ bool "Support FIT printing"
+ default y
+ help
+ Support printing the content of the fitImage in a verbose manner.
+
+if SPL
+
+config SPL_FIT
+ bool "Support Flattened Image Tree within SPL"
+ depends on SPL
+ select SPL_OF_LIBFDT
+
+config SPL_FIT_PRINT
+ bool "Support FIT printing within SPL"
+ depends on SPL_FIT
+ help
+ Support printing the content of the fitImage in a verbose manner in SPL.
+
+config SPL_FIT_FULL_CHECK
+ bool "Do a full check of the FIT before using it"
+ help
+ Enable this do a full check of the FIT to make sure it is valid. This
+ helps to protect against carefully crafted FITs which take advantage
+ of bugs or omissions in the code. This includes a bad structure,
+ multiple root nodes and the like.
+
+
+config SPL_FIT_SIGNATURE
+ bool "Enable signature verification of FIT firmware within SPL"
+ depends on SPL_DM
+ depends on SPL_LOAD_FIT || SPL_LOAD_FIT_FULL
+ select FIT_SIGNATURE
+ select SPL_FIT
+ select SPL_CRYPTO_SUPPORT
+ select SPL_HASH_SUPPORT
+ select SPL_RSA
+ select SPL_RSA_VERIFY
+ select SPL_IMAGE_SIGN_INFO
+ select SPL_FIT_FULL_CHECK
+
+config SPL_LOAD_FIT
+ bool "Enable SPL loading U-Boot as a FIT (basic fitImage features)"
+ select SPL_FIT
+ help
+ Normally with the SPL framework a legacy image is generated as part
+ of the build. This contains U-Boot along with information as to
+ where it should be loaded. This option instead enables generation
+ of a FIT (Flat Image Tree) which provides more flexibility. In
+ particular it can handle selecting from multiple device tree
+ and passing the correct one to U-Boot.
+
+ This path has the following limitations:
+
+ 1. "loadables" images, other than FDTs, which do not have a "load"
+ property will not be loaded. This limitation also applies to FPGA
+ images with the correct "compatible" string.
+ 2. For FPGA images, only the "compatible" = "u-boot,fpga-legacy"
+ loading method is supported.
+ 3. FDTs are only loaded for images with an "os" property of "u-boot".
+ "linux" images are also supported with Falcon boot mode.
+
+config SPL_LOAD_FIT_ADDRESS
+ hex "load address of fit image"
+ depends on SPL_LOAD_FIT
+ default 0x0
+ help
+ Specify the load address of the fit image that will be loaded
+ by SPL.
+
+config SPL_LOAD_FIT_APPLY_OVERLAY
+ bool "Enable SPL applying DT overlays from FIT"
+ depends on SPL_LOAD_FIT
+ select OF_LIBFDT_OVERLAY
+ help
+ The device tree is loaded from the FIT image. Allow the SPL is to
+ also load device-tree overlays from the FIT image an apply them
+ over the device tree.
+
+config SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ
+ depends on SPL_LOAD_FIT_APPLY_OVERLAY
+ default 0x10000
+ hex "size of temporary buffer used to load the overlays"
+ help
+ The size of the area where the overlays will be loaded and
+ uncompress. Must be at least as large as biggest overlay
+ (uncompressed)
+
+config SPL_LOAD_FIT_FULL
+ bool "Enable SPL loading U-Boot as a FIT (full fitImage features)"
+ select SPL_FIT
+ help
+ Normally with the SPL framework a legacy image is generated as part
+ of the build. This contains U-Boot along with information as to
+ where it should be loaded. This option instead enables generation
+ of a FIT (Flat Image Tree) which provides more flexibility. In
+ particular it can handle selecting from multiple device tree
+ and passing the correct one to U-Boot.
+
+config SPL_FIT_IMAGE_POST_PROCESS
+ bool "Enable post-processing of FIT artifacts after loading by the SPL"
+ depends on SPL_LOAD_FIT
+ help
+ Allows doing any sort of manipulation to blobs after they got extracted
+ from the U-Boot FIT image like stripping off headers or modifying the
+ size of the blob, verification, authentication, decryption etc. in a
+ platform or board specific way. In order to use this feature a platform
+ or board-specific implementation of board_fit_image_post_process() must
+ be provided. Also, anything done during this post-processing step would
+ need to be comprehended in how the images were prepared before being
+ injected into the FIT creation (i.e. the blobs would have been pre-
+ processed before being added to the FIT image).
+
+config SPL_FIT_SOURCE
+ string ".its source file for U-Boot FIT image"
+ depends on SPL_FIT
+ help
+ Specifies a (platform specific) FIT source file to generate the
+ U-Boot FIT image. This could specify further image to load and/or
+ execute.
+
+config USE_SPL_FIT_GENERATOR
+ bool "Use a script to generate the .its script"
+ default y if SPL_FIT && (!ARCH_SUNXI && !RISCV)
+
+config SPL_FIT_GENERATOR
+ string ".its file generator script for U-Boot FIT image"
+ depends on USE_SPL_FIT_GENERATOR
+ default "arch/arm/mach-rockchip/make_fit_atf.py" if SPL_LOAD_FIT && ARCH_ROCKCHIP
+ default "arch/arm/mach-zynqmp/mkimage_fit_atf.sh" if SPL_LOAD_FIT && ARCH_ZYNQMP
+ help
+ Specifies a (platform specific) script file to generate the FIT
+ source file used to build the U-Boot FIT image file. This gets
+ passed a list of supported device tree file stub names to
+ include in the generated image.
+
+endif # SPL
+
+endif # FIT
+
+config LEGACY_IMAGE_FORMAT
+ bool "Enable support for the legacy image format"
+ default y if !FIT_SIGNATURE
+ help
+ This option enables the legacy image format. It is enabled by
+ default for backward compatibility, unless FIT_SIGNATURE is
+ set where it is disabled so that unsigned images cannot be
+ loaded. If a board needs the legacy image format support in this
+ case, enable it here.
+
+config SUPPORT_RAW_INITRD
+ bool "Enable raw initrd images"
+ help
+ Note, defining the SUPPORT_RAW_INITRD allows user to supply
+ kernel with raw initrd images. The syntax is slightly different, the
+ address of the initrd must be augmented by it's size, in the following
+ format: "<initrd address>:<initrd size>".
+
+config OF_BOARD_SETUP
+ bool "Set up board-specific details in device tree before boot"
+ depends on OF_LIBFDT
+ help
+ This causes U-Boot to call ft_board_setup() before booting into
+ the Operating System. This function can set up various
+ board-specific information in the device tree for use by the OS.
+ The device tree is then passed to the OS.
+
+config OF_SYSTEM_SETUP
+ bool "Set up system-specific details in device tree before boot"
+ depends on OF_LIBFDT
+ help
+ This causes U-Boot to call ft_system_setup() before booting into
+ the Operating System. This function can set up various
+ system-specific information in the device tree for use by the OS.
+ The device tree is then passed to the OS.
+
+config OF_STDOUT_VIA_ALIAS
+ bool "Update the device-tree stdout alias from U-Boot"
+ depends on OF_LIBFDT
+ help
+ This uses U-Boot's serial alias from the aliases node to update
+ the device tree passed to the OS. The "linux,stdout-path" property
+ in the chosen node is set to point to the correct serial node.
+ This option currently references CONFIG_CONS_INDEX, which is
+ incorrect when used with device tree as this option does not
+ exist / should not be used.
+
+config SYS_EXTRA_OPTIONS
+ string "Extra Options (DEPRECATED)"
+ help
+ The old configuration infrastructure (= mkconfig + boards.cfg)
+ provided the extra options field. If you have something like
+ "HAS_BAR,BAZ=64", the optional options
+ #define CONFIG_HAS
+ #define CONFIG_BAZ 64
+ will be defined in include/config.h.
+ This option was prepared for the smooth migration from the old
+ configuration to Kconfig. Since this option will be removed sometime,
+ new boards should not use this option.
+
+config HAVE_SYS_TEXT_BASE
+ bool
+ depends on !NIOS2 && !XTENSA
+ depends on !EFI_APP
+ default y
+
+config SYS_TEXT_BASE
+ depends on HAVE_SYS_TEXT_BASE
+ default 0x80800000 if ARCH_OMAP2PLUS || ARCH_K3
+ default 0x4a000000 if ARCH_SUNXI && !MACH_SUN9I && !MACH_SUN8I_V3S
+ default 0x2a000000 if ARCH_SUNXI && MACH_SUN9I
+ default 0x42e00000 if ARCH_SUNXI && MACH_SUN8I_V3S
+ hex "Text Base"
+ help
+ The address in memory that U-Boot will be running from, initially.
+
+config SYS_CLK_FREQ
+ depends on ARC || ARCH_SUNXI || MPC83xx
+ int "CPU clock frequency"
+ help
+ TODO: Move CONFIG_SYS_CLK_FREQ for all the architecture
+
+config ARCH_FIXUP_FDT_MEMORY
+ bool "Enable arch_fixup_memory_banks() call"
+ default y
+ help
+ Enable FDT memory map syncup before OS boot. This feature can be
+ used for booting OS with different memory setup where the part of
+ the memory location should be used for different purpose.
+
+config CHROMEOS
+ bool "Support booting Chrome OS"
+ help
+ Chrome OS requires U-Boot to set up a table indicating the boot mode
+ (e.g. Developer mode) and a few other things. Enable this if you are
+ booting on a Chromebook to avoid getting an error about an invalid
+ firmware ID.
+
+config CHROMEOS_VBOOT
+ bool "Support Chrome OS verified boot"
+ help
+ This is intended to enable the full Chrome OS verified boot support
+ in U-Boot. It is not actually implemented in the U-Boot source code
+ at present, so this option is always set to 'n'. It allows
+ distinguishing between booting Chrome OS in a basic way (developer
+ mode) and a full boot.
+
+endmenu # Boot images
+
+menu "Boot timing"
+
+config BOOTSTAGE
+ bool "Boot timing and reporting"
+ help
+ Enable recording of boot time while booting. To use it, insert
+ calls to bootstage_mark() with a suitable BOOTSTAGE_ID from
+ bootstage.h. Only a single entry is recorded for each ID. You can
+ give the entry a name with bootstage_mark_name(). You can also
+ record elapsed time in a particular stage using bootstage_start()
+ before starting and bootstage_accum() when finished. Bootstage will
+ add up all the accumulated time and report it.
+
+ Normally, IDs are defined in bootstage.h but a small number of
+ additional 'user' IDs can be used by passing BOOTSTAGE_ID_ALLOC
+ as the ID.
+
+ Calls to show_boot_progress() will also result in log entries but
+ these will not have names.
+
+config SPL_BOOTSTAGE
+ bool "Boot timing and reported in SPL"
+ depends on BOOTSTAGE
+ help
+ Enable recording of boot time in SPL. To make this visible to U-Boot
+ proper, enable BOOTSTAGE_STASH as well. This will stash the timing
+ information when SPL finishes and load it when U-Boot proper starts
+ up.
+
+config TPL_BOOTSTAGE
+ bool "Boot timing and reported in TPL"
+ depends on BOOTSTAGE
+ help
+ Enable recording of boot time in SPL. To make this visible to U-Boot
+ proper, enable BOOTSTAGE_STASH as well. This will stash the timing
+ information when TPL finishes and load it when U-Boot proper starts
+ up.
+
+config BOOTSTAGE_REPORT
+ bool "Display a detailed boot timing report before booting the OS"
+ depends on BOOTSTAGE
+ help
+ Enable output of a boot time report just before the OS is booted.
+ This shows how long it took U-Boot to go through each stage of the
+ boot process. The report looks something like this:
+
+ Timer summary in microseconds:
+ Mark Elapsed Stage
+ 0 0 reset
+ 3,575,678 3,575,678 board_init_f start
+ 3,575,695 17 arch_cpu_init A9
+ 3,575,777 82 arch_cpu_init done
+ 3,659,598 83,821 board_init_r start
+ 3,910,375 250,777 main_loop
+ 29,916,167 26,005,792 bootm_start
+ 30,361,327 445,160 start_kernel
+
+config BOOTSTAGE_RECORD_COUNT
+ int "Number of boot stage records to store"
+ depends on BOOTSTAGE
+ default 30
+ help
+ This is the size of the bootstage record list and is the maximum
+ number of bootstage records that can be recorded.
+
+config SPL_BOOTSTAGE_RECORD_COUNT
+ int "Number of boot stage records to store for SPL"
+ depends on SPL_BOOTSTAGE
+ default 5
+ help
+ This is the size of the bootstage record list and is the maximum
+ number of bootstage records that can be recorded.
+
+config TPL_BOOTSTAGE_RECORD_COUNT
+ int "Number of boot stage records to store for TPL"
+ depends on TPL_BOOTSTAGE
+ default 5
+ help
+ This is the size of the bootstage record list and is the maximum
+ number of bootstage records that can be recorded.
+
+config BOOTSTAGE_FDT
+ bool "Store boot timing information in the OS device tree"
+ depends on BOOTSTAGE
+ help
+ Stash the bootstage information in the FDT. A root 'bootstage'
+ node is created with each bootstage id as a child. Each child
+ has a 'name' property and either 'mark' containing the
+ mark time in microseconds, or 'accum' containing the
+ accumulated time for that bootstage id in microseconds.
+ For example:
+
+ bootstage {
+ 154 {
+ name = "board_init_f";
+ mark = <3575678>;
+ };
+ 170 {
+ name = "lcd";
+ accum = <33482>;
+ };
+ };
+
+ Code in the Linux kernel can find this in /proc/devicetree.
+
+config BOOTSTAGE_STASH
+ bool "Stash the boot timing information in memory before booting OS"
+ depends on BOOTSTAGE
+ help
+ Some OSes do not support device tree. Bootstage can instead write
+ the boot timing information in a binary format at a given address.
+ This happens through a call to bootstage_stash(), typically in
+ the CPU's cleanup_before_linux() function. You can use the
+ 'bootstage stash' and 'bootstage unstash' commands to do this on
+ the command line.
+
+config BOOTSTAGE_STASH_ADDR
+ hex "Address to stash boot timing information"
+ default 0
+ help
+ Provide an address which will not be overwritten by the OS when it
+ starts, so that it can read this information when ready.
+
+config BOOTSTAGE_STASH_SIZE
+ hex "Size of boot timing stash region"
+ default 0x1000
+ help
+ This should be large enough to hold the bootstage stash. A value of
+ 4096 (4KiB) is normally plenty.
+
+config SHOW_BOOT_PROGRESS
+ bool "Show boot progress in a board-specific manner"
+ help
+ Defining this option allows to add some board-specific code (calling
+ a user-provided function show_boot_progress(int) that enables you to
+ show the system's boot progress on some display (for example, some
+ LEDs) on your board. At the moment, the following checkpoints are
+ implemented:
+
+ Legacy uImage format:
+
+ Arg Where When
+ 1 common/cmd_bootm.c before attempting to boot an image
+ -1 common/cmd_bootm.c Image header has bad magic number
+ 2 common/cmd_bootm.c Image header has correct magic number
+ -2 common/cmd_bootm.c Image header has bad checksum
+ 3 common/cmd_bootm.c Image header has correct checksum
+ -3 common/cmd_bootm.c Image data has bad checksum
+ 4 common/cmd_bootm.c Image data has correct checksum
+ -4 common/cmd_bootm.c Image is for unsupported architecture
+ 5 common/cmd_bootm.c Architecture check OK
+ -5 common/cmd_bootm.c Wrong Image Type (not kernel, multi)
+ 6 common/cmd_bootm.c Image Type check OK
+ -6 common/cmd_bootm.c gunzip uncompression error
+ -7 common/cmd_bootm.c Unimplemented compression type
+ 7 common/cmd_bootm.c Uncompression OK
+ 8 common/cmd_bootm.c No uncompress/copy overwrite error
+ -9 common/cmd_bootm.c Unsupported OS (not Linux, BSD, VxWorks, QNX)
+
+ 9 common/image.c Start initial ramdisk verification
+ -10 common/image.c Ramdisk header has bad magic number
+ -11 common/image.c Ramdisk header has bad checksum
+ 10 common/image.c Ramdisk header is OK
+ -12 common/image.c Ramdisk data has bad checksum
+ 11 common/image.c Ramdisk data has correct checksum
+ 12 common/image.c Ramdisk verification complete, start loading
+ -13 common/image.c Wrong Image Type (not PPC Linux ramdisk)
+ 13 common/image.c Start multifile image verification
+ 14 common/image.c No initial ramdisk, no multifile, continue.
+
+ 15 arch/<arch>/lib/bootm.c All preparation done, transferring control to OS
+
+ -30 arch/powerpc/lib/board.c Fatal error, hang the system
+ -31 post/post.c POST test failed, detected by post_output_backlog()
+ -32 post/post.c POST test failed, detected by post_run_single()
+
+ 34 common/cmd_doc.c before loading a Image from a DOC device
+ -35 common/cmd_doc.c Bad usage of "doc" command
+ 35 common/cmd_doc.c correct usage of "doc" command
+ -36 common/cmd_doc.c No boot device
+ 36 common/cmd_doc.c correct boot device
+ -37 common/cmd_doc.c Unknown Chip ID on boot device
+ 37 common/cmd_doc.c correct chip ID found, device available
+ -38 common/cmd_doc.c Read Error on boot device
+ 38 common/cmd_doc.c reading Image header from DOC device OK
+ -39 common/cmd_doc.c Image header has bad magic number
+ 39 common/cmd_doc.c Image header has correct magic number
+ -40 common/cmd_doc.c Error reading Image from DOC device
+ 40 common/cmd_doc.c Image header has correct magic number
+ 41 common/cmd_ide.c before loading a Image from a IDE device
+ -42 common/cmd_ide.c Bad usage of "ide" command
+ 42 common/cmd_ide.c correct usage of "ide" command
+ -43 common/cmd_ide.c No boot device
+ 43 common/cmd_ide.c boot device found
+ -44 common/cmd_ide.c Device not available
+ 44 common/cmd_ide.c Device available
+ -45 common/cmd_ide.c wrong partition selected
+ 45 common/cmd_ide.c partition selected
+ -46 common/cmd_ide.c Unknown partition table
+ 46 common/cmd_ide.c valid partition table found
+ -47 common/cmd_ide.c Invalid partition type
+ 47 common/cmd_ide.c correct partition type
+ -48 common/cmd_ide.c Error reading Image Header on boot device
+ 48 common/cmd_ide.c reading Image Header from IDE device OK
+ -49 common/cmd_ide.c Image header has bad magic number
+ 49 common/cmd_ide.c Image header has correct magic number
+ -50 common/cmd_ide.c Image header has bad checksum
+ 50 common/cmd_ide.c Image header has correct checksum
+ -51 common/cmd_ide.c Error reading Image from IDE device
+ 51 common/cmd_ide.c reading Image from IDE device OK
+ 52 common/cmd_nand.c before loading a Image from a NAND device
+ -53 common/cmd_nand.c Bad usage of "nand" command
+ 53 common/cmd_nand.c correct usage of "nand" command
+ -54 common/cmd_nand.c No boot device
+ 54 common/cmd_nand.c boot device found
+ -55 common/cmd_nand.c Unknown Chip ID on boot device
+ 55 common/cmd_nand.c correct chip ID found, device available
+ -56 common/cmd_nand.c Error reading Image Header on boot device
+ 56 common/cmd_nand.c reading Image Header from NAND device OK
+ -57 common/cmd_nand.c Image header has bad magic number
+ 57 common/cmd_nand.c Image header has correct magic number
+ -58 common/cmd_nand.c Error reading Image from NAND device
+ 58 common/cmd_nand.c reading Image from NAND device OK
+
+ -60 common/env_common.c Environment has a bad CRC, using default
+
+ 64 net/eth.c starting with Ethernet configuration.
+ -64 net/eth.c no Ethernet found.
+ 65 net/eth.c Ethernet found.
+
+ -80 common/cmd_net.c usage wrong
+ 80 common/cmd_net.c before calling net_loop()
+ -81 common/cmd_net.c some error in net_loop() occurred
+ 81 common/cmd_net.c net_loop() back without error
+ -82 common/cmd_net.c size == 0 (File with size 0 loaded)
+ 82 common/cmd_net.c trying automatic boot
+ 83 common/cmd_net.c running "source" command
+ -83 common/cmd_net.c some error in automatic boot or "source" command
+ 84 common/cmd_net.c end without errors
+
+ FIT uImage format:
+
+ Arg Where When
+ 100 common/cmd_bootm.c Kernel FIT Image has correct format
+ -100 common/cmd_bootm.c Kernel FIT Image has incorrect format
+ 101 common/cmd_bootm.c No Kernel subimage unit name, using configuration
+ -101 common/cmd_bootm.c Can't get configuration for kernel subimage
+ 102 common/cmd_bootm.c Kernel unit name specified
+ -103 common/cmd_bootm.c Can't get kernel subimage node offset
+ 103 common/cmd_bootm.c Found configuration node
+ 104 common/cmd_bootm.c Got kernel subimage node offset
+ -104 common/cmd_bootm.c Kernel subimage hash verification failed
+ 105 common/cmd_bootm.c Kernel subimage hash verification OK
+ -105 common/cmd_bootm.c Kernel subimage is for unsupported architecture
+ 106 common/cmd_bootm.c Architecture check OK
+ -106 common/cmd_bootm.c Kernel subimage has wrong type
+ 107 common/cmd_bootm.c Kernel subimage type OK
+ -107 common/cmd_bootm.c Can't get kernel subimage data/size
+ 108 common/cmd_bootm.c Got kernel subimage data/size
+ -108 common/cmd_bootm.c Wrong image type (not legacy, FIT)
+ -109 common/cmd_bootm.c Can't get kernel subimage type
+ -110 common/cmd_bootm.c Can't get kernel subimage comp
+ -111 common/cmd_bootm.c Can't get kernel subimage os
+ -112 common/cmd_bootm.c Can't get kernel subimage load address
+ -113 common/cmd_bootm.c Image uncompress/copy overwrite error
+
+ 120 common/image.c Start initial ramdisk verification
+ -120 common/image.c Ramdisk FIT image has incorrect format
+ 121 common/image.c Ramdisk FIT image has correct format
+ 122 common/image.c No ramdisk subimage unit name, using configuration
+ -122 common/image.c Can't get configuration for ramdisk subimage
+ 123 common/image.c Ramdisk unit name specified
+ -124 common/image.c Can't get ramdisk subimage node offset
+ 125 common/image.c Got ramdisk subimage node offset
+ -125 common/image.c Ramdisk subimage hash verification failed
+ 126 common/image.c Ramdisk subimage hash verification OK
+ -126 common/image.c Ramdisk subimage for unsupported architecture
+ 127 common/image.c Architecture check OK
+ -127 common/image.c Can't get ramdisk subimage data/size
+ 128 common/image.c Got ramdisk subimage data/size
+ 129 common/image.c Can't get ramdisk load address
+ -129 common/image.c Got ramdisk load address
+
+ -130 common/cmd_doc.c Incorrect FIT image format
+ 131 common/cmd_doc.c FIT image format OK
+
+ -140 common/cmd_ide.c Incorrect FIT image format
+ 141 common/cmd_ide.c FIT image format OK
+
+ -150 common/cmd_nand.c Incorrect FIT image format
+ 151 common/cmd_nand.c FIT image format OK
+
+endmenu
+
+menu "Boot media"
+
+config NOR_BOOT
+ bool "Support for booting from NOR flash"
+ depends on NOR
+ help
+ Enabling this will make a U-Boot binary that is capable of being
+ booted via NOR. In this case we will enable certain pinmux early
+ as the ROM only partially sets up pinmux. We also default to using
+ NOR for environment.
+
+config NAND_BOOT
+ bool "Support for booting from NAND flash"
+ default n
+ imply MTD_RAW_NAND
+ help
+ Enabling this will make a U-Boot binary that is capable of being
+ booted via NAND flash. This is not a must, some SoCs need this,
+ some not.
+
+config ONENAND_BOOT
+ bool "Support for booting from ONENAND"
+ default n
+ imply MTD_RAW_NAND
+ help
+ Enabling this will make a U-Boot binary that is capable of being
+ booted via ONENAND. This is not a must, some SoCs need this,
+ some not.
+
+config QSPI_BOOT
+ bool "Support for booting from QSPI flash"
+ default n
+ help
+ Enabling this will make a U-Boot binary that is capable of being
+ booted via QSPI flash. This is not a must, some SoCs need this,
+ some not.
+
+config SATA_BOOT
+ bool "Support for booting from SATA"
+ default n
+ help
+ Enabling this will make a U-Boot binary that is capable of being
+ booted via SATA. This is not a must, some SoCs need this,
+ some not.
+
+config SD_BOOT
+ bool "Support for booting from SD/EMMC"
+ default n
+ help
+ Enabling this will make a U-Boot binary that is capable of being
+ booted via SD/EMMC. This is not a must, some SoCs need this,
+ some not.
+
+config SPI_BOOT
+ bool "Support for booting from SPI flash"
+ default n
+ help
+ Enabling this will make a U-Boot binary that is capable of being
+ booted via SPI flash. This is not a must, some SoCs need this,
+ some not.
+
+endmenu
+
+menu "Autoboot options"
+
+config AUTOBOOT
+ bool "Autoboot"
+ default y
+ help
+ This enables the autoboot. See doc/README.autoboot for detail.
+
+config BOOTDELAY
+ int "delay in seconds before automatically booting"
+ default 2
+ depends on AUTOBOOT
+ help
+ Delay before automatically running bootcmd;
+ set to 0 to autoboot with no delay, but you can stop it by key input.
+ set to -1 to disable autoboot.
+ set to -2 to autoboot with no delay and not check for abort
+
+ If this value is >= 0 then it is also used for the default delay
+ before starting the default entry in bootmenu. If it is < 0 then
+ a default value of 10s is used.
+
+ See doc/README.autoboot for details.
+
+config AUTOBOOT_KEYED
+ bool "Stop autobooting via specific input key / string"
+ default n
+ help
+ This option enables stopping (aborting) of the automatic
+ boot feature only by issuing a specific input key or
+ string. If not enabled, any input key will abort the
+ U-Boot automatic booting process and bring the device
+ to the U-Boot prompt for user input.
+
+config AUTOBOOT_PROMPT
+ string "Autoboot stop prompt"
+ depends on AUTOBOOT_KEYED
+ default "Autoboot in %d seconds\\n"
+ help
+ This string is displayed before the boot delay selected by
+ CONFIG_BOOTDELAY starts. If it is not defined there is no
+ output indicating that autoboot is in progress.
+
+ Note that this define is used as the (only) argument to a
+ printf() call, so it may contain '%' format specifications,
+ provided that it also includes, sepearated by commas exactly
+ like in a printf statement, the required arguments. It is
+ the responsibility of the user to select only such arguments
+ that are valid in the given context.
+
+config AUTOBOOT_ENCRYPTION
+ bool "Enable encryption in autoboot stopping"
+ depends on AUTOBOOT_KEYED
+ help
+ This option allows a string to be entered into U-Boot to stop the
+ autoboot. The string itself is hashed and compared against the hash
+ in the environment variable 'bootstopkeysha256'. If it matches then
+ boot stops and a command-line prompt is presented.
+
+ This provides a way to ship a secure production device which can also
+ be accessed at the U-Boot command line.
+
+config AUTOBOOT_DELAY_STR
+ string "Delay autobooting via specific input key / string"
+ depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION
+ help
+ This option delays the automatic boot feature by issuing
+ a specific input key or string. If CONFIG_AUTOBOOT_DELAY_STR
+ or the environment variable "bootdelaykey" is specified
+ and this string is received from console input before
+ autoboot starts booting, U-Boot gives a command prompt. The
+ U-Boot prompt will time out if CONFIG_BOOT_RETRY_TIME is
+ used, otherwise it never times out.
+
+config AUTOBOOT_STOP_STR
+ string "Stop autobooting via specific input key / string"
+ depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION
+ help
+ This option enables stopping (aborting) of the automatic
+ boot feature only by issuing a specific input key or
+ string. If CONFIG_AUTOBOOT_STOP_STR or the environment
+ variable "bootstopkey" is specified and this string is
+ received from console input before autoboot starts booting,
+ U-Boot gives a command prompt. The U-Boot prompt never
+ times out, even if CONFIG_BOOT_RETRY_TIME is used.
+
+config AUTOBOOT_KEYED_CTRLC
+ bool "Enable Ctrl-C autoboot interruption"
+ depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION
+ default n
+ help
+ This option allows for the boot sequence to be interrupted
+ by ctrl-c, in addition to the "bootdelaykey" and "bootstopkey".
+ Setting this variable provides an escape sequence from the
+ limited "password" strings.
+
+config AUTOBOOT_STOP_STR_SHA256
+ string "Stop autobooting via SHA256 encrypted password"
+ depends on AUTOBOOT_KEYED && AUTOBOOT_ENCRYPTION
+ help
+ This option adds the feature to only stop the autobooting,
+ and therefore boot into the U-Boot prompt, when the input
+ string / password matches a values that is encypted via
+ a SHA256 hash and saved in the environment variable
+ "bootstopkeysha256". If the value in that variable
+ includes a ":", the portion prior to the ":" will be treated
+ as a salt value.
+
+config AUTOBOOT_USE_MENUKEY
+ bool "Allow a specify key to run a menu from the environment"
+ depends on !AUTOBOOT_KEYED
+ help
+ If a specific key is pressed to stop autoboot, then the commands in
+ the environment variable 'menucmd' are executed before boot starts.
+
+config AUTOBOOT_MENUKEY
+ int "ASCII value of boot key to show a menu"
+ default 0
+ depends on AUTOBOOT_USE_MENUKEY
+ help
+ If this key is pressed to stop autoboot, then the commands in the
+ environment variable 'menucmd' will be executed before boot starts.
+ For example, 33 means "!" in ASCII, so pressing ! at boot would take
+ this action.
+
+config AUTOBOOT_MENU_SHOW
+ bool "Show a menu on boot"
+ depends on CMD_BOOTMENU
+ help
+ This enables the boot menu, controlled by environment variables
+ defined by the board. The menu starts after running the 'preboot'
+ environmnent variable (if enabled) and before handling the boot delay.
+ See README.bootmenu for more details.
+
+endmenu
+
+config USE_BOOTARGS
+ bool "Enable boot arguments"
+ help
+ Provide boot arguments to bootm command. Boot arguments are specified
+ in CONFIG_BOOTARGS option. Enable this option to be able to specify
+ CONFIG_BOOTARGS string. If this option is disabled, CONFIG_BOOTARGS
+ will be undefined and won't take any space in U-Boot image.
+
+config BOOTARGS
+ string "Boot arguments"
+ depends on USE_BOOTARGS && !USE_DEFAULT_ENV_FILE
+ help
+ This can be used to pass arguments to the bootm command. The value of
+ CONFIG_BOOTARGS goes into the environment value "bootargs". Note that
+ this value will also override the "chosen" node in FDT blob.
+
+config BOOTARGS_SUBST
+ bool "Support substituting strings in boot arguments"
+ help
+ This allows substituting string values in the boot arguments. These
+ are applied after the commandline has been built.
+
+ One use for this is to insert the root-disk UUID into the command
+ line where bootargs contains "root=${uuid}"
+
+ setenv bootargs "console= root=${uuid}"
+ # Set the 'uuid' environment variable
+ part uuid mmc 2:2 uuid
+
+ # Command-line substitution will put the real uuid into the
+ # kernel command line
+ bootm
+
+config USE_BOOTCOMMAND
+ bool "Enable a default value for bootcmd"
+ help
+ Provide a default value for the bootcmd entry in the environment. If
+ autoboot is enabled this is what will be run automatically. Enable
+ this option to be able to specify CONFIG_BOOTCOMMAND as a string. If
+ this option is disabled, CONFIG_BOOTCOMMAND will be undefined and
+ won't take any space in U-Boot image.
+
+config BOOTCOMMAND
+ string "bootcmd value"
+ depends on USE_BOOTCOMMAND && !USE_DEFAULT_ENV_FILE
+ default "run distro_bootcmd" if DISTRO_DEFAULTS
+ help
+ This is the string of commands that will be used as bootcmd and if
+ AUTOBOOT is set, automatically run.
+
+config USE_PREBOOT
+ bool "Enable preboot"
+ help
+ When this option is enabled, the existence of the environment
+ variable "preboot" will be checked immediately before starting the
+ CONFIG_BOOTDELAY countdown and/or running the auto-boot command resp.
+ entering interactive mode.
+
+ This feature is especially useful when "preboot" is automatically
+ generated or modified. For example, the boot code can modify the
+ "preboot" when a user holds down a certain combination of keys.
+
+config PREBOOT
+ string "preboot default value"
+ depends on USE_PREBOOT && !USE_DEFAULT_ENV_FILE
+ default "usb start" if USB_KEYBOARD
+ default ""
+ help
+ This is the default of "preboot" environment variable.
+
+config DEFAULT_FDT_FILE
+ string "Default fdt file"
+ help
+ This option is used to set the default fdt file to boot OS.
+
+endmenu # Booting
diff --git a/roms/u-boot/common/Makefile b/roms/u-boot/common/Makefile
new file mode 100644
index 000000000..829ea5fb4
--- /dev/null
+++ b/roms/u-boot/common/Makefile
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2004-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+# core
+ifndef CONFIG_SPL_BUILD
+obj-y += init/
+obj-y += main.o
+obj-y += exports.o
+obj-$(CONFIG_HASH) += hash.o
+obj-$(CONFIG_HUSH_PARSER) += cli_hush.o
+obj-$(CONFIG_AUTOBOOT) += autoboot.o
+
+# This option is not just y/n - it can have a numeric value
+ifdef CONFIG_BOOT_RETRY_TIME
+obj-y += bootretry.o
+endif
+
+# # boards
+obj-y += board_f.o
+obj-y += board_r.o
+obj-$(CONFIG_DISPLAY_BOARDINFO) += board_info.o
+obj-$(CONFIG_DISPLAY_BOARDINFO_LATE) += board_info.o
+
+obj-$(CONFIG_CMD_BOOTM) += bootm.o bootm_os.o
+obj-$(CONFIG_CMD_BOOTZ) += bootm.o bootm_os.o
+obj-$(CONFIG_CMD_BOOTI) += bootm.o bootm_os.o
+
+obj-$(CONFIG_CMD_BEDBUG) += bedbug.o
+obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o
+obj-$(CONFIG_MII) += miiphyutil.o
+obj-$(CONFIG_CMD_MII) += miiphyutil.o
+obj-$(CONFIG_PHYLIB) += miiphyutil.o
+
+ifdef CONFIG_USB
+obj-y += usb.o usb_hub.o
+obj-$(CONFIG_USB_STORAGE) += usb_storage.o
+endif
+
+# others
+obj-$(CONFIG_CONSOLE_MUX) += iomux.o
+obj-$(CONFIG_MTD_NOR_FLASH) += flash.o
+obj-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o
+obj-$(CONFIG_I2C_EDID) += edid.o
+obj-$(CONFIG_KALLSYMS) += kallsyms.o
+obj-y += splash.o
+obj-$(CONFIG_SPLASH_SOURCE) += splash_source.o
+ifndef CONFIG_DM_VIDEO
+obj-$(CONFIG_LCD) += lcd.o lcd_console.o
+endif
+obj-$(CONFIG_LCD_ROTATION) += lcd_console_rotation.o
+obj-$(CONFIG_LCD_DT_SIMPLEFB) += lcd_simplefb.o
+obj-$(CONFIG_LYNXKDI) += lynxkdi.o
+obj-$(CONFIG_MENU) += menu.o
+obj-$(CONFIG_UPDATE_COMMON) += update.o
+obj-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
+obj-$(CONFIG_CMDLINE) += cli_readline.o cli_simple.o
+
+endif # !CONFIG_SPL_BUILD
+
+obj-$(CONFIG_$(SPL_TPL_)BOOTSTAGE) += bootstage.o
+obj-$(CONFIG_$(SPL_TPL_)BLOBLIST) += bloblist.o
+
+ifdef CONFIG_SPL_BUILD
+ifdef CONFIG_SPL_DFU
+obj-$(CONFIG_DFU_OVER_USB) += dfu.o
+endif
+obj-$(CONFIG_SPL_HASH_SUPPORT) += hash.o
+obj-$(CONFIG_TPL_HASH_SUPPORT) += hash.o
+obj-$(CONFIG_SPL_LOAD_FIT) += common_fit.o
+obj-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
+obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o
+
+ifdef CONFIG_SPL_USB_HOST_SUPPORT
+obj-y += usb.o
+obj-y += usb_hub.o
+obj-$(CONFIG_SPL_USB_STORAGE) += usb_storage.o
+else
+obj-$(CONFIG_USB_MUSB_HOST) += usb.o
+endif
+endif # CONFIG_SPL_BUILD
+
+#others
+obj-$(CONFIG_DDR_SPD) += ddr_spd.o
+obj-$(CONFIG_SPD_EEPROM) += ddr_spd.o
+obj-$(CONFIG_HWCONFIG) += hwconfig.o
+obj-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o
+ifdef CONFIG_SPL_BUILD
+ifdef CONFIG_TPL_BUILD
+obj-$(CONFIG_TPL_SERIAL_SUPPORT) += console.o
+else
+obj-$(CONFIG_SPL_SERIAL_SUPPORT) += console.o
+endif
+else
+obj-y += console.o
+endif # CONFIG_SPL_BUILD
+
+obj-$(CONFIG_CROS_EC) += cros_ec.o
+obj-y += dlmalloc.o
+ifdef CONFIG_SYS_MALLOC_F
+ifneq ($(CONFIG_$(SPL_TPL_)SYS_MALLOC_F_LEN),0)
+obj-y += malloc_simple.o
+endif
+endif
+
+obj-y += image.o
+obj-$(CONFIG_ANDROID_AB) += android_ab.o
+obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o
+obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
+obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o
+obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
+obj-$(CONFIG_$(SPL_)MULTI_DTB_FIT) += boot_fit.o common_fit.o
+obj-$(CONFIG_$(SPL_TPL_)IMAGE_SIGN_INFO) += image-sig.o
+obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += image-fit-sig.o
+obj-$(CONFIG_$(SPL_TPL_)FIT_CIPHER) += image-cipher.o
+obj-$(CONFIG_IO_TRACE) += iotrace.o
+obj-y += memsize.o
+obj-y += stdio.o
+
+obj-$(CONFIG_CMD_ADTIMG) += image-android-dt.o
+
+ifdef CONFIG_CMD_EEPROM_LAYOUT
+obj-y += eeprom/eeprom_field.o eeprom/eeprom_layout.o
+endif
+
+obj-y += cli.o
+obj-$(CONFIG_FSL_DDR_INTERACTIVE) += cli_simple.o cli_readline.o
+obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += cli_simple.o cli_readline.o
+obj-$(CONFIG_DFU_OVER_USB) += dfu.o
+obj-y += command.o
+obj-$(CONFIG_$(SPL_TPL_)LOG) += log.o
+obj-$(CONFIG_$(SPL_TPL_)LOG_CONSOLE) += log_console.o
+obj-$(CONFIG_$(SPL_TPL_)LOG_SYSLOG) += log_syslog.o
+obj-y += s_record.o
+obj-$(CONFIG_CMD_LOADB) += xyzModem.o
+obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o
+
+obj-$(CONFIG_AVB_VERIFY) += avb_verify.o
+obj-$(CONFIG_$(SPL_TPL_)STACKPROTECTOR) += stackprot.o
+obj-$(CONFIG_SCP03) += scp03.o
+
+obj-$(CONFIG_QFW) += qfw.o
diff --git a/roms/u-boot/common/android_ab.c b/roms/u-boot/common/android_ab.c
new file mode 100644
index 000000000..4943f26d5
--- /dev/null
+++ b/roms/u-boot/common/android_ab.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ */
+#include <common.h>
+#include <android_ab.h>
+#include <android_bootloader_message.h>
+#include <blk.h>
+#include <log.h>
+#include <malloc.h>
+#include <part.h>
+#include <memalign.h>
+#include <linux/err.h>
+#include <u-boot/crc.h>
+#include <u-boot/crc.h>
+
+/**
+ * Compute the CRC-32 of the bootloader control struct.
+ *
+ * Only the bytes up to the crc32_le field are considered for the CRC-32
+ * calculation.
+ *
+ * @param[in] abc bootloader control block
+ *
+ * @return crc32 sum
+ */
+static uint32_t ab_control_compute_crc(struct bootloader_control *abc)
+{
+ return crc32(0, (void *)abc, offsetof(typeof(*abc), crc32_le));
+}
+
+/**
+ * Initialize bootloader_control to the default value.
+ *
+ * It allows us to boot all slots in order from the first one. This value
+ * should be used when the bootloader message is corrupted, but not when
+ * a valid message indicates that all slots are unbootable.
+ *
+ * @param[in] abc bootloader control block
+ *
+ * @return 0 on success and a negative on error
+ */
+static int ab_control_default(struct bootloader_control *abc)
+{
+ int i;
+ const struct slot_metadata metadata = {
+ .priority = 15,
+ .tries_remaining = 7,
+ .successful_boot = 0,
+ .verity_corrupted = 0,
+ .reserved = 0
+ };
+
+ if (!abc)
+ return -EFAULT;
+
+ memcpy(abc->slot_suffix, "a\0\0\0", 4);
+ abc->magic = BOOT_CTRL_MAGIC;
+ abc->version = BOOT_CTRL_VERSION;
+ abc->nb_slot = NUM_SLOTS;
+ memset(abc->reserved0, 0, sizeof(abc->reserved0));
+ for (i = 0; i < abc->nb_slot; ++i)
+ abc->slot_info[i] = metadata;
+
+ memset(abc->reserved1, 0, sizeof(abc->reserved1));
+ abc->crc32_le = ab_control_compute_crc(abc);
+
+ return 0;
+}
+
+/**
+ * Load the boot_control struct from disk into newly allocated memory.
+ *
+ * This function allocates and returns an integer number of disk blocks,
+ * based on the block size of the passed device to help performing a
+ * read-modify-write operation on the boot_control struct.
+ * The boot_control struct offset (2 KiB) must be a multiple of the device
+ * block size, for simplicity.
+ *
+ * @param[in] dev_desc Device where to read the boot_control struct from
+ * @param[in] part_info Partition in 'dev_desc' where to read from, normally
+ * the "misc" partition should be used
+ * @param[out] pointer to pointer to bootloader_control data
+ * @return 0 on success and a negative on error
+ */
+static int ab_control_create_from_disk(struct blk_desc *dev_desc,
+ const struct disk_partition *part_info,
+ struct bootloader_control **abc)
+{
+ ulong abc_offset, abc_blocks, ret;
+
+ abc_offset = offsetof(struct bootloader_message_ab, slot_suffix);
+ if (abc_offset % part_info->blksz) {
+ log_err("ANDROID: Boot control block not block aligned.\n");
+ return -EINVAL;
+ }
+ abc_offset /= part_info->blksz;
+
+ abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
+ part_info->blksz);
+ if (abc_offset + abc_blocks > part_info->size) {
+ log_err("ANDROID: boot control partition too small. Need at");
+ log_err(" least %lu blocks but have %lu blocks.\n",
+ abc_offset + abc_blocks, part_info->size);
+ return -EINVAL;
+ }
+ *abc = malloc_cache_aligned(abc_blocks * part_info->blksz);
+ if (!*abc)
+ return -ENOMEM;
+
+ ret = blk_dread(dev_desc, part_info->start + abc_offset, abc_blocks,
+ *abc);
+ if (IS_ERR_VALUE(ret)) {
+ log_err("ANDROID: Could not read from boot ctrl partition\n");
+ free(*abc);
+ return -EIO;
+ }
+
+ log_debug("ANDROID: Loaded ABC, %lu blocks\n", abc_blocks);
+
+ return 0;
+}
+
+/**
+ * Store the loaded boot_control block.
+ *
+ * Store back to the same location it was read from with
+ * ab_control_create_from_misc().
+ *
+ * @param[in] dev_desc Device where we should write the boot_control struct
+ * @param[in] part_info Partition on the 'dev_desc' where to write
+ * @param[in] abc Pointer to the boot control struct and the extra bytes after
+ * it up to the nearest block boundary
+ * @return 0 on success and a negative on error
+ */
+static int ab_control_store(struct blk_desc *dev_desc,
+ const struct disk_partition *part_info,
+ struct bootloader_control *abc)
+{
+ ulong abc_offset, abc_blocks, ret;
+
+ abc_offset = offsetof(struct bootloader_message_ab, slot_suffix) /
+ part_info->blksz;
+ abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
+ part_info->blksz);
+ ret = blk_dwrite(dev_desc, part_info->start + abc_offset, abc_blocks,
+ abc);
+ if (IS_ERR_VALUE(ret)) {
+ log_err("ANDROID: Could not write back the misc partition\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * Compare two slots.
+ *
+ * The function determines slot which is should we boot from among the two.
+ *
+ * @param[in] a The first bootable slot metadata
+ * @param[in] b The second bootable slot metadata
+ * @return Negative if the slot "a" is better, positive of the slot "b" is
+ * better or 0 if they are equally good.
+ */
+static int ab_compare_slots(const struct slot_metadata *a,
+ const struct slot_metadata *b)
+{
+ /* Higher priority is better */
+ if (a->priority != b->priority)
+ return b->priority - a->priority;
+
+ /* Higher successful_boot value is better, in case of same priority */
+ if (a->successful_boot != b->successful_boot)
+ return b->successful_boot - a->successful_boot;
+
+ /* Higher tries_remaining is better to ensure round-robin */
+ if (a->tries_remaining != b->tries_remaining)
+ return b->tries_remaining - a->tries_remaining;
+
+ return 0;
+}
+
+int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info)
+{
+ struct bootloader_control *abc = NULL;
+ u32 crc32_le;
+ int slot, i, ret;
+ bool store_needed = false;
+ char slot_suffix[4];
+
+ ret = ab_control_create_from_disk(dev_desc, part_info, &abc);
+ if (ret < 0) {
+ /*
+ * This condition represents an actual problem with the code or
+ * the board setup, like an invalid partition information.
+ * Signal a repair mode and do not try to boot from either slot.
+ */
+ return ret;
+ }
+
+ crc32_le = ab_control_compute_crc(abc);
+ if (abc->crc32_le != crc32_le) {
+ log_err("ANDROID: Invalid CRC-32 (expected %.8x, found %.8x),",
+ crc32_le, abc->crc32_le);
+ log_err("re-initializing A/B metadata.\n");
+
+ ret = ab_control_default(abc);
+ if (ret < 0) {
+ free(abc);
+ return -ENODATA;
+ }
+ store_needed = true;
+ }
+
+ if (abc->magic != BOOT_CTRL_MAGIC) {
+ log_err("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic);
+ free(abc);
+ return -ENODATA;
+ }
+
+ if (abc->version > BOOT_CTRL_VERSION) {
+ log_err("ANDROID: Unsupported A/B metadata version: %.8x\n",
+ abc->version);
+ free(abc);
+ return -ENODATA;
+ }
+
+ /*
+ * At this point a valid boot control metadata is stored in abc,
+ * followed by other reserved data in the same block. We select a with
+ * the higher priority slot that
+ * - is not marked as corrupted and
+ * - either has tries_remaining > 0 or successful_boot is true.
+ * If the selected slot has a false successful_boot, we also decrement
+ * the tries_remaining until it eventually becomes unbootable because
+ * tries_remaining reaches 0. This mechanism produces a bootloader
+ * induced rollback, typically right after a failed update.
+ */
+
+ /* Safety check: limit the number of slots. */
+ if (abc->nb_slot > ARRAY_SIZE(abc->slot_info)) {
+ abc->nb_slot = ARRAY_SIZE(abc->slot_info);
+ store_needed = true;
+ }
+
+ slot = -1;
+ for (i = 0; i < abc->nb_slot; ++i) {
+ if (abc->slot_info[i].verity_corrupted ||
+ !abc->slot_info[i].tries_remaining) {
+ log_debug("ANDROID: unbootable slot %d tries: %d, ",
+ i, abc->slot_info[i].tries_remaining);
+ log_debug("corrupt: %d\n",
+ abc->slot_info[i].verity_corrupted);
+ continue;
+ }
+ log_debug("ANDROID: bootable slot %d pri: %d, tries: %d, ",
+ i, abc->slot_info[i].priority,
+ abc->slot_info[i].tries_remaining);
+ log_debug("corrupt: %d, successful: %d\n",
+ abc->slot_info[i].verity_corrupted,
+ abc->slot_info[i].successful_boot);
+
+ if (slot < 0 ||
+ ab_compare_slots(&abc->slot_info[i],
+ &abc->slot_info[slot]) < 0) {
+ slot = i;
+ }
+ }
+
+ if (slot >= 0 && !abc->slot_info[slot].successful_boot) {
+ log_err("ANDROID: Attempting slot %c, tries remaining %d\n",
+ BOOT_SLOT_NAME(slot),
+ abc->slot_info[slot].tries_remaining);
+ abc->slot_info[slot].tries_remaining--;
+ store_needed = true;
+ }
+
+ if (slot >= 0) {
+ /*
+ * Legacy user-space requires this field to be set in the BCB.
+ * Newer releases load this slot suffix from the command line
+ * or the device tree.
+ */
+ memset(slot_suffix, 0, sizeof(slot_suffix));
+ slot_suffix[0] = BOOT_SLOT_NAME(slot);
+ if (memcmp(abc->slot_suffix, slot_suffix,
+ sizeof(slot_suffix))) {
+ memcpy(abc->slot_suffix, slot_suffix,
+ sizeof(slot_suffix));
+ store_needed = true;
+ }
+ }
+
+ if (store_needed) {
+ abc->crc32_le = ab_control_compute_crc(abc);
+ ab_control_store(dev_desc, part_info, abc);
+ }
+ free(abc);
+
+ if (slot < 0)
+ return -EINVAL;
+
+ return slot;
+}
diff --git a/roms/u-boot/common/autoboot.c b/roms/u-boot/common/autoboot.c
new file mode 100644
index 000000000..b42148c72
--- /dev/null
+++ b/roms/u-boot/common/autoboot.c
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <common.h>
+#include <autoboot.h>
+#include <bootretry.h>
+#include <cli.h>
+#include <command.h>
+#include <console.h>
+#include <env.h>
+#include <fdtdec.h>
+#include <hash.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <menu.h>
+#include <post.h>
+#include <time.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+#include <u-boot/sha256.h>
+#include <bootcount.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MAX_DELAY_STOP_STR 64
+
+#ifndef DEBUG_BOOTKEYS
+#define DEBUG_BOOTKEYS 0
+#endif
+#define debug_bootkeys(fmt, args...) \
+ debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
+
+/* Stored value of bootdelay, used by autoboot_command() */
+static int stored_bootdelay;
+static int menukey;
+
+#ifdef CONFIG_AUTOBOOT_ENCRYPTION
+#define AUTOBOOT_STOP_STR_SHA256 CONFIG_AUTOBOOT_STOP_STR_SHA256
+#else
+#define AUTOBOOT_STOP_STR_SHA256 ""
+#endif
+
+#ifdef CONFIG_AUTOBOOT_USE_MENUKEY
+#define AUTOBOOT_MENUKEY CONFIG_AUTOBOOT_MENUKEY
+#else
+#define AUTOBOOT_MENUKEY 0
+#endif
+
+/*
+ * Use a "constant-length" time compare function for this
+ * hash compare:
+ *
+ * https://crackstation.net/hashing-security.htm
+ */
+static int slow_equals(u8 *a, u8 *b, int len)
+{
+ int diff = 0;
+ int i;
+
+ for (i = 0; i < len; i++)
+ diff |= a[i] ^ b[i];
+
+ return diff == 0;
+}
+
+/**
+ * passwd_abort_sha256() - check for a hashed key sequence to abort booting
+ *
+ * This checks for the user entering a SHA256 hash within a given time.
+ *
+ * @etime: Timeout value ticks (stop when get_ticks() reachs this)
+ * @return 0 if autoboot should continue, 1 if it should stop
+ */
+static int passwd_abort_sha256(uint64_t etime)
+{
+ const char *sha_env_str = env_get("bootstopkeysha256");
+ u8 sha_env[SHA256_SUM_LEN];
+ u8 *sha;
+ char *presskey;
+ char *c;
+ const char *algo_name = "sha256";
+ u_int presskey_len = 0;
+ int abort = 0;
+ int size = sizeof(sha);
+ int ret;
+
+ if (sha_env_str == NULL)
+ sha_env_str = AUTOBOOT_STOP_STR_SHA256;
+
+ presskey = malloc_cache_aligned(MAX_DELAY_STOP_STR);
+ c = strstr(sha_env_str, ":");
+ if (c && (c - sha_env_str < MAX_DELAY_STOP_STR)) {
+ /* preload presskey with salt */
+ memcpy(presskey, sha_env_str, c - sha_env_str);
+ presskey_len = c - sha_env_str;
+ sha_env_str = c + 1;
+ }
+ /*
+ * Generate the binary value from the environment hash value
+ * so that we can compare this value with the computed hash
+ * from the user input
+ */
+ ret = hash_parse_string(algo_name, sha_env_str, sha_env);
+ if (ret) {
+ printf("Hash %s not supported!\n", algo_name);
+ return 0;
+ }
+
+ sha = malloc_cache_aligned(SHA256_SUM_LEN);
+ size = SHA256_SUM_LEN;
+ /*
+ * We don't know how long the stop-string is, so we need to
+ * generate the sha256 hash upon each input character and
+ * compare the value with the one saved in the environment
+ */
+ do {
+ if (tstc()) {
+ /* Check for input string overflow */
+ if (presskey_len >= MAX_DELAY_STOP_STR) {
+ free(presskey);
+ free(sha);
+ return 0;
+ }
+
+ presskey[presskey_len++] = getchar();
+
+ /* Calculate sha256 upon each new char */
+ hash_block(algo_name, (const void *)presskey,
+ presskey_len, sha, &size);
+
+ /* And check if sha matches saved value in env */
+ if (slow_equals(sha, sha_env, SHA256_SUM_LEN))
+ abort = 1;
+ }
+ } while (!abort && get_ticks() <= etime);
+
+ free(presskey);
+ free(sha);
+ return abort;
+}
+
+/**
+ * passwd_abort_key() - check for a key sequence to aborted booting
+ *
+ * This checks for the user entering a string within a given time.
+ *
+ * @etime: Timeout value ticks (stop when get_ticks() reachs this)
+ * @return 0 if autoboot should continue, 1 if it should stop
+ */
+static int passwd_abort_key(uint64_t etime)
+{
+ int abort = 0;
+ struct {
+ char *str;
+ u_int len;
+ int retry;
+ }
+ delaykey[] = {
+ { .str = env_get("bootdelaykey"), .retry = 1 },
+ { .str = env_get("bootstopkey"), .retry = 0 },
+ };
+
+ char presskey[MAX_DELAY_STOP_STR];
+ int presskey_len = 0;
+ int presskey_max = 0;
+ int i;
+
+# ifdef CONFIG_AUTOBOOT_DELAY_STR
+ if (delaykey[0].str == NULL)
+ delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
+# endif
+# ifdef CONFIG_AUTOBOOT_STOP_STR
+ if (delaykey[1].str == NULL)
+ delaykey[1].str = CONFIG_AUTOBOOT_STOP_STR;
+# endif
+
+ for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
+ delaykey[i].len = delaykey[i].str == NULL ?
+ 0 : strlen(delaykey[i].str);
+ delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
+ MAX_DELAY_STOP_STR : delaykey[i].len;
+
+ presskey_max = presskey_max > delaykey[i].len ?
+ presskey_max : delaykey[i].len;
+
+ debug_bootkeys("%s key:<%s>\n",
+ delaykey[i].retry ? "delay" : "stop",
+ delaykey[i].str ? delaykey[i].str : "NULL");
+ }
+
+ /* In order to keep up with incoming data, check timeout only
+ * when catch up.
+ */
+ do {
+ if (tstc()) {
+ if (presskey_len < presskey_max) {
+ presskey[presskey_len++] = getchar();
+ } else {
+ for (i = 0; i < presskey_max - 1; i++)
+ presskey[i] = presskey[i + 1];
+
+ presskey[i] = getchar();
+ }
+ }
+
+ for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
+ if (delaykey[i].len > 0 &&
+ presskey_len >= delaykey[i].len &&
+ memcmp(presskey + presskey_len -
+ delaykey[i].len, delaykey[i].str,
+ delaykey[i].len) == 0) {
+ debug_bootkeys("got %skey\n",
+ delaykey[i].retry ? "delay" :
+ "stop");
+
+ /* don't retry auto boot */
+ if (!delaykey[i].retry)
+ bootretry_dont_retry();
+ abort = 1;
+ }
+ }
+ } while (!abort && get_ticks() <= etime);
+
+ return abort;
+}
+
+/***************************************************************************
+ * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
+ * returns: 0 - no key string, allow autoboot 1 - got key string, abort
+ */
+static int abortboot_key_sequence(int bootdelay)
+{
+ int abort;
+ uint64_t etime = endtick(bootdelay);
+
+# ifdef CONFIG_AUTOBOOT_PROMPT
+ /*
+ * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards.
+ * To print the bootdelay value upon bootup.
+ */
+ printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
+# endif
+
+ if (IS_ENABLED(CONFIG_AUTOBOOT_ENCRYPTION))
+ abort = passwd_abort_sha256(etime);
+ else
+ abort = passwd_abort_key(etime);
+ if (!abort)
+ debug_bootkeys("key timeout\n");
+
+ return abort;
+}
+
+static int abortboot_single_key(int bootdelay)
+{
+ int abort = 0;
+ unsigned long ts;
+
+ printf("Hit any key to stop autoboot: %2d ", bootdelay);
+
+ /*
+ * Check if key already pressed
+ */
+ if (tstc()) { /* we got a key press */
+ getchar(); /* consume input */
+ puts("\b\b\b 0");
+ abort = 1; /* don't auto boot */
+ }
+
+ while ((bootdelay > 0) && (!abort)) {
+ --bootdelay;
+ /* delay 1000 ms */
+ ts = get_timer(0);
+ do {
+ if (tstc()) { /* we got a key press */
+ int key;
+
+ abort = 1; /* don't auto boot */
+ bootdelay = 0; /* no more delay */
+ key = getchar();/* consume input */
+ if (IS_ENABLED(CONFIG_AUTOBOOT_USE_MENUKEY))
+ menukey = key;
+ break;
+ }
+ udelay(10000);
+ } while (!abort && get_timer(ts) < 1000);
+
+ printf("\b\b\b%2d ", bootdelay);
+ }
+
+ putc('\n');
+
+ return abort;
+}
+
+static int abortboot(int bootdelay)
+{
+ int abort = 0;
+
+ if (bootdelay >= 0) {
+ if (IS_ENABLED(CONFIG_AUTOBOOT_KEYED))
+ abort = abortboot_key_sequence(bootdelay);
+ else
+ abort = abortboot_single_key(bootdelay);
+ }
+
+ if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && abort)
+ gd->flags &= ~GD_FLG_SILENT;
+
+ return abort;
+}
+
+static void process_fdt_options(const void *blob)
+{
+#ifdef CONFIG_SYS_TEXT_BASE
+ ulong addr;
+
+ /* Add an env variable to point to a kernel payload, if available */
+ addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
+ if (addr)
+ env_set_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
+
+ /* Add an env variable to point to a root disk, if available */
+ addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
+ if (addr)
+ env_set_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
+#endif /* CONFIG_SYS_TEXT_BASE */
+}
+
+const char *bootdelay_process(void)
+{
+ char *s;
+ int bootdelay;
+
+ bootcount_inc();
+
+ s = env_get("bootdelay");
+ bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
+
+ if (IS_ENABLED(CONFIG_OF_CONTROL))
+ bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
+ bootdelay);
+
+ debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
+
+ if (IS_ENABLED(CONFIG_AUTOBOOT_MENU_SHOW))
+ bootdelay = menu_show(bootdelay);
+ bootretry_init_cmd_timeout();
+
+#ifdef CONFIG_POST
+ if (gd->flags & GD_FLG_POSTFAIL) {
+ s = env_get("failbootcmd");
+ } else
+#endif /* CONFIG_POST */
+ if (bootcount_error())
+ s = env_get("altbootcmd");
+ else
+ s = env_get("bootcmd");
+
+ if (IS_ENABLED(CONFIG_OF_CONTROL))
+ process_fdt_options(gd->fdt_blob);
+ stored_bootdelay = bootdelay;
+
+ return s;
+}
+
+void autoboot_command(const char *s)
+{
+ debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
+
+ if (s && (stored_bootdelay == -2 ||
+ (stored_bootdelay != -1 && !abortboot(stored_bootdelay)))) {
+ bool lock;
+ int prev;
+
+ lock = IS_ENABLED(CONFIG_AUTOBOOT_KEYED) &&
+ !IS_ENABLED(CONFIG_AUTOBOOT_KEYED_CTRLC);
+ if (lock)
+ prev = disable_ctrlc(1); /* disable Ctrl-C checking */
+
+ run_command_list(s, -1, 0);
+
+ if (lock)
+ disable_ctrlc(prev); /* restore Ctrl-C checking */
+ }
+
+ if (IS_ENABLED(CONFIG_AUTOBOOT_USE_MENUKEY) &&
+ menukey == AUTOBOOT_MENUKEY) {
+ s = env_get("menucmd");
+ if (s)
+ run_command_list(s, -1, 0);
+ }
+}
diff --git a/roms/u-boot/common/avb_verify.c b/roms/u-boot/common/avb_verify.c
new file mode 100644
index 000000000..0520a7145
--- /dev/null
+++ b/roms/u-boot/common/avb_verify.c
@@ -0,0 +1,1023 @@
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <avb_verify.h>
+#include <blk.h>
+#include <cpu_func.h>
+#include <image.h>
+#include <malloc.h>
+#include <part.h>
+#include <tee.h>
+#include <tee/optee_ta_avb.h>
+
+static const unsigned char avb_root_pub[1032] = {
+ 0x0, 0x0, 0x10, 0x0, 0x55, 0xd9, 0x4, 0xad, 0xd8, 0x4,
+ 0xaf, 0xe3, 0xd3, 0x84, 0x6c, 0x7e, 0xd, 0x89, 0x3d, 0xc2,
+ 0x8c, 0xd3, 0x12, 0x55, 0xe9, 0x62, 0xc9, 0xf1, 0xf, 0x5e,
+ 0xcc, 0x16, 0x72, 0xab, 0x44, 0x7c, 0x2c, 0x65, 0x4a, 0x94,
+ 0xb5, 0x16, 0x2b, 0x0, 0xbb, 0x6, 0xef, 0x13, 0x7, 0x53,
+ 0x4c, 0xf9, 0x64, 0xb9, 0x28, 0x7a, 0x1b, 0x84, 0x98, 0x88,
+ 0xd8, 0x67, 0xa4, 0x23, 0xf9, 0xa7, 0x4b, 0xdc, 0x4a, 0xf,
+ 0xf7, 0x3a, 0x18, 0xae, 0x54, 0xa8, 0x15, 0xfe, 0xb0, 0xad,
+ 0xac, 0x35, 0xda, 0x3b, 0xad, 0x27, 0xbc, 0xaf, 0xe8, 0xd3,
+ 0x2f, 0x37, 0x34, 0xd6, 0x51, 0x2b, 0x6c, 0x5a, 0x27, 0xd7,
+ 0x96, 0x6, 0xaf, 0x6b, 0xb8, 0x80, 0xca, 0xfa, 0x30, 0xb4,
+ 0xb1, 0x85, 0xb3, 0x4d, 0xaa, 0xaa, 0xc3, 0x16, 0x34, 0x1a,
+ 0xb8, 0xe7, 0xc7, 0xfa, 0xf9, 0x9, 0x77, 0xab, 0x97, 0x93,
+ 0xeb, 0x44, 0xae, 0xcf, 0x20, 0xbc, 0xf0, 0x80, 0x11, 0xdb,
+ 0x23, 0xc, 0x47, 0x71, 0xb9, 0x6d, 0xd6, 0x7b, 0x60, 0x47,
+ 0x87, 0x16, 0x56, 0x93, 0xb7, 0xc2, 0x2a, 0x9a, 0xb0, 0x4c,
+ 0x1, 0xc, 0x30, 0xd8, 0x93, 0x87, 0xf0, 0xed, 0x6e, 0x8b,
+ 0xbe, 0x30, 0x5b, 0xf6, 0xa6, 0xaf, 0xdd, 0x80, 0x7c, 0x45,
+ 0x5e, 0x8f, 0x91, 0x93, 0x5e, 0x44, 0xfe, 0xb8, 0x82, 0x7,
+ 0xee, 0x79, 0xca, 0xbf, 0x31, 0x73, 0x62, 0x58, 0xe3, 0xcd,
+ 0xc4, 0xbc, 0xc2, 0x11, 0x1d, 0xa1, 0x4a, 0xbf, 0xfe, 0x27,
+ 0x7d, 0xa1, 0xf6, 0x35, 0xa3, 0x5e, 0xca, 0xdc, 0x57, 0x2f,
+ 0x3e, 0xf0, 0xc9, 0x5d, 0x86, 0x6a, 0xf8, 0xaf, 0x66, 0xa7,
+ 0xed, 0xcd, 0xb8, 0xed, 0xa1, 0x5f, 0xba, 0x9b, 0x85, 0x1a,
+ 0xd5, 0x9, 0xae, 0x94, 0x4e, 0x3b, 0xcf, 0xcb, 0x5c, 0xc9,
+ 0x79, 0x80, 0xf7, 0xcc, 0xa6, 0x4a, 0xa8, 0x6a, 0xd8, 0xd3,
+ 0x31, 0x11, 0xf9, 0xf6, 0x2, 0x63, 0x2a, 0x1a, 0x2d, 0xd1,
+ 0x1a, 0x66, 0x1b, 0x16, 0x41, 0xbd, 0xbd, 0xf7, 0x4d, 0xc0,
+ 0x4a, 0xe5, 0x27, 0x49, 0x5f, 0x7f, 0x58, 0xe3, 0x27, 0x2d,
+ 0xe5, 0xc9, 0x66, 0xe, 0x52, 0x38, 0x16, 0x38, 0xfb, 0x16,
+ 0xeb, 0x53, 0x3f, 0xe6, 0xfd, 0xe9, 0xa2, 0x5e, 0x25, 0x59,
+ 0xd8, 0x79, 0x45, 0xff, 0x3, 0x4c, 0x26, 0xa2, 0x0, 0x5a,
+ 0x8e, 0xc2, 0x51, 0xa1, 0x15, 0xf9, 0x7b, 0xf4, 0x5c, 0x81,
+ 0x9b, 0x18, 0x47, 0x35, 0xd8, 0x2d, 0x5, 0xe9, 0xad, 0xf,
+ 0x35, 0x74, 0x15, 0xa3, 0x8e, 0x8b, 0xcc, 0x27, 0xda, 0x7c,
+ 0x5d, 0xe4, 0xfa, 0x4, 0xd3, 0x5, 0xb, 0xba, 0x3a, 0xb2,
+ 0x49, 0x45, 0x2f, 0x47, 0xc7, 0xd, 0x41, 0x3f, 0x97, 0x80,
+ 0x4d, 0x3f, 0xc1, 0xb5, 0xbb, 0x70, 0x5f, 0xa7, 0x37, 0xaf,
+ 0x48, 0x22, 0x12, 0x45, 0x2e, 0xf5, 0xf, 0x87, 0x92, 0xe2,
+ 0x84, 0x1, 0xf9, 0x12, 0xf, 0x14, 0x15, 0x24, 0xce, 0x89,
+ 0x99, 0xee, 0xb9, 0xc4, 0x17, 0x70, 0x70, 0x15, 0xea, 0xbe,
+ 0xc6, 0x6c, 0x1f, 0x62, 0xb3, 0xf4, 0x2d, 0x16, 0x87, 0xfb,
+ 0x56, 0x1e, 0x45, 0xab, 0xae, 0x32, 0xe4, 0x5e, 0x91, 0xed,
+ 0x53, 0x66, 0x5e, 0xbd, 0xed, 0xad, 0xe6, 0x12, 0x39, 0xd,
+ 0x83, 0xc9, 0xe8, 0x6b, 0x6c, 0x2d, 0xa5, 0xee, 0xc4, 0x5a,
+ 0x66, 0xae, 0x8c, 0x97, 0xd7, 0xd, 0x6c, 0x49, 0xc7, 0xf5,
+ 0xc4, 0x92, 0x31, 0x8b, 0x9, 0xee, 0x33, 0xda, 0xa9, 0x37,
+ 0xb6, 0x49, 0x18, 0xf8, 0xe, 0x60, 0x45, 0xc8, 0x33, 0x91,
+ 0xef, 0x20, 0x57, 0x10, 0xbe, 0x78, 0x2d, 0x83, 0x26, 0xd6,
+ 0xca, 0x61, 0xf9, 0x2f, 0xe0, 0xbf, 0x5, 0x30, 0x52, 0x5a,
+ 0x12, 0x1c, 0x0, 0xa7, 0x5d, 0xcc, 0x7c, 0x2e, 0xc5, 0x95,
+ 0x8b, 0xa3, 0x3b, 0xf0, 0x43, 0x2e, 0x5e, 0xdd, 0x0, 0xdb,
+ 0xd, 0xb3, 0x37, 0x99, 0xa9, 0xcd, 0x9c, 0xb7, 0x43, 0xf7,
+ 0x35, 0x44, 0x21, 0xc2, 0x82, 0x71, 0xab, 0x8d, 0xaa, 0xb4,
+ 0x41, 0x11, 0xec, 0x1e, 0x8d, 0xfc, 0x14, 0x82, 0x92, 0x4e,
+ 0x83, 0x6a, 0xa, 0x6b, 0x35, 0x5e, 0x5d, 0xe9, 0x5c, 0xcc,
+ 0x8c, 0xde, 0x39, 0xd1, 0x4a, 0x5b, 0x5f, 0x63, 0xa9, 0x64,
+ 0xe0, 0xa, 0xcb, 0xb, 0xb8, 0x5a, 0x7c, 0xc3, 0xb, 0xe6,
+ 0xbe, 0xfe, 0x8b, 0xf, 0x7d, 0x34, 0x8e, 0x2, 0x66, 0x74,
+ 0x1, 0x6c, 0xca, 0x76, 0xac, 0x7c, 0x67, 0x8, 0x2f, 0x3f,
+ 0x1a, 0xa6, 0x2c, 0x60, 0xb3, 0xff, 0xda, 0x8d, 0xb8, 0x12,
+ 0xc, 0x0, 0x7f, 0xcc, 0x50, 0xa1, 0x5c, 0x64, 0xa1, 0xe2,
+ 0x5f, 0x32, 0x65, 0xc9, 0x9c, 0xbe, 0xd6, 0xa, 0x13, 0x87,
+ 0x3c, 0x2a, 0x45, 0x47, 0xc, 0xca, 0x42, 0x82, 0xfa, 0x89,
+ 0x65, 0xe7, 0x89, 0xb4, 0x8f, 0xf7, 0x1e, 0xe6, 0x23, 0xa5,
+ 0xd0, 0x59, 0x37, 0x79, 0x92, 0xd7, 0xce, 0x3d, 0xfd, 0xe3,
+ 0xa1, 0xb, 0xcf, 0x6c, 0x85, 0xa0, 0x65, 0xf3, 0x5c, 0xc6,
+ 0x4a, 0x63, 0x5f, 0x6e, 0x3a, 0x3a, 0x2a, 0x8b, 0x6a, 0xb6,
+ 0x2f, 0xbb, 0xf8, 0xb2, 0x4b, 0x62, 0xbc, 0x1a, 0x91, 0x25,
+ 0x66, 0xe3, 0x69, 0xca, 0x60, 0x49, 0xb, 0xf6, 0x8a, 0xbe,
+ 0x3e, 0x76, 0x53, 0xc2, 0x7a, 0xa8, 0x4, 0x17, 0x75, 0xf1,
+ 0xf3, 0x3, 0x62, 0x1b, 0x85, 0xb2, 0xb0, 0xef, 0x80, 0x15,
+ 0xb6, 0xd4, 0x4e, 0xdf, 0x71, 0xac, 0xdb, 0x2a, 0x4, 0xd4,
+ 0xb4, 0x21, 0xba, 0x65, 0x56, 0x57, 0xe8, 0xfa, 0x84, 0xa2,
+ 0x7d, 0x13, 0xe, 0xaf, 0xd7, 0x9a, 0x58, 0x2a, 0xa3, 0x81,
+ 0x84, 0x8d, 0x9, 0xa0, 0x6a, 0xc1, 0xbb, 0xd9, 0xf5, 0x86,
+ 0xac, 0xbd, 0x75, 0x61, 0x9, 0xe6, 0x8c, 0x3d, 0x77, 0xb2,
+ 0xed, 0x30, 0x20, 0xe4, 0x0, 0x1d, 0x97, 0xe8, 0xbf, 0xc7,
+ 0x0, 0x1b, 0x21, 0xb1, 0x16, 0xe7, 0x41, 0x67, 0x2e, 0xec,
+ 0x38, 0xbc, 0xe5, 0x1b, 0xb4, 0x6, 0x23, 0x31, 0x71, 0x1c,
+ 0x49, 0xcd, 0x76, 0x4a, 0x76, 0x36, 0x8d, 0xa3, 0x89, 0x8b,
+ 0x4a, 0x7a, 0xf4, 0x87, 0xc8, 0x15, 0xf, 0x37, 0x39, 0xf6,
+ 0x6d, 0x80, 0x19, 0xef, 0x5c, 0xa8, 0x66, 0xce, 0x1b, 0x16,
+ 0x79, 0x21, 0xdf, 0xd7, 0x31, 0x30, 0xc4, 0x21, 0xdd, 0x34,
+ 0x5b, 0xd2, 0x1a, 0x2b, 0x3e, 0x5d, 0xf7, 0xea, 0xca, 0x5,
+ 0x8e, 0xb7, 0xcb, 0x49, 0x2e, 0xa0, 0xe3, 0xf4, 0xa7, 0x48,
+ 0x19, 0x10, 0x9c, 0x4, 0xa7, 0xf4, 0x28, 0x74, 0xc8, 0x6f,
+ 0x63, 0x20, 0x2b, 0x46, 0x24, 0x26, 0x19, 0x1d, 0xd1, 0x2c,
+ 0x31, 0x6d, 0x5a, 0x29, 0xa2, 0x6, 0xa6, 0xb2, 0x41, 0xcc,
+ 0xa, 0x27, 0x96, 0x9, 0x96, 0xac, 0x47, 0x65, 0x78, 0x68,
+ 0x51, 0x98, 0xd6, 0xd8, 0xa6, 0x2d, 0xa0, 0xcf, 0xec, 0xe2,
+ 0x74, 0xf2, 0x82, 0xe3, 0x97, 0xd9, 0x7e, 0xd4, 0xf8, 0xb,
+ 0x70, 0x43, 0x3d, 0xb1, 0x7b, 0x97, 0x80, 0xd6, 0xcb, 0xd7,
+ 0x19, 0xbc, 0x63, 0xb, 0xfd, 0x4d, 0x88, 0xfe, 0x67, 0xac,
+ 0xb8, 0xcc, 0x50, 0xb7, 0x68, 0xb3, 0x5b, 0xd6, 0x1e, 0x25,
+ 0xfc, 0x5f, 0x3c, 0x8d, 0xb1, 0x33, 0x7c, 0xb3, 0x49, 0x1,
+ 0x3f, 0x71, 0x55, 0xe, 0x51, 0xba, 0x61, 0x26, 0xfa, 0xea,
+ 0xe5, 0xb5, 0xe8, 0xaa, 0xcf, 0xcd, 0x96, 0x9f, 0xd6, 0xc1,
+ 0x5f, 0x53, 0x91, 0xad, 0x5, 0xde, 0x20, 0xe7, 0x51, 0xda,
+ 0x5b, 0x95, 0x67, 0xed, 0xf4, 0xee, 0x42, 0x65, 0x70, 0x13,
+ 0xb, 0x70, 0x14, 0x1c, 0xc9, 0xe0, 0x19, 0xca, 0x5f, 0xf5,
+ 0x1d, 0x70, 0x4b, 0x6c, 0x6, 0x74, 0xec, 0xb5, 0x2e, 0x77,
+ 0xe1, 0x74, 0xa1, 0xa3, 0x99, 0xa0, 0x85, 0x9e, 0xf1, 0xac,
+ 0xd8, 0x7e,
+};
+
+/**
+ * ============================================================================
+ * Boot states support (GREEN, YELLOW, ORANGE, RED) and dm_verity
+ * ============================================================================
+ */
+char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state)
+{
+ struct AvbOpsData *data;
+ char *cmdline = NULL;
+
+ if (!ops)
+ return NULL;
+
+ data = (struct AvbOpsData *)ops->user_data;
+ if (!data)
+ return NULL;
+
+ data->boot_state = boot_state;
+ switch (boot_state) {
+ case AVB_GREEN:
+ cmdline = "androidboot.verifiedbootstate=green";
+ break;
+ case AVB_YELLOW:
+ cmdline = "androidboot.verifiedbootstate=yellow";
+ break;
+ case AVB_ORANGE:
+ cmdline = "androidboot.verifiedbootstate=orange";
+ case AVB_RED:
+ break;
+ }
+
+ return cmdline;
+}
+
+char *append_cmd_line(char *cmdline_orig, char *cmdline_new)
+{
+ char *cmd_line;
+
+ if (!cmdline_new)
+ return cmdline_orig;
+
+ if (cmdline_orig)
+ cmd_line = cmdline_orig;
+ else
+ cmd_line = " ";
+
+ cmd_line = avb_strdupv(cmd_line, " ", cmdline_new, NULL);
+
+ return cmd_line;
+}
+
+static int avb_find_dm_args(char **args, char *str)
+{
+ int i;
+
+ if (!str)
+ return -1;
+
+ for (i = 0; i < AVB_MAX_ARGS && args[i]; ++i) {
+ if (strstr(args[i], str))
+ return i;
+ }
+
+ return -1;
+}
+
+static char *avb_set_enforce_option(const char *cmdline, const char *option)
+{
+ char *cmdarg[AVB_MAX_ARGS];
+ char *newargs = NULL;
+ int i = 0;
+ int total_args;
+
+ memset(cmdarg, 0, sizeof(cmdarg));
+ cmdarg[i++] = strtok((char *)cmdline, " ");
+
+ do {
+ cmdarg[i] = strtok(NULL, " ");
+ if (!cmdarg[i])
+ break;
+
+ if (++i >= AVB_MAX_ARGS) {
+ printf("%s: Can't handle more then %d args\n",
+ __func__, i);
+ return NULL;
+ }
+ } while (true);
+
+ total_args = i;
+ i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_LOGGING);
+ if (i >= 0) {
+ cmdarg[i] = (char *)option;
+ } else {
+ i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_RESTART);
+ if (i < 0) {
+ printf("%s: No verity options found\n", __func__);
+ return NULL;
+ }
+
+ cmdarg[i] = (char *)option;
+ }
+
+ for (i = 0; i <= total_args; i++)
+ newargs = append_cmd_line(newargs, cmdarg[i]);
+
+ return newargs;
+}
+
+char *avb_set_ignore_corruption(const char *cmdline)
+{
+ char *newargs = NULL;
+
+ newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_LOGGING);
+ if (newargs)
+ newargs = append_cmd_line(newargs,
+ "androidboot.veritymode=eio");
+
+ return newargs;
+}
+
+char *avb_set_enforce_verity(const char *cmdline)
+{
+ char *newargs;
+
+ newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_RESTART);
+ if (newargs)
+ newargs = append_cmd_line(newargs,
+ "androidboot.veritymode=enforcing");
+ return newargs;
+}
+
+/**
+ * ============================================================================
+ * IO(mmc) auxiliary functions
+ * ============================================================================
+ */
+static unsigned long mmc_read_and_flush(struct mmc_part *part,
+ lbaint_t start,
+ lbaint_t sectors,
+ void *buffer)
+{
+ unsigned long blks;
+ void *tmp_buf;
+ size_t buf_size;
+ bool unaligned = is_buf_unaligned(buffer);
+
+ if (start < part->info.start) {
+ printf("%s: partition start out of bounds\n", __func__);
+ return 0;
+ }
+ if ((start + sectors) > (part->info.start + part->info.size)) {
+ sectors = part->info.start + part->info.size - start;
+ printf("%s: read sector aligned to partition bounds (%ld)\n",
+ __func__, sectors);
+ }
+
+ /*
+ * Reading fails on unaligned buffers, so we have to
+ * use aligned temporary buffer and then copy to destination
+ */
+
+ if (unaligned) {
+ printf("Handling unaligned read buffer..\n");
+ tmp_buf = get_sector_buf();
+ buf_size = get_sector_buf_size();
+ if (sectors > buf_size / part->info.blksz)
+ sectors = buf_size / part->info.blksz;
+ } else {
+ tmp_buf = buffer;
+ }
+
+ blks = blk_dread(part->mmc_blk,
+ start, sectors, tmp_buf);
+ /* flush cache after read */
+ flush_cache((ulong)tmp_buf, sectors * part->info.blksz);
+
+ if (unaligned)
+ memcpy(buffer, tmp_buf, sectors * part->info.blksz);
+
+ return blks;
+}
+
+static unsigned long mmc_write(struct mmc_part *part, lbaint_t start,
+ lbaint_t sectors, void *buffer)
+{
+ void *tmp_buf;
+ size_t buf_size;
+ bool unaligned = is_buf_unaligned(buffer);
+
+ if (start < part->info.start) {
+ printf("%s: partition start out of bounds\n", __func__);
+ return 0;
+ }
+ if ((start + sectors) > (part->info.start + part->info.size)) {
+ sectors = part->info.start + part->info.size - start;
+ printf("%s: sector aligned to partition bounds (%ld)\n",
+ __func__, sectors);
+ }
+ if (unaligned) {
+ tmp_buf = get_sector_buf();
+ buf_size = get_sector_buf_size();
+ printf("Handling unaligned wrire buffer..\n");
+ if (sectors > buf_size / part->info.blksz)
+ sectors = buf_size / part->info.blksz;
+
+ memcpy(tmp_buf, buffer, sectors * part->info.blksz);
+ } else {
+ tmp_buf = buffer;
+ }
+
+ return blk_dwrite(part->mmc_blk,
+ start, sectors, tmp_buf);
+}
+
+static struct mmc_part *get_partition(AvbOps *ops, const char *partition)
+{
+ int ret;
+ u8 dev_num;
+ int part_num = 0;
+ struct mmc_part *part;
+ struct blk_desc *mmc_blk;
+
+ part = malloc(sizeof(struct mmc_part));
+ if (!part)
+ return NULL;
+
+ dev_num = get_boot_device(ops);
+ part->mmc = find_mmc_device(dev_num);
+ if (!part->mmc) {
+ printf("No MMC device at slot %x\n", dev_num);
+ goto err;
+ }
+
+ if (mmc_init(part->mmc)) {
+ printf("MMC initialization failed\n");
+ goto err;
+ }
+
+ ret = mmc_switch_part(part->mmc, part_num);
+ if (ret)
+ goto err;
+
+ mmc_blk = mmc_get_blk_desc(part->mmc);
+ if (!mmc_blk) {
+ printf("Error - failed to obtain block descriptor\n");
+ goto err;
+ }
+
+ ret = part_get_info_by_name(mmc_blk, partition, &part->info);
+ if (ret < 0) {
+ printf("Can't find partition '%s'\n", partition);
+ goto err;
+ }
+
+ part->dev_num = dev_num;
+ part->mmc_blk = mmc_blk;
+
+ return part;
+err:
+ free(part);
+ return NULL;
+}
+
+static AvbIOResult mmc_byte_io(AvbOps *ops,
+ const char *partition,
+ s64 offset,
+ size_t num_bytes,
+ void *buffer,
+ size_t *out_num_read,
+ enum mmc_io_type io_type)
+{
+ ulong ret;
+ struct mmc_part *part;
+ u64 start_offset, start_sector, sectors, residue;
+ u8 *tmp_buf;
+ size_t io_cnt = 0;
+
+ if (!partition || !buffer || io_type > IO_WRITE)
+ return AVB_IO_RESULT_ERROR_IO;
+
+ part = get_partition(ops, partition);
+ if (!part)
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+
+ if (!part->info.blksz)
+ return AVB_IO_RESULT_ERROR_IO;
+
+ start_offset = calc_offset(part, offset);
+ while (num_bytes) {
+ start_sector = start_offset / part->info.blksz;
+ sectors = num_bytes / part->info.blksz;
+ /* handle non block-aligned reads */
+ if (start_offset % part->info.blksz ||
+ num_bytes < part->info.blksz) {
+ tmp_buf = get_sector_buf();
+ if (start_offset % part->info.blksz) {
+ residue = part->info.blksz -
+ (start_offset % part->info.blksz);
+ if (residue > num_bytes)
+ residue = num_bytes;
+ } else {
+ residue = num_bytes;
+ }
+
+ if (io_type == IO_READ) {
+ ret = mmc_read_and_flush(part,
+ part->info.start +
+ start_sector,
+ 1, tmp_buf);
+
+ if (ret != 1) {
+ printf("%s: read error (%ld, %lld)\n",
+ __func__, ret, start_sector);
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+ /*
+ * if this is not aligned at sector start,
+ * we have to adjust the tmp buffer
+ */
+ tmp_buf += (start_offset % part->info.blksz);
+ memcpy(buffer, (void *)tmp_buf, residue);
+ } else {
+ ret = mmc_read_and_flush(part,
+ part->info.start +
+ start_sector,
+ 1, tmp_buf);
+
+ if (ret != 1) {
+ printf("%s: read error (%ld, %lld)\n",
+ __func__, ret, start_sector);
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+ memcpy((void *)tmp_buf +
+ start_offset % part->info.blksz,
+ buffer, residue);
+
+ ret = mmc_write(part, part->info.start +
+ start_sector, 1, tmp_buf);
+ if (ret != 1) {
+ printf("%s: write error (%ld, %lld)\n",
+ __func__, ret, start_sector);
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+ }
+
+ io_cnt += residue;
+ buffer += residue;
+ start_offset += residue;
+ num_bytes -= residue;
+ continue;
+ }
+
+ if (sectors) {
+ if (io_type == IO_READ) {
+ ret = mmc_read_and_flush(part,
+ part->info.start +
+ start_sector,
+ sectors, buffer);
+ } else {
+ ret = mmc_write(part,
+ part->info.start +
+ start_sector,
+ sectors, buffer);
+ }
+
+ if (!ret) {
+ printf("%s: sector read error\n", __func__);
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ io_cnt += ret * part->info.blksz;
+ buffer += ret * part->info.blksz;
+ start_offset += ret * part->info.blksz;
+ num_bytes -= ret * part->info.blksz;
+ }
+ }
+
+ /* Set counter for read operation */
+ if (io_type == IO_READ && out_num_read)
+ *out_num_read = io_cnt;
+
+ return AVB_IO_RESULT_OK;
+}
+
+/**
+ * ============================================================================
+ * AVB 2.0 operations
+ * ============================================================================
+ */
+
+/**
+ * read_from_partition() - reads @num_bytes from @offset from partition
+ * identified by a string name
+ *
+ * @ops: contains AVB ops handlers
+ * @partition_name: partition name, NUL-terminated UTF-8 string
+ * @offset: offset from the beginning of partition
+ * @num_bytes: amount of bytes to read
+ * @buffer: destination buffer to store data
+ * @out_num_read:
+ *
+ * @return:
+ * AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ * AVB_IO_RESULT_ERROR_IO, if i/o error occurred from the underlying i/o
+ * subsystem
+ * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if there is no partition with
+ * the given name
+ */
+static AvbIOResult read_from_partition(AvbOps *ops,
+ const char *partition_name,
+ s64 offset_from_partition,
+ size_t num_bytes,
+ void *buffer,
+ size_t *out_num_read)
+{
+ return mmc_byte_io(ops, partition_name, offset_from_partition,
+ num_bytes, buffer, out_num_read, IO_READ);
+}
+
+/**
+ * write_to_partition() - writes N bytes to a partition identified by a string
+ * name
+ *
+ * @ops: AvbOps, contains AVB ops handlers
+ * @partition_name: partition name
+ * @offset_from_partition: offset from the beginning of partition
+ * @num_bytes: amount of bytes to write
+ * @buf: data to write
+ * @out_num_read:
+ *
+ * @return:
+ * AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ * AVB_IO_RESULT_ERROR_IO, if input/output error occurred
+ * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition, specified in
+ * @partition_name was not found
+ */
+static AvbIOResult write_to_partition(AvbOps *ops,
+ const char *partition_name,
+ s64 offset_from_partition,
+ size_t num_bytes,
+ const void *buffer)
+{
+ return mmc_byte_io(ops, partition_name, offset_from_partition,
+ num_bytes, (void *)buffer, NULL, IO_WRITE);
+}
+
+/**
+ * validate_vmbeta_public_key() - checks if the given public key used to sign
+ * the vbmeta partition is trusted
+ *
+ * @ops: AvbOps, contains AVB ops handlers
+ * @public_key_data: public key for verifying vbmeta partition signature
+ * @public_key_length: length of public key
+ * @public_key_metadata:
+ * @public_key_metadata_length:
+ * @out_key_is_trusted:
+ *
+ * @return:
+ * AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ */
+static AvbIOResult validate_vbmeta_public_key(AvbOps *ops,
+ const u8 *public_key_data,
+ size_t public_key_length,
+ const u8
+ *public_key_metadata,
+ size_t
+ public_key_metadata_length,
+ bool *out_key_is_trusted)
+{
+ if (!public_key_length || !public_key_data || !out_key_is_trusted)
+ return AVB_IO_RESULT_ERROR_IO;
+
+ *out_key_is_trusted = false;
+ if (public_key_length != sizeof(avb_root_pub))
+ return AVB_IO_RESULT_ERROR_IO;
+
+ if (memcmp(avb_root_pub, public_key_data, public_key_length) == 0)
+ *out_key_is_trusted = true;
+
+ return AVB_IO_RESULT_OK;
+}
+
+#ifdef CONFIG_OPTEE_TA_AVB
+static int get_open_session(struct AvbOpsData *ops_data)
+{
+ struct udevice *tee = NULL;
+
+ while (!ops_data->tee) {
+ const struct tee_optee_ta_uuid uuid = TA_AVB_UUID;
+ struct tee_open_session_arg arg;
+ int rc;
+
+ tee = tee_find_device(tee, NULL, NULL, NULL);
+ if (!tee)
+ return -ENODEV;
+
+ memset(&arg, 0, sizeof(arg));
+ tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
+ rc = tee_open_session(tee, &arg, 0, NULL);
+ if (!rc) {
+ ops_data->tee = tee;
+ ops_data->session = arg.session;
+ }
+ }
+
+ return 0;
+}
+
+static AvbIOResult invoke_func(struct AvbOpsData *ops_data, u32 func,
+ ulong num_param, struct tee_param *param)
+{
+ struct tee_invoke_arg arg;
+
+ if (get_open_session(ops_data))
+ return AVB_IO_RESULT_ERROR_IO;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.func = func;
+ arg.session = ops_data->session;
+
+ if (tee_invoke_func(ops_data->tee, &arg, num_param, param))
+ return AVB_IO_RESULT_ERROR_IO;
+ switch (arg.ret) {
+ case TEE_SUCCESS:
+ return AVB_IO_RESULT_OK;
+ case TEE_ERROR_OUT_OF_MEMORY:
+ return AVB_IO_RESULT_ERROR_OOM;
+ case TEE_ERROR_STORAGE_NO_SPACE:
+ return AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE;
+ case TEE_ERROR_ITEM_NOT_FOUND:
+ return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
+ case TEE_ERROR_TARGET_DEAD:
+ /*
+ * The TA has paniced, close the session to reload the TA
+ * for the next request.
+ */
+ tee_close_session(ops_data->tee, ops_data->session);
+ ops_data->tee = NULL;
+ return AVB_IO_RESULT_ERROR_IO;
+ default:
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+}
+#endif
+
+/**
+ * read_rollback_index() - gets the rollback index corresponding to the
+ * location of given by @out_rollback_index.
+ *
+ * @ops: contains AvbOps handlers
+ * @rollback_index_slot:
+ * @out_rollback_index: used to write a retrieved rollback index.
+ *
+ * @return
+ * AVB_IO_RESULT_OK, if the roolback index was retrieved
+ */
+static AvbIOResult read_rollback_index(AvbOps *ops,
+ size_t rollback_index_slot,
+ u64 *out_rollback_index)
+{
+#ifndef CONFIG_OPTEE_TA_AVB
+ /* For now we always return 0 as the stored rollback index. */
+ printf("%s not supported yet\n", __func__);
+
+ if (out_rollback_index)
+ *out_rollback_index = 0;
+
+ return AVB_IO_RESULT_OK;
+#else
+ AvbIOResult rc;
+ struct tee_param param[2];
+
+ if (rollback_index_slot >= TA_AVB_MAX_ROLLBACK_LOCATIONS)
+ return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
+
+ memset(param, 0, sizeof(param));
+ param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = rollback_index_slot;
+ param[1].attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+
+ rc = invoke_func(ops->user_data, TA_AVB_CMD_READ_ROLLBACK_INDEX,
+ ARRAY_SIZE(param), param);
+ if (rc)
+ return rc;
+
+ *out_rollback_index = (u64)param[1].u.value.a << 32 |
+ (u32)param[1].u.value.b;
+ return AVB_IO_RESULT_OK;
+#endif
+}
+
+/**
+ * write_rollback_index() - sets the rollback index corresponding to the
+ * location of given by @out_rollback_index.
+ *
+ * @ops: contains AvbOps handlers
+ * @rollback_index_slot:
+ * @rollback_index: rollback index to write.
+ *
+ * @return
+ * AVB_IO_RESULT_OK, if the roolback index was retrieved
+ */
+static AvbIOResult write_rollback_index(AvbOps *ops,
+ size_t rollback_index_slot,
+ u64 rollback_index)
+{
+#ifndef CONFIG_OPTEE_TA_AVB
+ /* For now this is a no-op. */
+ printf("%s not supported yet\n", __func__);
+
+ return AVB_IO_RESULT_OK;
+#else
+ struct tee_param param[2];
+
+ if (rollback_index_slot >= TA_AVB_MAX_ROLLBACK_LOCATIONS)
+ return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
+
+ memset(param, 0, sizeof(param));
+ param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = rollback_index_slot;
+ param[1].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[1].u.value.a = (u32)(rollback_index >> 32);
+ param[1].u.value.b = (u32)rollback_index;
+
+ return invoke_func(ops->user_data, TA_AVB_CMD_WRITE_ROLLBACK_INDEX,
+ ARRAY_SIZE(param), param);
+#endif
+}
+
+/**
+ * read_is_device_unlocked() - gets whether the device is unlocked
+ *
+ * @ops: contains AVB ops handlers
+ * @out_is_unlocked: device unlock state is stored here, true if unlocked,
+ * false otherwise
+ *
+ * @return:
+ * AVB_IO_RESULT_OK: state is retrieved successfully
+ * AVB_IO_RESULT_ERROR_IO: an error occurred
+ */
+static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
+{
+#ifndef CONFIG_OPTEE_TA_AVB
+ /* For now we always return that the device is unlocked. */
+
+ printf("%s not supported yet\n", __func__);
+
+ *out_is_unlocked = true;
+
+ return AVB_IO_RESULT_OK;
+#else
+ AvbIOResult rc;
+ struct tee_param param = { .attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT };
+
+ rc = invoke_func(ops->user_data, TA_AVB_CMD_READ_LOCK_STATE, 1, &param);
+ if (rc)
+ return rc;
+ *out_is_unlocked = !param.u.value.a;
+ return AVB_IO_RESULT_OK;
+#endif
+}
+
+/**
+ * get_unique_guid_for_partition() - gets the GUID for a partition identified
+ * by a string name
+ *
+ * @ops: contains AVB ops handlers
+ * @partition: partition name (NUL-terminated UTF-8 string)
+ * @guid_buf: buf, used to copy in GUID string. Example of value:
+ * 527c1c6d-6361-4593-8842-3c78fcd39219
+ * @guid_buf_size: @guid_buf buffer size
+ *
+ * @return:
+ * AVB_IO_RESULT_OK, on success (GUID found)
+ * AVB_IO_RESULT_ERROR_IO, if incorrect buffer size (@guid_buf_size) was
+ * provided
+ * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition was not found
+ */
+static AvbIOResult get_unique_guid_for_partition(AvbOps *ops,
+ const char *partition,
+ char *guid_buf,
+ size_t guid_buf_size)
+{
+ struct mmc_part *part;
+ size_t uuid_size;
+
+ part = get_partition(ops, partition);
+ if (!part)
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+
+ uuid_size = sizeof(part->info.uuid);
+ if (uuid_size > guid_buf_size)
+ return AVB_IO_RESULT_ERROR_IO;
+
+ memcpy(guid_buf, part->info.uuid, uuid_size);
+ guid_buf[uuid_size - 1] = 0;
+
+ return AVB_IO_RESULT_OK;
+}
+
+/**
+ * get_size_of_partition() - gets the size of a partition identified
+ * by a string name
+ *
+ * @ops: contains AVB ops handlers
+ * @partition: partition name (NUL-terminated UTF-8 string)
+ * @out_size_num_bytes: returns the value of a partition size
+ *
+ * @return:
+ * AVB_IO_RESULT_OK, on success (GUID found)
+ * AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE, out_size_num_bytes is NULL
+ * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition was not found
+ */
+static AvbIOResult get_size_of_partition(AvbOps *ops,
+ const char *partition,
+ u64 *out_size_num_bytes)
+{
+ struct mmc_part *part;
+
+ if (!out_size_num_bytes)
+ return AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE;
+
+ part = get_partition(ops, partition);
+ if (!part)
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+
+ *out_size_num_bytes = part->info.blksz * part->info.size;
+
+ return AVB_IO_RESULT_OK;
+}
+
+#ifdef CONFIG_OPTEE_TA_AVB
+static AvbIOResult read_persistent_value(AvbOps *ops,
+ const char *name,
+ size_t buffer_size,
+ u8 *out_buffer,
+ size_t *out_num_bytes_read)
+{
+ AvbIOResult rc;
+ struct tee_shm *shm_name;
+ struct tee_shm *shm_buf;
+ struct tee_param param[2];
+ struct udevice *tee;
+ size_t name_size = strlen(name) + 1;
+
+ if (get_open_session(ops->user_data))
+ return AVB_IO_RESULT_ERROR_IO;
+
+ tee = ((struct AvbOpsData *)ops->user_data)->tee;
+
+ rc = tee_shm_alloc(tee, name_size,
+ TEE_SHM_ALLOC, &shm_name);
+ if (rc)
+ return AVB_IO_RESULT_ERROR_OOM;
+
+ rc = tee_shm_alloc(tee, buffer_size,
+ TEE_SHM_ALLOC, &shm_buf);
+ if (rc) {
+ rc = AVB_IO_RESULT_ERROR_OOM;
+ goto free_name;
+ }
+
+ memcpy(shm_name->addr, name, name_size);
+
+ memset(param, 0, sizeof(param));
+ param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
+ param[0].u.memref.shm = shm_name;
+ param[0].u.memref.size = name_size;
+ param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
+ param[1].u.memref.shm = shm_buf;
+ param[1].u.memref.size = buffer_size;
+
+ rc = invoke_func(ops->user_data, TA_AVB_CMD_READ_PERSIST_VALUE,
+ 2, param);
+ if (rc)
+ goto out;
+
+ if (param[1].u.memref.size > buffer_size) {
+ rc = AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
+ goto out;
+ }
+
+ *out_num_bytes_read = param[1].u.memref.size;
+
+ memcpy(out_buffer, shm_buf->addr, *out_num_bytes_read);
+
+out:
+ tee_shm_free(shm_buf);
+free_name:
+ tee_shm_free(shm_name);
+
+ return rc;
+}
+
+static AvbIOResult write_persistent_value(AvbOps *ops,
+ const char *name,
+ size_t value_size,
+ const u8 *value)
+{
+ AvbIOResult rc;
+ struct tee_shm *shm_name;
+ struct tee_shm *shm_buf;
+ struct tee_param param[2];
+ struct udevice *tee;
+ size_t name_size = strlen(name) + 1;
+
+ if (get_open_session(ops->user_data))
+ return AVB_IO_RESULT_ERROR_IO;
+
+ tee = ((struct AvbOpsData *)ops->user_data)->tee;
+
+ if (!value_size)
+ return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
+
+ rc = tee_shm_alloc(tee, name_size,
+ TEE_SHM_ALLOC, &shm_name);
+ if (rc)
+ return AVB_IO_RESULT_ERROR_OOM;
+
+ rc = tee_shm_alloc(tee, value_size,
+ TEE_SHM_ALLOC, &shm_buf);
+ if (rc) {
+ rc = AVB_IO_RESULT_ERROR_OOM;
+ goto free_name;
+ }
+
+ memcpy(shm_name->addr, name, name_size);
+ memcpy(shm_buf->addr, value, value_size);
+
+ memset(param, 0, sizeof(param));
+ param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
+ param[0].u.memref.shm = shm_name;
+ param[0].u.memref.size = name_size;
+ param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
+ param[1].u.memref.shm = shm_buf;
+ param[1].u.memref.size = value_size;
+
+ rc = invoke_func(ops->user_data, TA_AVB_CMD_WRITE_PERSIST_VALUE,
+ 2, param);
+ if (rc)
+ goto out;
+
+out:
+ tee_shm_free(shm_buf);
+free_name:
+ tee_shm_free(shm_name);
+
+ return rc;
+}
+#endif
+
+/**
+ * ============================================================================
+ * AVB2.0 AvbOps alloc/initialisation/free
+ * ============================================================================
+ */
+AvbOps *avb_ops_alloc(int boot_device)
+{
+ struct AvbOpsData *ops_data;
+
+ ops_data = avb_calloc(sizeof(struct AvbOpsData));
+ if (!ops_data)
+ return NULL;
+
+ ops_data->ops.user_data = ops_data;
+
+ ops_data->ops.read_from_partition = read_from_partition;
+ ops_data->ops.write_to_partition = write_to_partition;
+ ops_data->ops.validate_vbmeta_public_key = validate_vbmeta_public_key;
+ ops_data->ops.read_rollback_index = read_rollback_index;
+ ops_data->ops.write_rollback_index = write_rollback_index;
+ ops_data->ops.read_is_device_unlocked = read_is_device_unlocked;
+ ops_data->ops.get_unique_guid_for_partition =
+ get_unique_guid_for_partition;
+#ifdef CONFIG_OPTEE_TA_AVB
+ ops_data->ops.write_persistent_value = write_persistent_value;
+ ops_data->ops.read_persistent_value = read_persistent_value;
+#endif
+ ops_data->ops.get_size_of_partition = get_size_of_partition;
+ ops_data->mmc_dev = boot_device;
+
+ return &ops_data->ops;
+}
+
+void avb_ops_free(AvbOps *ops)
+{
+ struct AvbOpsData *ops_data;
+
+ if (!ops)
+ return;
+
+ ops_data = ops->user_data;
+
+ if (ops_data) {
+#ifdef CONFIG_OPTEE_TA_AVB
+ if (ops_data->tee)
+ tee_close_session(ops_data->tee, ops_data->session);
+#endif
+ avb_free(ops_data);
+ }
+}
diff --git a/roms/u-boot/common/bedbug.c b/roms/u-boot/common/bedbug.c
new file mode 100644
index 000000000..18a35ca23
--- /dev/null
+++ b/roms/u-boot/common/bedbug.c
@@ -0,0 +1,1254 @@
+/* $Id$ */
+
+#include <common.h>
+#include <asm/ptrace.h>
+
+#include <linux/ctype.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/ppc.h>
+#include <bedbug/regs.h>
+#include <bedbug/tables.h>
+
+#define Elf32_Word unsigned long
+
+/* USE_SOURCE_CODE enables some symbolic debugging functions of this
+ code. This is only useful if the program will have access to the
+ source code for the binary being examined.
+*/
+
+/* #define USE_SOURCE_CODE 1 */
+
+#ifdef USE_SOURCE_CODE
+extern int line_info_from_addr __P ((Elf32_Word, char *, char *, int *));
+extern struct symreflist *symByAddr;
+extern char *symbol_name_from_addr __P ((Elf32_Word, int, int *));
+#endif /* USE_SOURCE_CODE */
+
+int print_operands __P ((struct ppc_ctx *));
+int get_operand_value __P ((struct opcode *, unsigned long,
+ enum OP_FIELD, unsigned long *));
+struct opcode *find_opcode __P ((unsigned long));
+struct opcode *find_opcode_by_name __P ((char *));
+char *spr_name __P ((int));
+int spr_value __P ((char *));
+char *tbr_name __P ((int));
+int tbr_value __P ((char *));
+int parse_operand __P ((unsigned long, struct opcode *,
+ struct operand *, char *, int *));
+int get_word __P ((char **, char *));
+long read_number __P ((char *));
+int downstring __P ((char *));
+
+
+/*======================================================================
+ * Entry point for the PPC disassembler.
+ *
+ * Arguments:
+ * memaddr The address to start disassembling from.
+ *
+ * virtual If this value is non-zero, then this will be
+ * used as the base address for the output and
+ * symbol lookups. If this value is zero then
+ * memaddr is used as the absolute address.
+ *
+ * num_instr The number of instructions to disassemble. Since
+ * each instruction is 32 bits long, this can be
+ * computed if you know the total size of the region.
+ *
+ * pfunc The address of a function that is called to print
+ * each line of output. The function should take a
+ * single character pointer as its parameters a la puts.
+ *
+ * flags Sets options for the output. This is a
+ * bitwise-inclusive-OR of the following
+ * values. Note that only one of the radix
+ * options may be set.
+ *
+ * F_RADOCTAL - output radix is unsigned base 8.
+ * F_RADUDECIMAL - output radix is unsigned base 10.
+ * F_RADSDECIMAL - output radix is signed base 10.
+ * F_RADHEX - output radix is unsigned base 16.
+ * F_SIMPLE - use simplified mnemonics.
+ * F_SYMBOL - lookup symbols for addresses.
+ * F_INSTR - output raw instruction.
+ * F_LINENO - show line # info if available.
+ *
+ * Returns true if the area was successfully disassembled or false if
+ * a problem was encountered with accessing the memory.
+ */
+
+int disppc (unsigned char *memaddr, unsigned char *virtual, int num_instr,
+ int (*pfunc) (const char *), unsigned long flags)
+{
+ int i;
+ struct ppc_ctx ctx;
+
+#ifdef USE_SOURCE_CODE
+ int line_no = 0;
+ int last_line_no = 0;
+ char funcname[128] = { 0 };
+ char filename[256] = { 0 };
+ char last_funcname[128] = { 0 };
+ int symoffset;
+ char *symname;
+ char *cursym = (char *) 0;
+#endif /* USE_SOURCE_CODE */
+ /*------------------------------------------------------------*/
+
+ ctx.flags = flags;
+ ctx.virtual = virtual;
+
+ /* Figure out the output radix before we go any further */
+
+ if (ctx.flags & F_RADOCTAL) {
+ /* Unsigned octal output */
+ strcpy (ctx.radix_fmt, "O%o");
+ } else if (ctx.flags & F_RADUDECIMAL) {
+ /* Unsigned decimal output */
+ strcpy (ctx.radix_fmt, "%u");
+ } else if (ctx.flags & F_RADSDECIMAL) {
+ /* Signed decimal output */
+ strcpy (ctx.radix_fmt, "%d");
+ } else {
+ /* Unsigned hex output */
+ strcpy (ctx.radix_fmt, "0x%x");
+ }
+
+ if (ctx.virtual == 0) {
+ ctx.virtual = memaddr;
+ }
+#ifdef USE_SOURCE_CODE
+ if (ctx.flags & F_SYMBOL) {
+ if (symByAddr == 0) /* no symbols loaded */
+ ctx.flags &= ~F_SYMBOL;
+ else {
+ cursym = (char *) 0;
+ symoffset = 0;
+ }
+ }
+#endif /* USE_SOURCE_CODE */
+
+ /* format each line as "XXXXXXXX: <symbol> IIIIIIII disassembly" where,
+ XXXXXXXX is the memory address in hex,
+ <symbol> is the symbolic location if F_SYMBOL is set.
+ IIIIIIII is the raw machine code in hex if F_INSTR is set,
+ and disassembly is the disassembled machine code with numbers
+ formatted according to the 'radix' parameter */
+
+ for (i = 0; i < num_instr; ++i, memaddr += 4, ctx.virtual += 4) {
+#ifdef USE_SOURCE_CODE
+ if (ctx.flags & F_LINENO) {
+ if ((line_info_from_addr ((Elf32_Word) ctx.virtual,
+ filename, funcname, &line_no) == true) &&
+ ((line_no != last_line_no) ||
+ (strcmp (last_funcname, funcname) != 0))) {
+ print_source_line (filename, funcname, line_no, pfunc);
+ }
+ last_line_no = line_no;
+ strcpy (last_funcname, funcname);
+ }
+#endif /* USE_SOURCE_CODE */
+
+ sprintf (ctx.data, "%08lx: ", (unsigned long) ctx.virtual);
+ ctx.datalen = 10;
+
+#ifdef USE_SOURCE_CODE
+ if (ctx.flags & F_SYMBOL) {
+ if ((symname =
+ symbol_name_from_addr((Elf32_Word) ctx.virtual,
+ true, 0)) != 0) {
+ cursym = symname;
+ symoffset = 0;
+ } else {
+ if ((cursym == 0) &&
+ ((symname =
+ symbol_name_from_addr((Elf32_Word) ctx.virtual,
+ false, &symoffset)) != 0)) {
+ cursym = symname;
+ } else {
+ symoffset += 4;
+ }
+ }
+
+ if (cursym != 0) {
+ sprintf (&ctx.data[ctx.datalen], "<%s+", cursym);
+ ctx.datalen = strlen (ctx.data);
+ sprintf (&ctx.data[ctx.datalen], ctx.radix_fmt, symoffset);
+ strcat (ctx.data, ">");
+ ctx.datalen = strlen (ctx.data);
+ }
+ }
+#endif /* USE_SOURCE_CODE */
+
+ ctx.instr = INSTRUCTION (memaddr);
+
+ if (ctx.flags & F_INSTR) {
+ /* Find the opcode structure for this opcode. If one is not found
+ then it must be an illegal instruction */
+ sprintf (&ctx.data[ctx.datalen],
+ " %02lx %02lx %02lx %02lx ",
+ ((ctx.instr >> 24) & 0xff),
+ ((ctx.instr >> 16) & 0xff), ((ctx.instr >> 8) & 0xff),
+ (ctx.instr & 0xff));
+ ctx.datalen += 18;
+ } else {
+ strcat (ctx.data, " ");
+ ctx.datalen += 3;
+ }
+
+ if ((ctx.op = find_opcode (ctx.instr)) == 0) {
+ /* Illegal Opcode */
+ sprintf (&ctx.data[ctx.datalen], " .long 0x%08lx",
+ ctx.instr);
+ ctx.datalen += 24;
+ (*pfunc) (ctx.data);
+ continue;
+ }
+
+ if (((ctx.flags & F_SIMPLE) == 0) ||
+ (ctx.op->hfunc == 0) ||
+ ((*ctx.op->hfunc) (&ctx) == false)) {
+ sprintf (&ctx.data[ctx.datalen], "%-7s ", ctx.op->name);
+ ctx.datalen += 8;
+ print_operands (&ctx);
+ }
+
+ (*pfunc) (ctx.data);
+ }
+
+ return true;
+} /* disppc */
+
+
+
+/*======================================================================
+ * Called by the disassembler to print the operands for an instruction.
+ *
+ * Arguments:
+ * ctx A pointer to the disassembler context record.
+ *
+ * always returns 0.
+ */
+
+int print_operands (struct ppc_ctx *ctx)
+{
+ int open_parens = 0;
+ int field;
+ unsigned long operand;
+ struct operand *opr;
+
+#ifdef USE_SOURCE_CODE
+ char *symname;
+ int offset;
+#endif /* USE_SOURCE_CODE */
+ /*------------------------------------------------------------*/
+
+ /* Walk through the operands and list each in order */
+ for (field = 0; ctx->op->fields[field] != 0; ++field) {
+ if (ctx->op->fields[field] > n_operands) {
+ continue; /* bad operand ?! */
+ }
+
+ opr = &operands[ctx->op->fields[field] - 1];
+
+ if (opr->hint & OH_SILENT) {
+ continue;
+ }
+
+ if ((field > 0) && !open_parens) {
+ strcat (ctx->data, ",");
+ ctx->datalen++;
+ }
+
+ operand = (ctx->instr >> opr->shift) & ((1 << opr->bits) - 1);
+
+ if (opr->hint & OH_ADDR) {
+ if ((operand & (1 << (opr->bits - 1))) != 0) {
+ operand = operand - (1 << opr->bits);
+ }
+
+ if (ctx->op->hint & H_RELATIVE)
+ operand = (operand << 2) + (unsigned long) ctx->virtual;
+ else
+ operand = (operand << 2);
+
+
+ sprintf (&ctx->data[ctx->datalen], "0x%lx", operand);
+ ctx->datalen = strlen (ctx->data);
+
+#ifdef USE_SOURCE_CODE
+ if ((ctx->flags & F_SYMBOL) &&
+ ((symname =
+ symbol_name_from_addr (operand, 0, &offset)) != 0)) {
+ sprintf (&ctx->data[ctx->datalen], " <%s", symname);
+ if (offset != 0) {
+ strcat (ctx->data, "+");
+ ctx->datalen = strlen (ctx->data);
+ sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt,
+ offset);
+ }
+ strcat (ctx->data, ">");
+ }
+#endif /* USE_SOURCE_CODE */
+ }
+
+ else if (opr->hint & OH_REG) {
+ if ((operand == 0) &&
+ (opr->field == O_rA) && (ctx->op->hint & H_RA0_IS_0)) {
+ strcat (ctx->data, "0");
+ } else {
+ sprintf (&ctx->data[ctx->datalen], "r%d", (short) operand);
+ }
+
+ if (open_parens) {
+ strcat (ctx->data, ")");
+ open_parens--;
+ }
+ }
+
+ else if (opr->hint & OH_SPR) {
+ strcat (ctx->data, spr_name (operand));
+ }
+
+ else if (opr->hint & OH_TBR) {
+ strcat (ctx->data, tbr_name (operand));
+ }
+
+ else if (opr->hint & OH_LITERAL) {
+ switch (opr->field) {
+ case O_cr2:
+ strcat (ctx->data, "cr2");
+ ctx->datalen += 3;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ else {
+ sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt,
+ (unsigned short) operand);
+
+ if (open_parens) {
+ strcat (ctx->data, ")");
+ open_parens--;
+ }
+
+ else if (opr->hint & OH_OFFSET) {
+ strcat (ctx->data, "(");
+ open_parens++;
+ }
+ }
+
+ ctx->datalen = strlen (ctx->data);
+ }
+
+ return 0;
+} /* print_operands */
+
+
+
+/*======================================================================
+ * Called to get the value of an arbitrary operand with in an instruction.
+ *
+ * Arguments:
+ * op The pointer to the opcode structure to which
+ * the operands belong.
+ *
+ * instr The instruction (32 bits) containing the opcode
+ * and the operands to print. By the time that
+ * this routine is called the operand has already
+ * been added to the output.
+ *
+ * field The field (operand) to get the value of.
+ *
+ * value The address of an unsigned long to be filled in
+ * with the value of the operand if it is found. This
+ * will only be filled in if the function returns
+ * true. This may be passed as 0 if the value is
+ * not required.
+ *
+ * Returns true if the operand was found or false if it was not.
+ */
+
+int get_operand_value (struct opcode *op, unsigned long instr,
+ enum OP_FIELD field, unsigned long *value)
+{
+ int i;
+ struct operand *opr;
+
+ /*------------------------------------------------------------*/
+
+ if (field > n_operands) {
+ return false; /* bad operand ?! */
+ }
+
+ /* Walk through the operands and list each in order */
+ for (i = 0; op->fields[i] != 0; ++i) {
+ if (op->fields[i] != field) {
+ continue;
+ }
+
+ opr = &operands[op->fields[i] - 1];
+
+ if (value) {
+ *value = (instr >> opr->shift) & ((1 << opr->bits) - 1);
+ }
+ return true;
+ }
+
+ return false;
+} /* operand_value */
+
+
+
+/*======================================================================
+ * Called by the disassembler to match an opcode value to an opcode structure.
+ *
+ * Arguments:
+ * instr The instruction (32 bits) to match. This value
+ * may contain operand values as well as the opcode
+ * since they will be masked out anyway for this
+ * search.
+ *
+ * Returns the address of an opcode struct (from the opcode table) if the
+ * operand successfully matched an entry, or 0 if no match was found.
+ */
+
+struct opcode *find_opcode (unsigned long instr)
+{
+ struct opcode *ptr;
+ int top = 0;
+ int bottom = n_opcodes - 1;
+ int idx;
+
+ /*------------------------------------------------------------*/
+
+ while (top <= bottom) {
+ idx = (top + bottom) >> 1;
+ ptr = &opcodes[idx];
+
+ if ((instr & ptr->mask) < ptr->opcode) {
+ bottom = idx - 1;
+ } else if ((instr & ptr->mask) > ptr->opcode) {
+ top = idx + 1;
+ } else {
+ return ptr;
+ }
+ }
+
+ return (struct opcode *) 0;
+} /* find_opcode */
+
+
+
+/*======================================================================
+ * Called by the assembler to match an opcode name to an opcode structure.
+ *
+ * Arguments:
+ * name The text name of the opcode, e.g. "b", "mtspr", etc.
+ *
+ * The opcodes are sorted numerically by their instruction binary code
+ * so a search for the name cannot use the binary search used by the
+ * other find routine.
+ *
+ * Returns the address of an opcode struct (from the opcode table) if the
+ * name successfully matched an entry, or 0 if no match was found.
+ */
+
+struct opcode *find_opcode_by_name (char *name)
+{
+ int idx;
+
+ /*------------------------------------------------------------*/
+
+ downstring (name);
+
+ for (idx = 0; idx < n_opcodes; ++idx) {
+ if (!strcmp (name, opcodes[idx].name))
+ return &opcodes[idx];
+ }
+
+ return (struct opcode *) 0;
+} /* find_opcode_by_name */
+
+
+
+/*======================================================================
+ * Convert the 'spr' operand from its numeric value to its symbolic name.
+ *
+ * Arguments:
+ * value The value of the 'spr' operand. This value should
+ * be unmodified from its encoding in the instruction.
+ * the split-field computations will be performed
+ * here before the switch.
+ *
+ * Returns the address of a character array containing the name of the
+ * special purpose register defined by the 'value' parameter, or the
+ * address of a character array containing "???" if no match was found.
+ */
+
+char *spr_name (int value)
+{
+ unsigned short spr;
+ static char other[10];
+ int i;
+
+ /*------------------------------------------------------------*/
+
+ /* spr is a 10 bit field whose interpretation has the high and low
+ five-bit fields reversed from their encoding in the operand */
+
+ spr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5);
+
+ for (i = 0; i < n_sprs; ++i) {
+ if (spr == spr_map[i].spr_val)
+ return spr_map[i].spr_name;
+ }
+
+ sprintf (other, "%d", spr);
+ return other;
+} /* spr_name */
+
+
+
+/*======================================================================
+ * Convert the 'spr' operand from its symbolic name to its numeric value
+ *
+ * Arguments:
+ * name The symbolic name of the 'spr' operand. The
+ * split-field encoding will be done by this routine.
+ * NOTE: name can be a number.
+ *
+ * Returns the numeric value for the spr appropriate for encoding a machine
+ * instruction. Returns 0 if unable to find the SPR.
+ */
+
+int spr_value (char *name)
+{
+ struct spr_info *sprp;
+ int spr;
+ int i;
+
+ /*------------------------------------------------------------*/
+
+ if (!name || !*name)
+ return 0;
+
+ if (isdigit ((int) name[0])) {
+ i = htonl (read_number (name));
+ spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5);
+ return spr;
+ }
+
+ downstring (name);
+
+ for (i = 0; i < n_sprs; ++i) {
+ sprp = &spr_map[i];
+
+ if (strcmp (name, sprp->spr_name) == 0) {
+ /* spr is a 10 bit field whose interpretation has the high and low
+ five-bit fields reversed from their encoding in the operand */
+ i = htonl (sprp->spr_val);
+ spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5);
+
+ return spr;
+ }
+ }
+
+ return 0;
+} /* spr_value */
+
+
+
+/*======================================================================
+ * Convert the 'tbr' operand from its numeric value to its symbolic name.
+ *
+ * Arguments:
+ * value The value of the 'tbr' operand. This value should
+ * be unmodified from its encoding in the instruction.
+ * the split-field computations will be performed
+ * here before the switch.
+ *
+ * Returns the address of a character array containing the name of the
+ * time base register defined by the 'value' parameter, or the address
+ * of a character array containing "???" if no match was found.
+ */
+
+char *tbr_name (int value)
+{
+ unsigned short tbr;
+
+ /*------------------------------------------------------------*/
+
+ /* tbr is a 10 bit field whose interpretation has the high and low
+ five-bit fields reversed from their encoding in the operand */
+
+ tbr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5);
+
+ if (tbr == 268)
+ return "TBL";
+
+ else if (tbr == 269)
+ return "TBU";
+
+
+ return "???";
+} /* tbr_name */
+
+
+
+/*======================================================================
+ * Convert the 'tbr' operand from its symbolic name to its numeric value.
+ *
+ * Arguments:
+ * name The symbolic name of the 'tbr' operand. The
+ * split-field encoding will be done by this routine.
+ *
+ * Returns the numeric value for the spr appropriate for encoding a machine
+ * instruction. Returns 0 if unable to find the TBR.
+ */
+
+int tbr_value (char *name)
+{
+ int tbr;
+ int val;
+
+ /*------------------------------------------------------------*/
+
+ if (!name || !*name)
+ return 0;
+
+ downstring (name);
+
+ if (isdigit ((int) name[0])) {
+ val = read_number (name);
+
+ if (val != 268 && val != 269)
+ return 0;
+ } else if (strcmp (name, "tbl") == 0)
+ val = 268;
+ else if (strcmp (name, "tbu") == 0)
+ val = 269;
+ else
+ return 0;
+
+ /* tbr is a 10 bit field whose interpretation has the high and low
+ five-bit fields reversed from their encoding in the operand */
+
+ val = htonl (val);
+ tbr = ((val >> 5) & 0x1f) | ((val & 0x1f) << 5);
+ return tbr;
+} /* tbr_name */
+
+
+
+/*======================================================================
+ * The next several functions (handle_xxx) are the routines that handle
+ * disassembling the opcodes with simplified mnemonics.
+ *
+ * Arguments:
+ * ctx A pointer to the disassembler context record.
+ *
+ * Returns true if the simpler form was printed or false if it was not.
+ */
+
+int handle_bc (struct ppc_ctx *ctx)
+{
+ unsigned long bo;
+ unsigned long bi;
+ static struct opcode blt = { B_OPCODE (16, 0, 0), B_MASK, {O_BD, 0},
+ 0, "blt", H_RELATIVE
+ };
+ static struct opcode bne =
+ { B_OPCODE (16, 0, 0), B_MASK, {O_cr2, O_BD, 0},
+ 0, "bne", H_RELATIVE
+ };
+ static struct opcode bdnz = { B_OPCODE (16, 0, 0), B_MASK, {O_BD, 0},
+ 0, "bdnz", H_RELATIVE
+ };
+
+ /*------------------------------------------------------------*/
+
+ if (get_operand_value(ctx->op, ctx->instr, O_BO, &bo) == false)
+ return false;
+
+ if (get_operand_value(ctx->op, ctx->instr, O_BI, &bi) == false)
+ return false;
+
+ if ((bo == 12) && (bi == 0)) {
+ ctx->op = &blt;
+ sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
+ ctx->datalen += 8;
+ print_operands (ctx);
+ return true;
+ } else if ((bo == 4) && (bi == 10)) {
+ ctx->op = &bne;
+ sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
+ ctx->datalen += 8;
+ print_operands (ctx);
+ return true;
+ } else if ((bo == 16) && (bi == 0)) {
+ ctx->op = &bdnz;
+ sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
+ ctx->datalen += 8;
+ print_operands (ctx);
+ return true;
+ }
+
+ return false;
+} /* handle_blt */
+
+
+
+/*======================================================================
+ * Outputs source line information for the disassembler. This should
+ * be modified in the future to lookup the actual line of source code
+ * from the file, but for now this will do.
+ *
+ * Arguments:
+ * filename The address of a character array containing the
+ * absolute path and file name of the source file.
+ *
+ * funcname The address of a character array containing the
+ * name of the function (not C++ demangled (yet))
+ * to which this code belongs.
+ *
+ * line_no An integer specifying the source line number that
+ * generated this code.
+ *
+ * pfunc The address of a function to call to print the output.
+ *
+ *
+ * Returns true if it was able to output the line info, or false if it was
+ * not.
+ */
+
+int print_source_line (char *filename, char *funcname,
+ int line_no, int (*pfunc) (const char *))
+{
+ char out_buf[256];
+
+ /*------------------------------------------------------------*/
+
+ (*pfunc) (""); /* output a newline */
+ sprintf (out_buf, "%s %s(): line %d", filename, funcname, line_no);
+ (*pfunc) (out_buf);
+
+ return true;
+} /* print_source_line */
+
+
+
+/*======================================================================
+ * Entry point for the PPC assembler.
+ *
+ * Arguments:
+ * asm_buf An array of characters containing the assembly opcode
+ * and operands to convert to a POWERPC machine
+ * instruction.
+ *
+ * Returns the machine instruction or zero.
+ */
+
+unsigned long asmppc (unsigned long memaddr, char *asm_buf, int *err)
+{
+ struct opcode *opc;
+ struct operand *oper[MAX_OPERANDS];
+ unsigned long instr;
+ unsigned long param;
+ char *ptr = asm_buf;
+ char scratch[20];
+ int i;
+ int w_operands = 0; /* wanted # of operands */
+ int n_operands = 0; /* # of operands read */
+ int asm_debug = 0;
+
+ /*------------------------------------------------------------*/
+
+ if (err)
+ *err = 0;
+
+ if (get_word (&ptr, scratch) == 0)
+ return 0;
+
+ /* Lookup the opcode structure based on the opcode name */
+ if ((opc = find_opcode_by_name (scratch)) == (struct opcode *) 0) {
+ if (err)
+ *err = E_ASM_BAD_OPCODE;
+ return 0;
+ }
+
+ if (asm_debug) {
+ printf ("asmppc: Opcode = \"%s\"\n", opc->name);
+ }
+
+ for (i = 0; i < 8; ++i) {
+ if (opc->fields[i] == 0)
+ break;
+ ++w_operands;
+ }
+
+ if (asm_debug) {
+ printf ("asmppc: Expecting %d operands\n", w_operands);
+ }
+
+ instr = opc->opcode;
+
+ /* read each operand */
+ while (n_operands < w_operands) {
+
+ oper[n_operands] = &operands[opc->fields[n_operands] - 1];
+
+ if (oper[n_operands]->hint & OH_SILENT) {
+ /* Skip silent operands, they are covered in opc->opcode */
+
+ if (asm_debug) {
+ printf ("asmppc: Operand %d \"%s\" SILENT\n", n_operands,
+ oper[n_operands]->name);
+ }
+
+ ++n_operands;
+ continue;
+ }
+
+ if (get_word (&ptr, scratch) == 0)
+ break;
+
+ if (asm_debug) {
+ printf ("asmppc: Operand %d \"%s\" : \"%s\"\n", n_operands,
+ oper[n_operands]->name, scratch);
+ }
+
+ if ((param = parse_operand (memaddr, opc, oper[n_operands],
+ scratch, err)) == -1)
+ return 0;
+
+ instr |= param;
+ ++n_operands;
+ }
+
+ if (n_operands < w_operands) {
+ if (err)
+ *err = E_ASM_NUM_OPERANDS;
+ return 0;
+ }
+
+ if (asm_debug) {
+ printf ("asmppc: Instruction = 0x%08lx\n", instr);
+ }
+
+ return instr;
+} /* asmppc */
+
+
+
+/*======================================================================
+ * Called by the assembler to interpret a single operand
+ *
+ * Arguments:
+ * ctx A pointer to the disassembler context record.
+ *
+ * Returns 0 if the operand is ok, or -1 if it is bad.
+ */
+
+int parse_operand (unsigned long memaddr, struct opcode *opc,
+ struct operand *oper, char *txt, int *err)
+{
+ long data;
+ long mask;
+ int is_neg = 0;
+
+ /*------------------------------------------------------------*/
+
+ mask = (1 << oper->bits) - 1;
+
+ if (oper->hint & OH_ADDR) {
+ data = read_number (txt);
+
+ if (opc->hint & H_RELATIVE)
+ data = data - memaddr;
+
+ if (data < 0)
+ is_neg = 1;
+
+ data >>= 2;
+ data &= (mask >> 1);
+
+ if (is_neg)
+ data |= 1 << (oper->bits - 1);
+ }
+
+ else if (oper->hint & OH_REG) {
+ if (txt[0] == 'r' || txt[0] == 'R')
+ txt++;
+ else if (txt[0] == '%' && (txt[1] == 'r' || txt[1] == 'R'))
+ txt += 2;
+
+ data = read_number (txt);
+ if (data > 31) {
+ if (err)
+ *err = E_ASM_BAD_REGISTER;
+ return -1;
+ }
+
+ data = htonl (data);
+ }
+
+ else if (oper->hint & OH_SPR) {
+ if ((data = spr_value (txt)) == 0) {
+ if (err)
+ *err = E_ASM_BAD_SPR;
+ return -1;
+ }
+ }
+
+ else if (oper->hint & OH_TBR) {
+ if ((data = tbr_value (txt)) == 0) {
+ if (err)
+ *err = E_ASM_BAD_TBR;
+ return -1;
+ }
+ }
+
+ else {
+ data = htonl (read_number (txt));
+ }
+
+ return (data & mask) << oper->shift;
+} /* parse_operand */
+
+
+char *asm_error_str (int err)
+{
+ switch (err) {
+ case E_ASM_BAD_OPCODE:
+ return "Bad opcode";
+ case E_ASM_NUM_OPERANDS:
+ return "Bad number of operands";
+ case E_ASM_BAD_REGISTER:
+ return "Bad register number";
+ case E_ASM_BAD_SPR:
+ return "Bad SPR name or number";
+ case E_ASM_BAD_TBR:
+ return "Bad TBR name or number";
+ }
+
+ return "";
+} /* asm_error_str */
+
+
+
+/*======================================================================
+ * Copy a word from one buffer to another, ignores leading white spaces.
+ *
+ * Arguments:
+ * src The address of a character pointer to the
+ * source buffer.
+ * dest A pointer to a character buffer to write the word
+ * into.
+ *
+ * Returns the number of non-white space characters copied, or zero.
+ */
+
+int get_word (char **src, char *dest)
+{
+ char *ptr = *src;
+ int nchars = 0;
+
+ /*------------------------------------------------------------*/
+
+ /* Eat white spaces */
+ while (*ptr && isblank (*ptr))
+ ptr++;
+
+ if (*ptr == 0) {
+ *src = ptr;
+ return 0;
+ }
+
+ /* Find the text of the word */
+ while (*ptr && !isblank (*ptr) && (*ptr != ','))
+ dest[nchars++] = *ptr++;
+ ptr = (*ptr == ',') ? ptr + 1 : ptr;
+ dest[nchars] = 0;
+
+ *src = ptr;
+ return nchars;
+} /* get_word */
+
+
+
+/*======================================================================
+ * Convert a numeric string to a number, be aware of base notations.
+ *
+ * Arguments:
+ * txt The numeric string.
+ *
+ * Returns the converted numeric value.
+ */
+
+long read_number (char *txt)
+{
+ long val;
+ int is_neg = 0;
+
+ /*------------------------------------------------------------*/
+
+ if (txt == 0 || *txt == 0)
+ return 0;
+
+ if (*txt == '-') {
+ is_neg = 1;
+ ++txt;
+ }
+
+ if (txt[0] == '0' && (txt[1] == 'x' || txt[1] == 'X')) /* hex */
+ val = simple_strtoul (&txt[2], NULL, 16);
+ else /* decimal */
+ val = simple_strtoul (txt, NULL, 10);
+
+ if (is_neg)
+ val = -val;
+
+ return val;
+} /* read_number */
+
+
+int downstring (char *s)
+{
+ if (!s || !*s)
+ return 0;
+
+ while (*s) {
+ if (isupper (*s))
+ *s = tolower (*s);
+ s++;
+ }
+
+ return 0;
+} /* downstring */
+
+
+
+/*======================================================================
+ * Examines the instruction at the current address and determines the
+ * next address to be executed. This will take into account branches
+ * of different types so that a "step" and "next" operations can be
+ * supported.
+ *
+ * Arguments:
+ * nextaddr The address (to be filled in) of the next
+ * instruction to execute. This will only be a valid
+ * address if true is returned.
+ *
+ * step_over A flag indicating how to compute addresses for
+ * branch statements:
+ * true = Step over the branch (next)
+ * false = step into the branch (step)
+ *
+ * Returns true if it was able to compute the address. Returns false if
+ * it has a problem reading the current instruction or one of the registers.
+ */
+
+int find_next_address (unsigned char *nextaddr, int step_over,
+ struct pt_regs *regs)
+{
+ unsigned long pc; /* SRR0 register from PPC */
+ unsigned long ctr; /* CTR register from PPC */
+ unsigned long cr; /* CR register from PPC */
+ unsigned long lr; /* LR register from PPC */
+ unsigned long instr; /* instruction at SRR0 */
+ unsigned long next; /* computed instruction for 'next' */
+ unsigned long step; /* computed instruction for 'step' */
+ unsigned long addr = 0; /* target address operand */
+ unsigned long aa = 0; /* AA operand */
+ unsigned long lk = 0; /* LK operand */
+ unsigned long bo = 0; /* BO operand */
+ unsigned long bi = 0; /* BI operand */
+ struct opcode *op = 0; /* opcode structure for 'instr' */
+ int ctr_ok = 0;
+ int cond_ok = 0;
+ int conditional = 0;
+ int branch = 0;
+
+ /*------------------------------------------------------------*/
+
+ if (nextaddr == 0 || regs == 0) {
+ printf ("find_next_address: bad args");
+ return false;
+ }
+
+ pc = regs->nip & 0xfffffffc;
+ instr = INSTRUCTION (pc);
+
+ if ((op = find_opcode (instr)) == (struct opcode *) 0) {
+ printf ("find_next_address: can't parse opcode 0x%lx", instr);
+ return false;
+ }
+
+ ctr = regs->ctr;
+ cr = regs->ccr;
+ lr = regs->link;
+
+ switch (op->opcode) {
+ case B_OPCODE (16, 0, 0): /* bc */
+ case B_OPCODE (16, 0, 1): /* bcl */
+ case B_OPCODE (16, 1, 0): /* bca */
+ case B_OPCODE (16, 1, 1): /* bcla */
+ if (!get_operand_value (op, instr, O_BD, &addr) ||
+ !get_operand_value (op, instr, O_BO, &bo) ||
+ !get_operand_value (op, instr, O_BI, &bi) ||
+ !get_operand_value (op, instr, O_AA, &aa) ||
+ !get_operand_value (op, instr, O_LK, &lk))
+ return false;
+
+ if ((addr & (1 << 13)) != 0)
+ addr = addr - (1 << 14);
+ addr <<= 2;
+ conditional = 1;
+ branch = 1;
+ break;
+
+ case I_OPCODE (18, 0, 0): /* b */
+ case I_OPCODE (18, 0, 1): /* bl */
+ case I_OPCODE (18, 1, 0): /* ba */
+ case I_OPCODE (18, 1, 1): /* bla */
+ if (!get_operand_value (op, instr, O_LI, &addr) ||
+ !get_operand_value (op, instr, O_AA, &aa) ||
+ !get_operand_value (op, instr, O_LK, &lk))
+ return false;
+
+ if ((addr & (1 << 23)) != 0)
+ addr = addr - (1 << 24);
+ addr <<= 2;
+ conditional = 0;
+ branch = 1;
+ break;
+
+ case XL_OPCODE (19, 528, 0): /* bcctr */
+ case XL_OPCODE (19, 528, 1): /* bcctrl */
+ if (!get_operand_value (op, instr, O_BO, &bo) ||
+ !get_operand_value (op, instr, O_BI, &bi) ||
+ !get_operand_value (op, instr, O_LK, &lk))
+ return false;
+
+ addr = ctr;
+ aa = 1;
+ conditional = 1;
+ branch = 1;
+ break;
+
+ case XL_OPCODE (19, 16, 0): /* bclr */
+ case XL_OPCODE (19, 16, 1): /* bclrl */
+ if (!get_operand_value (op, instr, O_BO, &bo) ||
+ !get_operand_value (op, instr, O_BI, &bi) ||
+ !get_operand_value (op, instr, O_LK, &lk))
+ return false;
+
+ addr = lr;
+ aa = 1;
+ conditional = 1;
+ branch = 1;
+ break;
+
+ default:
+ conditional = 0;
+ branch = 0;
+ break;
+ }
+
+ if (conditional) {
+ switch ((bo & 0x1e) >> 1) {
+ case 0: /* 0000y */
+ if (--ctr != 0)
+ ctr_ok = 1;
+
+ cond_ok = !(cr & (1 << (31 - bi)));
+ break;
+
+ case 1: /* 0001y */
+ if (--ctr == 0)
+ ctr_ok = 1;
+
+ cond_ok = !(cr & (1 << (31 - bi)));
+ break;
+
+ case 2: /* 001zy */
+ ctr_ok = 1;
+ cond_ok = !(cr & (1 << (31 - bi)));
+ break;
+
+ case 4: /* 0100y */
+ if (--ctr != 0)
+ ctr_ok = 1;
+
+ cond_ok = cr & (1 << (31 - bi));
+ break;
+
+ case 5: /* 0101y */
+ if (--ctr == 0)
+ ctr_ok = 1;
+
+ cond_ok = cr & (1 << (31 - bi));
+ break;
+
+ case 6: /* 011zy */
+ ctr_ok = 1;
+ cond_ok = cr & (1 << (31 - bi));
+ break;
+
+ case 8: /* 1z00y */
+ if (--ctr != 0)
+ ctr_ok = cond_ok = 1;
+ break;
+
+ case 9: /* 1z01y */
+ if (--ctr == 0)
+ ctr_ok = cond_ok = 1;
+ break;
+
+ case 10: /* 1z1zz */
+ ctr_ok = cond_ok = 1;
+ break;
+ }
+ }
+
+ if (branch && (!conditional || (ctr_ok && cond_ok))) {
+ if (aa)
+ step = addr;
+ else
+ step = addr + pc;
+
+ if (lk)
+ next = pc + 4;
+ else
+ next = step;
+ } else {
+ step = next = pc + 4;
+ }
+
+ if (step_over == true)
+ *(unsigned long *) nextaddr = next;
+ else
+ *(unsigned long *) nextaddr = step;
+
+ return true;
+} /* find_next_address */
+
+
+/*
+ * Copyright (c) 2000 William L. Pitts and W. Gerald Hicks
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
diff --git a/roms/u-boot/common/bloblist.c b/roms/u-boot/common/bloblist.c
new file mode 100644
index 000000000..eab63e9ca
--- /dev/null
+++ b/roms/u-boot/common/bloblist.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <bloblist.h>
+#include <log.h>
+#include <mapmem.h>
+#include <spl.h>
+#include <asm/global_data.h>
+#include <u-boot/crc.h>
+
+/*
+ * A bloblist is a single contiguous chunk of memory with a header
+ * (struct bloblist_hdr) and a number of blobs in it.
+ *
+ * Each blob starts on a BLOBLIST_ALIGN boundary relative to the start of the
+ * bloblist and consists of a struct bloblist_rec, some padding to the required
+ * alignment for the blog and then the actual data. The padding ensures that the
+ * start address of the data in each blob is aligned as required. Note that
+ * each blob's *data* is aligned to BLOBLIST_ALIGN regardless of the alignment
+ * of the bloblist itself or the blob header.
+ *
+ * So far, only BLOBLIST_ALIGN alignment is supported.
+ */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *const tag_name[] = {
+ [BLOBLISTT_NONE] = "(none)",
+ [BLOBLISTT_EC_HOSTEVENT] = "EC host event",
+ [BLOBLISTT_SPL_HANDOFF] = "SPL hand-off",
+ [BLOBLISTT_VBOOT_CTX] = "Chrome OS vboot context",
+ [BLOBLISTT_VBOOT_HANDOFF] = "Chrome OS vboot hand-off",
+ [BLOBLISTT_ACPI_GNVS] = "ACPI GNVS",
+ [BLOBLISTT_INTEL_VBT] = "Intel Video-BIOS table",
+ [BLOBLISTT_TPM2_TCG_LOG] = "TPM v2 log space",
+ [BLOBLISTT_TCPA_LOG] = "TPM log space",
+ [BLOBLISTT_ACPI_TABLES] = "ACPI tables for x86",
+ [BLOBLISTT_SMBIOS_TABLES] = "SMBIOS tables for x86",
+};
+
+const char *bloblist_tag_name(enum bloblist_tag_t tag)
+{
+ if (tag < 0 || tag >= BLOBLISTT_COUNT)
+ return "invalid";
+
+ return tag_name[tag];
+}
+
+static struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
+{
+ if (hdr->alloced <= hdr->hdr_size)
+ return NULL;
+ return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
+}
+
+static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
+ struct bloblist_rec *rec)
+{
+ ulong offset;
+
+ offset = (void *)rec - (void *)hdr;
+ offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN);
+ if (offset >= hdr->alloced)
+ return NULL;
+ return (struct bloblist_rec *)((void *)hdr + offset);
+}
+
+#define foreach_rec(_rec, _hdr) \
+ for (_rec = bloblist_first_blob(_hdr); \
+ _rec; \
+ _rec = bloblist_next_blob(_hdr, _rec))
+
+static struct bloblist_rec *bloblist_findrec(uint tag)
+{
+ struct bloblist_hdr *hdr = gd->bloblist;
+ struct bloblist_rec *rec;
+
+ if (!hdr)
+ return NULL;
+
+ foreach_rec(rec, hdr) {
+ if (rec->tag == tag)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static int bloblist_addrec(uint tag, int size, int align,
+ struct bloblist_rec **recp)
+{
+ struct bloblist_hdr *hdr = gd->bloblist;
+ struct bloblist_rec *rec;
+ int data_start, new_alloced;
+
+ if (!align)
+ align = BLOBLIST_ALIGN;
+
+ /* Figure out where the new data will start */
+ data_start = map_to_sysmem(hdr) + hdr->alloced + sizeof(*rec);
+
+ /* Align the address and then calculate the offset from ->alloced */
+ data_start = ALIGN(data_start, align) - map_to_sysmem(hdr);
+
+ /* Calculate the new allocated total */
+ new_alloced = data_start + ALIGN(size, align);
+
+ if (new_alloced >= hdr->size) {
+ log(LOGC_BLOBLIST, LOGL_ERR,
+ "Failed to allocate %x bytes size=%x, need size=%x\n",
+ size, hdr->size, new_alloced);
+ return log_msg_ret("bloblist add", -ENOSPC);
+ }
+ rec = (void *)hdr + hdr->alloced;
+
+ rec->tag = tag;
+ rec->hdr_size = data_start - hdr->alloced;
+ rec->size = size;
+ rec->spare = 0;
+
+ /* Zero the record data */
+ memset((void *)rec + rec->hdr_size, '\0', rec->size);
+
+ hdr->alloced = new_alloced;
+ *recp = rec;
+
+ return 0;
+}
+
+static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size,
+ int align)
+{
+ struct bloblist_rec *rec;
+
+ rec = bloblist_findrec(tag);
+ if (rec) {
+ if (size && size != rec->size) {
+ *recp = rec;
+ return -ESPIPE;
+ }
+ } else {
+ int ret;
+
+ ret = bloblist_addrec(tag, size, align, &rec);
+ if (ret)
+ return ret;
+ }
+ *recp = rec;
+
+ return 0;
+}
+
+void *bloblist_find(uint tag, int size)
+{
+ struct bloblist_rec *rec;
+
+ rec = bloblist_findrec(tag);
+ if (!rec)
+ return NULL;
+ if (size && size != rec->size)
+ return NULL;
+
+ return (void *)rec + rec->hdr_size;
+}
+
+void *bloblist_add(uint tag, int size, int align)
+{
+ struct bloblist_rec *rec;
+
+ if (bloblist_addrec(tag, size, align, &rec))
+ return NULL;
+
+ return (void *)rec + rec->hdr_size;
+}
+
+int bloblist_ensure_size(uint tag, int size, int align, void **blobp)
+{
+ struct bloblist_rec *rec;
+ int ret;
+
+ ret = bloblist_ensurerec(tag, &rec, size, align);
+ if (ret)
+ return ret;
+ *blobp = (void *)rec + rec->hdr_size;
+
+ return 0;
+}
+
+void *bloblist_ensure(uint tag, int size)
+{
+ struct bloblist_rec *rec;
+
+ if (bloblist_ensurerec(tag, &rec, size, 0))
+ return NULL;
+
+ return (void *)rec + rec->hdr_size;
+}
+
+int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp)
+{
+ struct bloblist_rec *rec;
+ int ret;
+
+ ret = bloblist_ensurerec(tag, &rec, *sizep, 0);
+ if (ret == -ESPIPE)
+ *sizep = rec->size;
+ else if (ret)
+ return ret;
+ *blobp = (void *)rec + rec->hdr_size;
+
+ return 0;
+}
+
+static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr)
+{
+ struct bloblist_rec *rec;
+ u32 chksum;
+
+ chksum = crc32(0, (unsigned char *)hdr,
+ offsetof(struct bloblist_hdr, chksum));
+ foreach_rec(rec, hdr) {
+ chksum = crc32(chksum, (void *)rec, rec->hdr_size);
+ chksum = crc32(chksum, (void *)rec + rec->hdr_size, rec->size);
+ }
+
+ return chksum;
+}
+
+int bloblist_new(ulong addr, uint size, uint flags)
+{
+ struct bloblist_hdr *hdr;
+
+ if (size < sizeof(*hdr))
+ return log_ret(-ENOSPC);
+ if (addr & (BLOBLIST_ALIGN - 1))
+ return log_ret(-EFAULT);
+ hdr = map_sysmem(addr, size);
+ memset(hdr, '\0', sizeof(*hdr));
+ hdr->version = BLOBLIST_VERSION;
+ hdr->hdr_size = sizeof(*hdr);
+ hdr->flags = flags;
+ hdr->magic = BLOBLIST_MAGIC;
+ hdr->size = size;
+ hdr->alloced = hdr->hdr_size;
+ hdr->chksum = 0;
+ gd->bloblist = hdr;
+
+ return 0;
+}
+
+int bloblist_check(ulong addr, uint size)
+{
+ struct bloblist_hdr *hdr;
+ u32 chksum;
+
+ hdr = map_sysmem(addr, sizeof(*hdr));
+ if (hdr->magic != BLOBLIST_MAGIC)
+ return log_msg_ret("Bad magic", -ENOENT);
+ if (hdr->version != BLOBLIST_VERSION)
+ return log_msg_ret("Bad version", -EPROTONOSUPPORT);
+ if (size && hdr->size != size)
+ return log_msg_ret("Bad size", -EFBIG);
+ chksum = bloblist_calc_chksum(hdr);
+ if (hdr->chksum != chksum) {
+ log(LOGC_BLOBLIST, LOGL_ERR, "Checksum %x != %x\n", hdr->chksum,
+ chksum);
+ return log_msg_ret("Bad checksum", -EIO);
+ }
+ gd->bloblist = hdr;
+
+ return 0;
+}
+
+int bloblist_finish(void)
+{
+ struct bloblist_hdr *hdr = gd->bloblist;
+
+ hdr->chksum = bloblist_calc_chksum(hdr);
+
+ return 0;
+}
+
+void bloblist_get_stats(ulong *basep, ulong *sizep, ulong *allocedp)
+{
+ struct bloblist_hdr *hdr = gd->bloblist;
+
+ *basep = map_to_sysmem(gd->bloblist);
+ *sizep = hdr->size;
+ *allocedp = hdr->alloced;
+}
+
+static void show_value(const char *prompt, ulong value)
+{
+ printf("%s:%*s %-5lx ", prompt, 8 - (int)strlen(prompt), "", value);
+ print_size(value, "\n");
+}
+
+void bloblist_show_stats(void)
+{
+ ulong base, size, alloced;
+
+ bloblist_get_stats(&base, &size, &alloced);
+ printf("base: %lx\n", base);
+ show_value("size", size);
+ show_value("alloced", alloced);
+ show_value("free", size - alloced);
+}
+
+void bloblist_show_list(void)
+{
+ struct bloblist_hdr *hdr = gd->bloblist;
+ struct bloblist_rec *rec;
+
+ printf("%-8s %8s Tag Name\n", "Address", "Size");
+ for (rec = bloblist_first_blob(hdr); rec;
+ rec = bloblist_next_blob(hdr, rec)) {
+ printf("%08lx %8x %3d %s\n",
+ (ulong)map_to_sysmem((void *)rec + rec->hdr_size),
+ rec->size, rec->tag, bloblist_tag_name(rec->tag));
+ }
+}
+
+void bloblist_reloc(void *to, uint to_size, void *from, uint from_size)
+{
+ struct bloblist_hdr *hdr;
+
+ memcpy(to, from, from_size);
+ hdr = to;
+ hdr->size = to_size;
+}
+
+int bloblist_init(void)
+{
+ bool expected;
+ int ret = -ENOENT;
+
+ /**
+ * Wed expect to find an existing bloblist in the first phase of U-Boot
+ * that runs
+ */
+ expected = !u_boot_first_phase();
+ if (spl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST))
+ expected = false;
+ if (expected)
+ ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
+ CONFIG_BLOBLIST_SIZE);
+ if (ret) {
+ log(LOGC_BLOBLIST, expected ? LOGL_WARNING : LOGL_DEBUG,
+ "Existing bloblist not found: creating new bloblist\n");
+ ret = bloblist_new(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE,
+ 0);
+ } else {
+ log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing bloblist\n");
+ }
+
+ return ret;
+}
diff --git a/roms/u-boot/common/board_f.c b/roms/u-boot/common/board_f.c
new file mode 100644
index 000000000..203e96579
--- /dev/null
+++ b/roms/u-boot/common/board_f.c
@@ -0,0 +1,1016 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2002-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ */
+
+#include <common.h>
+#include <bloblist.h>
+#include <bootstage.h>
+#include <clock_legacy.h>
+#include <console.h>
+#include <cpu.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <env.h>
+#include <env_internal.h>
+#include <fdtdec.h>
+#include <fs.h>
+#include <hang.h>
+#include <i2c.h>
+#include <init.h>
+#include <initcall.h>
+#include <lcd.h>
+#include <log.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <os.h>
+#include <post.h>
+#include <relocate.h>
+#include <serial.h>
+#ifdef CONFIG_SPL
+#include <spl.h>
+#endif
+#include <status_led.h>
+#include <sysreset.h>
+#include <timer.h>
+#include <trace.h>
+#include <video.h>
+#include <watchdog.h>
+#include <asm/cache.h>
+#ifdef CONFIG_MACH_TYPE
+#include <asm/mach-types.h>
+#endif
+#if defined(CONFIG_MP) && defined(CONFIG_PPC)
+#include <asm/mp.h>
+#endif
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <dm/root.h>
+#include <linux/errno.h>
+
+/*
+ * Pointer to initial global data area
+ *
+ * Here we initialize it if needed.
+ */
+#ifdef XTRN_DECLARE_GLOBAL_DATA_PTR
+#undef XTRN_DECLARE_GLOBAL_DATA_PTR
+#define XTRN_DECLARE_GLOBAL_DATA_PTR /* empty = allocate here */
+DECLARE_GLOBAL_DATA_PTR = (gd_t *)(CONFIG_SYS_INIT_GD_ADDR);
+#else
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+/*
+ * TODO(sjg@chromium.org): IMO this code should be
+ * refactored to a single function, something like:
+ *
+ * void led_set_state(enum led_colour_t colour, int on);
+ */
+/************************************************************************
+ * Coloured LED functionality
+ ************************************************************************
+ * May be supplied by boards if desired
+ */
+__weak void coloured_LED_init(void) {}
+__weak void red_led_on(void) {}
+__weak void red_led_off(void) {}
+__weak void green_led_on(void) {}
+__weak void green_led_off(void) {}
+__weak void yellow_led_on(void) {}
+__weak void yellow_led_off(void) {}
+__weak void blue_led_on(void) {}
+__weak void blue_led_off(void) {}
+
+/*
+ * Why is gd allocated a register? Prior to reloc it might be better to
+ * just pass it around to each function in this file?
+ *
+ * After reloc one could argue that it is hardly used and doesn't need
+ * to be in a register. Or if it is it should perhaps hold pointers to all
+ * global data for all modules, so that post-reloc we can avoid the massive
+ * literal pool we get on ARM. Or perhaps just encourage each module to use
+ * a structure...
+ */
+
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG)
+static int init_func_watchdog_init(void)
+{
+# if defined(CONFIG_HW_WATCHDOG) && \
+ (defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \
+ defined(CONFIG_SH) || \
+ defined(CONFIG_DESIGNWARE_WATCHDOG) || \
+ defined(CONFIG_IMX_WATCHDOG))
+ hw_watchdog_init();
+ puts(" Watchdog enabled\n");
+# endif
+ WATCHDOG_RESET();
+
+ return 0;
+}
+
+int init_func_watchdog_reset(void)
+{
+ WATCHDOG_RESET();
+
+ return 0;
+}
+#endif /* CONFIG_WATCHDOG */
+
+__weak void board_add_ram_info(int use_default)
+{
+ /* please define platform specific board_add_ram_info() */
+}
+
+static int init_baud_rate(void)
+{
+ gd->baudrate = env_get_ulong("baudrate", 10, CONFIG_BAUDRATE);
+ return 0;
+}
+
+static int display_text_info(void)
+{
+#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_EFI_APP)
+ ulong bss_start, bss_end, text_base;
+
+ bss_start = (ulong)&__bss_start;
+ bss_end = (ulong)&__bss_end;
+
+#ifdef CONFIG_SYS_TEXT_BASE
+ text_base = CONFIG_SYS_TEXT_BASE;
+#else
+ text_base = CONFIG_SYS_MONITOR_BASE;
+#endif
+
+ debug("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",
+ text_base, bss_start, bss_end);
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_SYSRESET
+static int print_resetinfo(void)
+{
+ struct udevice *dev;
+ char status[256];
+ int ret;
+
+ ret = uclass_first_device_err(UCLASS_SYSRESET, &dev);
+ if (ret) {
+ debug("%s: No sysreset device found (error: %d)\n",
+ __func__, ret);
+ /* Not all boards have sysreset drivers available during early
+ * boot, so don't fail if one can't be found.
+ */
+ return 0;
+ }
+
+ if (!sysreset_get_status(dev, status, sizeof(status)))
+ printf("%s", status);
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_DISPLAY_CPUINFO) && CONFIG_IS_ENABLED(CPU)
+static int print_cpuinfo(void)
+{
+ struct udevice *dev;
+ char desc[512];
+ int ret;
+
+ dev = cpu_get_current_dev();
+ if (!dev) {
+ debug("%s: Could not get CPU device\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ ret = cpu_get_desc(dev, desc, sizeof(desc));
+ if (ret) {
+ debug("%s: Could not get CPU description (err = %d)\n",
+ dev->name, ret);
+ return ret;
+ }
+
+ printf("CPU: %s\n", desc);
+
+ return 0;
+}
+#endif
+
+static int announce_dram_init(void)
+{
+ puts("DRAM: ");
+ return 0;
+}
+
+static int show_dram_config(void)
+{
+ unsigned long long size;
+ int i;
+
+ debug("\nRAM Configuration:\n");
+ for (i = size = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ size += gd->bd->bi_dram[i].size;
+ debug("Bank #%d: %llx ", i,
+ (unsigned long long)(gd->bd->bi_dram[i].start));
+#ifdef DEBUG
+ print_size(gd->bd->bi_dram[i].size, "\n");
+#endif
+ }
+ debug("\nDRAM: ");
+
+ print_size(size, "");
+ board_add_ram_info(0);
+ putc('\n');
+
+ return 0;
+}
+
+__weak int dram_init_banksize(void)
+{
+ gd->bd->bi_dram[0].start = gd->ram_base;
+ gd->bd->bi_dram[0].size = get_effective_memsize();
+
+ return 0;
+}
+
+#if defined(CONFIG_SYS_I2C)
+static int init_func_i2c(void)
+{
+ puts("I2C: ");
+ i2c_init_all();
+ puts("ready\n");
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_VID)
+__weak int init_func_vid(void)
+{
+ return 0;
+}
+#endif
+
+static int setup_mon_len(void)
+{
+#if defined(__ARM__) || defined(__MICROBLAZE__)
+ gd->mon_len = (ulong)&__bss_end - (ulong)_start;
+#elif defined(CONFIG_SANDBOX) || defined(CONFIG_EFI_APP)
+ gd->mon_len = (ulong)&_end - (ulong)_init;
+#elif defined(CONFIG_NIOS2) || defined(CONFIG_XTENSA)
+ gd->mon_len = CONFIG_SYS_MONITOR_LEN;
+#elif defined(CONFIG_NDS32) || defined(CONFIG_SH) || defined(CONFIG_RISCV)
+ gd->mon_len = (ulong)(&__bss_end) - (ulong)(&_start);
+#elif defined(CONFIG_SYS_MONITOR_BASE)
+ /* TODO: use (ulong)&__bss_end - (ulong)&__text_start; ? */
+ gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
+#endif
+ return 0;
+}
+
+static int setup_spl_handoff(void)
+{
+#if CONFIG_IS_ENABLED(HANDOFF)
+ gd->spl_handoff = bloblist_find(BLOBLISTT_SPL_HANDOFF,
+ sizeof(struct spl_handoff));
+ debug("Found SPL hand-off info %p\n", gd->spl_handoff);
+#endif
+
+ return 0;
+}
+
+__weak int arch_cpu_init(void)
+{
+ return 0;
+}
+
+__weak int mach_cpu_init(void)
+{
+ return 0;
+}
+
+/* Get the top of usable RAM */
+__weak ulong board_get_usable_ram_top(ulong total_size)
+{
+#if defined(CONFIG_SYS_SDRAM_BASE) && CONFIG_SYS_SDRAM_BASE > 0
+ /*
+ * Detect whether we have so much RAM that it goes past the end of our
+ * 32-bit address space. If so, clip the usable RAM so it doesn't.
+ */
+ if (gd->ram_top < CONFIG_SYS_SDRAM_BASE)
+ /*
+ * Will wrap back to top of 32-bit space when reservations
+ * are made.
+ */
+ return 0;
+#endif
+ return gd->ram_top;
+}
+
+static int setup_dest_addr(void)
+{
+ debug("Monitor len: %08lX\n", gd->mon_len);
+ /*
+ * Ram is setup, size stored in gd !!
+ */
+ debug("Ram size: %08lX\n", (ulong)gd->ram_size);
+#if defined(CONFIG_SYS_MEM_TOP_HIDE)
+ /*
+ * Subtract specified amount of memory to hide so that it won't
+ * get "touched" at all by U-Boot. By fixing up gd->ram_size
+ * the Linux kernel should now get passed the now "corrected"
+ * memory size and won't touch it either. This should work
+ * for arch/ppc and arch/powerpc. Only Linux board ports in
+ * arch/powerpc with bootwrapper support, that recalculate the
+ * memory size from the SDRAM controller setup will have to
+ * get fixed.
+ */
+ gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
+#endif
+#ifdef CONFIG_SYS_SDRAM_BASE
+ gd->ram_base = CONFIG_SYS_SDRAM_BASE;
+#endif
+ gd->ram_top = gd->ram_base + get_effective_memsize();
+ gd->ram_top = board_get_usable_ram_top(gd->mon_len);
+ gd->relocaddr = gd->ram_top;
+ debug("Ram top: %08lX\n", (ulong)gd->ram_top);
+#if defined(CONFIG_MP) && (defined(CONFIG_MPC86xx) || defined(CONFIG_E500))
+ /*
+ * We need to make sure the location we intend to put secondary core
+ * boot code is reserved and not used by any part of u-boot
+ */
+ if (gd->relocaddr > determine_mp_bootpg(NULL)) {
+ gd->relocaddr = determine_mp_bootpg(NULL);
+ debug("Reserving MP boot page to %08lx\n", gd->relocaddr);
+ }
+#endif
+ return 0;
+}
+
+#ifdef CONFIG_PRAM
+/* reserve protected RAM */
+static int reserve_pram(void)
+{
+ ulong reg;
+
+ reg = env_get_ulong("pram", 10, CONFIG_PRAM);
+ gd->relocaddr -= (reg << 10); /* size is in kB */
+ debug("Reserving %ldk for protected RAM at %08lx\n", reg,
+ gd->relocaddr);
+ return 0;
+}
+#endif /* CONFIG_PRAM */
+
+/* Round memory pointer down to next 4 kB limit */
+static int reserve_round_4k(void)
+{
+ gd->relocaddr &= ~(4096 - 1);
+ return 0;
+}
+
+__weak int arch_reserve_mmu(void)
+{
+ return 0;
+}
+
+static int reserve_video(void)
+{
+#ifdef CONFIG_DM_VIDEO
+ ulong addr;
+ int ret;
+
+ addr = gd->relocaddr;
+ ret = video_reserve(&addr);
+ if (ret)
+ return ret;
+ debug("Reserving %luk for video at: %08lx\n",
+ ((unsigned long)gd->relocaddr - addr) >> 10, addr);
+ gd->relocaddr = addr;
+#elif defined(CONFIG_LCD)
+# ifdef CONFIG_FB_ADDR
+ gd->fb_base = CONFIG_FB_ADDR;
+# else
+ /* reserve memory for LCD display (always full pages) */
+ gd->relocaddr = lcd_setmem(gd->relocaddr);
+ gd->fb_base = gd->relocaddr;
+# endif /* CONFIG_FB_ADDR */
+#endif
+
+ return 0;
+}
+
+static int reserve_trace(void)
+{
+#ifdef CONFIG_TRACE
+ gd->relocaddr -= CONFIG_TRACE_BUFFER_SIZE;
+ gd->trace_buff = map_sysmem(gd->relocaddr, CONFIG_TRACE_BUFFER_SIZE);
+ debug("Reserving %luk for trace data at: %08lx\n",
+ (unsigned long)CONFIG_TRACE_BUFFER_SIZE >> 10, gd->relocaddr);
+#endif
+
+ return 0;
+}
+
+static int reserve_uboot(void)
+{
+ if (!(gd->flags & GD_FLG_SKIP_RELOC)) {
+ /*
+ * reserve memory for U-Boot code, data & bss
+ * round down to next 4 kB limit
+ */
+ gd->relocaddr -= gd->mon_len;
+ gd->relocaddr &= ~(4096 - 1);
+ #if defined(CONFIG_E500) || defined(CONFIG_MIPS)
+ /* round down to next 64 kB limit so that IVPR stays aligned */
+ gd->relocaddr &= ~(65536 - 1);
+ #endif
+
+ debug("Reserving %ldk for U-Boot at: %08lx\n",
+ gd->mon_len >> 10, gd->relocaddr);
+ }
+
+ gd->start_addr_sp = gd->relocaddr;
+
+ return 0;
+}
+
+/*
+ * reserve after start_addr_sp the requested size and make the stack pointer
+ * 16-byte aligned, this alignment is needed for cast on the reserved memory
+ * ref = x86_64 ABI: https://reviews.llvm.org/D30049: 16 bytes
+ * = ARMv8 Instruction Set Overview: quad word, 16 bytes
+ */
+static unsigned long reserve_stack_aligned(size_t size)
+{
+ return ALIGN_DOWN(gd->start_addr_sp - size, 16);
+}
+
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+static int reserve_noncached(void)
+{
+ /*
+ * The value of gd->start_addr_sp must match the value of malloc_start
+ * calculated in boatrd_f.c:initr_malloc(), which is passed to
+ * board_r.c:mem_malloc_init() and then used by
+ * cache.c:noncached_init()
+ *
+ * These calculations must match the code in cache.c:noncached_init()
+ */
+ gd->start_addr_sp = ALIGN(gd->start_addr_sp, MMU_SECTION_SIZE) -
+ MMU_SECTION_SIZE;
+ gd->start_addr_sp -= ALIGN(CONFIG_SYS_NONCACHED_MEMORY,
+ MMU_SECTION_SIZE);
+ debug("Reserving %dM for noncached_alloc() at: %08lx\n",
+ CONFIG_SYS_NONCACHED_MEMORY >> 20, gd->start_addr_sp);
+
+ return 0;
+}
+#endif
+
+/* reserve memory for malloc() area */
+static int reserve_malloc(void)
+{
+ gd->start_addr_sp = reserve_stack_aligned(TOTAL_MALLOC_LEN);
+ debug("Reserving %dk for malloc() at: %08lx\n",
+ TOTAL_MALLOC_LEN >> 10, gd->start_addr_sp);
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+ reserve_noncached();
+#endif
+
+ return 0;
+}
+
+/* (permanently) allocate a Board Info struct */
+static int reserve_board(void)
+{
+ if (!gd->bd) {
+ gd->start_addr_sp = reserve_stack_aligned(sizeof(struct bd_info));
+ gd->bd = (struct bd_info *)map_sysmem(gd->start_addr_sp,
+ sizeof(struct bd_info));
+ memset(gd->bd, '\0', sizeof(struct bd_info));
+ debug("Reserving %zu Bytes for Board Info at: %08lx\n",
+ sizeof(struct bd_info), gd->start_addr_sp);
+ }
+ return 0;
+}
+
+static int reserve_global_data(void)
+{
+ gd->start_addr_sp = reserve_stack_aligned(sizeof(gd_t));
+ gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
+ debug("Reserving %zu Bytes for Global Data at: %08lx\n",
+ sizeof(gd_t), gd->start_addr_sp);
+ return 0;
+}
+
+static int reserve_fdt(void)
+{
+ if (!IS_ENABLED(CONFIG_OF_EMBED)) {
+ /*
+ * If the device tree is sitting immediately above our image
+ * then we must relocate it. If it is embedded in the data
+ * section, then it will be relocated with other data.
+ */
+ if (gd->fdt_blob) {
+ gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob), 32);
+
+ gd->start_addr_sp = reserve_stack_aligned(gd->fdt_size);
+ gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
+ debug("Reserving %lu Bytes for FDT at: %08lx\n",
+ gd->fdt_size, gd->start_addr_sp);
+ }
+ }
+
+ return 0;
+}
+
+static int reserve_bootstage(void)
+{
+#ifdef CONFIG_BOOTSTAGE
+ int size = bootstage_get_size();
+
+ gd->start_addr_sp = reserve_stack_aligned(size);
+ gd->new_bootstage = map_sysmem(gd->start_addr_sp, size);
+ debug("Reserving %#x Bytes for bootstage at: %08lx\n", size,
+ gd->start_addr_sp);
+#endif
+
+ return 0;
+}
+
+__weak int arch_reserve_stacks(void)
+{
+ return 0;
+}
+
+static int reserve_stacks(void)
+{
+ /* make stack pointer 16-byte aligned */
+ gd->start_addr_sp = reserve_stack_aligned(16);
+
+ /*
+ * let the architecture-specific code tailor gd->start_addr_sp and
+ * gd->irq_sp
+ */
+ return arch_reserve_stacks();
+}
+
+static int reserve_bloblist(void)
+{
+#ifdef CONFIG_BLOBLIST
+ /* Align to a 4KB boundary for easier reading of addresses */
+ gd->start_addr_sp = ALIGN_DOWN(gd->start_addr_sp -
+ CONFIG_BLOBLIST_SIZE_RELOC, 0x1000);
+ gd->new_bloblist = map_sysmem(gd->start_addr_sp,
+ CONFIG_BLOBLIST_SIZE_RELOC);
+#endif
+
+ return 0;
+}
+
+static int display_new_sp(void)
+{
+ debug("New Stack Pointer is: %08lx\n", gd->start_addr_sp);
+
+ return 0;
+}
+
+__weak int arch_setup_bdinfo(void)
+{
+ return 0;
+}
+
+int setup_bdinfo(void)
+{
+ struct bd_info *bd = gd->bd;
+
+ if (IS_ENABLED(CONFIG_SYS_HAS_SRAM)) {
+ bd->bi_sramstart = CONFIG_SYS_SRAM_BASE; /* start of SRAM */
+ bd->bi_sramsize = CONFIG_SYS_SRAM_SIZE; /* size of SRAM */
+ }
+
+#ifdef CONFIG_MACH_TYPE
+ bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
+#endif
+
+ return arch_setup_bdinfo();
+}
+
+#ifdef CONFIG_POST
+static int init_post(void)
+{
+ post_bootmode_init();
+ post_run(NULL, POST_ROM | post_bootmode_get(0));
+
+ return 0;
+}
+#endif
+
+static int reloc_fdt(void)
+{
+ if (!IS_ENABLED(CONFIG_OF_EMBED)) {
+ if (gd->flags & GD_FLG_SKIP_RELOC)
+ return 0;
+ if (gd->new_fdt) {
+ memcpy(gd->new_fdt, gd->fdt_blob,
+ fdt_totalsize(gd->fdt_blob));
+ gd->fdt_blob = gd->new_fdt;
+ }
+ }
+
+ return 0;
+}
+
+static int reloc_bootstage(void)
+{
+#ifdef CONFIG_BOOTSTAGE
+ if (gd->flags & GD_FLG_SKIP_RELOC)
+ return 0;
+ if (gd->new_bootstage) {
+ int size = bootstage_get_size();
+
+ debug("Copying bootstage from %p to %p, size %x\n",
+ gd->bootstage, gd->new_bootstage, size);
+ memcpy(gd->new_bootstage, gd->bootstage, size);
+ gd->bootstage = gd->new_bootstage;
+ bootstage_relocate();
+ }
+#endif
+
+ return 0;
+}
+
+static int reloc_bloblist(void)
+{
+#ifdef CONFIG_BLOBLIST
+ if (gd->flags & GD_FLG_SKIP_RELOC)
+ return 0;
+ if (gd->new_bloblist) {
+ int size = CONFIG_BLOBLIST_SIZE;
+
+ debug("Copying bloblist from %p to %p, size %x\n",
+ gd->bloblist, gd->new_bloblist, size);
+ bloblist_reloc(gd->new_bloblist, CONFIG_BLOBLIST_SIZE_RELOC,
+ gd->bloblist, size);
+ gd->bloblist = gd->new_bloblist;
+ }
+#endif
+
+ return 0;
+}
+
+static int setup_reloc(void)
+{
+ if (gd->flags & GD_FLG_SKIP_RELOC) {
+ debug("Skipping relocation due to flag\n");
+ return 0;
+ }
+
+#ifdef CONFIG_SYS_TEXT_BASE
+#ifdef ARM
+ gd->reloc_off = gd->relocaddr - (unsigned long)__image_copy_start;
+#elif defined(CONFIG_M68K)
+ /*
+ * On all ColdFire arch cpu, monitor code starts always
+ * just after the default vector table location, so at 0x400
+ */
+ gd->reloc_off = gd->relocaddr - (CONFIG_SYS_TEXT_BASE + 0x400);
+#elif !defined(CONFIG_SANDBOX)
+ gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
+#endif
+#endif
+ memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));
+
+ debug("Relocation Offset is: %08lx\n", gd->reloc_off);
+ debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n",
+ gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd),
+ gd->start_addr_sp);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF_BOARD_FIXUP
+static int fix_fdt(void)
+{
+ return board_fix_fdt((void *)gd->fdt_blob);
+}
+#endif
+
+/* ARM calls relocate_code from its crt0.S */
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
+ !CONFIG_IS_ENABLED(X86_64)
+
+static int jump_to_copy(void)
+{
+ if (gd->flags & GD_FLG_SKIP_RELOC)
+ return 0;
+ /*
+ * x86 is special, but in a nice way. It uses a trampoline which
+ * enables the dcache if possible.
+ *
+ * For now, other archs use relocate_code(), which is implemented
+ * similarly for all archs. When we do generic relocation, hopefully
+ * we can make all archs enable the dcache prior to relocation.
+ */
+#if defined(CONFIG_X86) || defined(CONFIG_ARC)
+ /*
+ * SDRAM and console are now initialised. The final stack can now
+ * be setup in SDRAM. Code execution will continue in Flash, but
+ * with the stack in SDRAM and Global Data in temporary memory
+ * (CPU cache)
+ */
+ arch_setup_gd(gd->new_gd);
+ board_init_f_r_trampoline(gd->start_addr_sp);
+#else
+ relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr);
+#endif
+
+ return 0;
+}
+#endif
+
+/* Record the board_init_f() bootstage (after arch_cpu_init()) */
+static int initf_bootstage(void)
+{
+ bool from_spl = IS_ENABLED(CONFIG_SPL_BOOTSTAGE) &&
+ IS_ENABLED(CONFIG_BOOTSTAGE_STASH);
+ int ret;
+
+ ret = bootstage_init(!from_spl);
+ if (ret)
+ return ret;
+ if (from_spl) {
+ const void *stash = map_sysmem(CONFIG_BOOTSTAGE_STASH_ADDR,
+ CONFIG_BOOTSTAGE_STASH_SIZE);
+
+ ret = bootstage_unstash(stash, CONFIG_BOOTSTAGE_STASH_SIZE);
+ if (ret && ret != -ENOENT) {
+ debug("Failed to unstash bootstage: err=%d\n", ret);
+ return ret;
+ }
+ }
+
+ bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");
+
+ return 0;
+}
+
+static int initf_dm(void)
+{
+#if defined(CONFIG_DM) && CONFIG_VAL(SYS_MALLOC_F_LEN)
+ int ret;
+
+ bootstage_start(BOOTSTAGE_ID_ACCUM_DM_F, "dm_f");
+ ret = dm_init_and_scan(true);
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_F);
+ if (ret)
+ return ret;
+
+ if (IS_ENABLED(CONFIG_TIMER_EARLY)) {
+ ret = dm_timer_init();
+ if (ret)
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+/* Architecture-specific memory reservation */
+__weak int reserve_arch(void)
+{
+ return 0;
+}
+
+__weak int arch_cpu_init_dm(void)
+{
+ return 0;
+}
+
+__weak int checkcpu(void)
+{
+ return 0;
+}
+
+__weak int clear_bss(void)
+{
+ return 0;
+}
+
+static const init_fnc_t init_sequence_f[] = {
+ setup_mon_len,
+#ifdef CONFIG_OF_CONTROL
+ fdtdec_setup,
+#endif
+#ifdef CONFIG_TRACE_EARLY
+ trace_early_init,
+#endif
+ initf_malloc,
+ log_init,
+ initf_bootstage, /* uses its own timer, so does not need DM */
+#ifdef CONFIG_BLOBLIST
+ bloblist_init,
+#endif
+ setup_spl_handoff,
+#if defined(CONFIG_CONSOLE_RECORD_INIT_F)
+ console_record_init,
+#endif
+#if defined(CONFIG_HAVE_FSP)
+ arch_fsp_init,
+#endif
+ arch_cpu_init, /* basic arch cpu dependent setup */
+ mach_cpu_init, /* SoC/machine dependent CPU setup */
+ initf_dm,
+ arch_cpu_init_dm,
+#if defined(CONFIG_BOARD_EARLY_INIT_F)
+ board_early_init_f,
+#endif
+#if defined(CONFIG_PPC) || defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
+ /* get CPU and bus clocks according to the environment variable */
+ get_clocks, /* get CPU and bus clocks (etc.) */
+#endif
+#if !defined(CONFIG_M68K)
+ timer_init, /* initialize timer */
+#endif
+#if defined(CONFIG_BOARD_POSTCLK_INIT)
+ board_postclk_init,
+#endif
+ env_init, /* initialize environment */
+ init_baud_rate, /* initialze baudrate settings */
+ serial_init, /* serial communications setup */
+ console_init_f, /* stage 1 init of console */
+ display_options, /* say that we are here */
+ display_text_info, /* show debugging info if required */
+ checkcpu,
+#if defined(CONFIG_SYSRESET)
+ print_resetinfo,
+#endif
+#if defined(CONFIG_DISPLAY_CPUINFO)
+ print_cpuinfo, /* display cpu info (and speed) */
+#endif
+#if defined(CONFIG_DTB_RESELECT)
+ embedded_dtb_select,
+#endif
+#if defined(CONFIG_DISPLAY_BOARDINFO)
+ show_board_info,
+#endif
+ INIT_FUNC_WATCHDOG_INIT
+#if defined(CONFIG_MISC_INIT_F)
+ misc_init_f,
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+#if defined(CONFIG_SYS_I2C)
+ init_func_i2c,
+#endif
+#if defined(CONFIG_VID) && !defined(CONFIG_SPL)
+ init_func_vid,
+#endif
+ announce_dram_init,
+ dram_init, /* configure available RAM banks */
+#ifdef CONFIG_POST
+ post_init_f,
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+#if defined(CONFIG_SYS_DRAM_TEST)
+ testdram,
+#endif /* CONFIG_SYS_DRAM_TEST */
+ INIT_FUNC_WATCHDOG_RESET
+
+#ifdef CONFIG_POST
+ init_post,
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+ /*
+ * Now that we have DRAM mapped and working, we can
+ * relocate the code and continue running from DRAM.
+ *
+ * Reserve memory at end of RAM for (top down in that order):
+ * - area that won't get touched by U-Boot and Linux (optional)
+ * - kernel log buffer
+ * - protected RAM
+ * - LCD framebuffer
+ * - monitor code
+ * - board info struct
+ */
+ setup_dest_addr,
+#ifdef CONFIG_OF_BOARD_FIXUP
+ fix_fdt,
+#endif
+#ifdef CONFIG_PRAM
+ reserve_pram,
+#endif
+ reserve_round_4k,
+ arch_reserve_mmu,
+ reserve_video,
+ reserve_trace,
+ reserve_uboot,
+ reserve_malloc,
+ reserve_board,
+ reserve_global_data,
+ reserve_fdt,
+ reserve_bootstage,
+ reserve_bloblist,
+ reserve_arch,
+ reserve_stacks,
+ dram_init_banksize,
+ show_dram_config,
+ INIT_FUNC_WATCHDOG_RESET
+ setup_bdinfo,
+ display_new_sp,
+ INIT_FUNC_WATCHDOG_RESET
+ reloc_fdt,
+ reloc_bootstage,
+ reloc_bloblist,
+ setup_reloc,
+#if defined(CONFIG_X86) || defined(CONFIG_ARC)
+ copy_uboot_to_ram,
+ do_elf_reloc_fixups,
+#endif
+ clear_bss,
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
+ !CONFIG_IS_ENABLED(X86_64)
+ jump_to_copy,
+#endif
+ NULL,
+};
+
+void board_init_f(ulong boot_flags)
+{
+ gd->flags = boot_flags;
+ gd->have_console = 0;
+
+ if (initcall_run_list(init_sequence_f))
+ hang();
+
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
+ !defined(CONFIG_EFI_APP) && !CONFIG_IS_ENABLED(X86_64) && \
+ !defined(CONFIG_ARC)
+ /* NOTREACHED - jump_to_copy() does not return */
+ hang();
+#endif
+}
+
+#if defined(CONFIG_X86) || defined(CONFIG_ARC)
+/*
+ * For now this code is only used on x86.
+ *
+ * init_sequence_f_r is the list of init functions which are run when
+ * U-Boot is executing from Flash with a semi-limited 'C' environment.
+ * The following limitations must be considered when implementing an
+ * '_f_r' function:
+ * - 'static' variables are read-only
+ * - Global Data (gd->xxx) is read/write
+ *
+ * The '_f_r' sequence must, as a minimum, copy U-Boot to RAM (if
+ * supported). It _should_, if possible, copy global data to RAM and
+ * initialise the CPU caches (to speed up the relocation process)
+ *
+ * NOTE: At present only x86 uses this route, but it is intended that
+ * all archs will move to this when generic relocation is implemented.
+ */
+static const init_fnc_t init_sequence_f_r[] = {
+#if !CONFIG_IS_ENABLED(X86_64)
+ init_cache_f_r,
+#endif
+
+ NULL,
+};
+
+void board_init_f_r(void)
+{
+ if (initcall_run_list(init_sequence_f_r))
+ hang();
+
+ /*
+ * The pre-relocation drivers may be using memory that has now gone
+ * away. Mark serial as unavailable - this will fall back to the debug
+ * UART if available.
+ *
+ * Do the same with log drivers since the memory may not be available.
+ */
+ gd->flags &= ~(GD_FLG_SERIAL_READY | GD_FLG_LOG_READY);
+#ifdef CONFIG_TIMER
+ gd->timer = NULL;
+#endif
+
+ /*
+ * U-Boot has been copied into SDRAM, the BSS has been cleared etc.
+ * Transfer execution from Flash to RAM by calculating the address
+ * of the in-RAM copy of board_init_r() and calling it
+ */
+ (board_init_r + gd->reloc_off)((gd_t *)gd, gd->relocaddr);
+
+ /* NOTREACHED - board_init_r() does not return */
+ hang();
+}
+#endif /* CONFIG_X86 */
diff --git a/roms/u-boot/common/board_info.c b/roms/u-boot/common/board_info.c
new file mode 100644
index 000000000..1cfe34f70
--- /dev/null
+++ b/roms/u-boot/common/board_info.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <dm.h>
+#include <init.h>
+#include <sysinfo.h>
+#include <asm/global_data.h>
+#include <linux/libfdt.h>
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int __weak checkboard(void)
+{
+ return 0;
+}
+
+/*
+ * Check sysinfo for board information. Failing that if the root node of the DTB
+ * has a "model" property, show it.
+ *
+ * Then call checkboard().
+ */
+int __weak show_board_info(void)
+{
+ if (IS_ENABLED(CONFIG_OF_CONTROL)) {
+ struct udevice *dev;
+ const char *model;
+ char str[80];
+ int ret = -ENOSYS;
+
+ if (IS_ENABLED(CONFIG_SYSINFO)) {
+ /* This might provide more detail */
+ ret = uclass_first_device_err(UCLASS_SYSINFO, &dev);
+ if (!ret)
+ ret = sysinfo_get_str(dev,
+ SYSINFO_ID_BOARD_MODEL,
+ sizeof(str), str);
+ }
+
+ /* Fail back to the main 'model' if available */
+ if (ret)
+ model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
+ else
+ model = str;
+
+ if (model)
+ printf("Model: %s\n", model);
+ }
+
+ return checkboard();
+}
diff --git a/roms/u-boot/common/board_r.c b/roms/u-boot/common/board_r.c
new file mode 100644
index 000000000..3f8240477
--- /dev/null
+++ b/roms/u-boot/common/board_r.c
@@ -0,0 +1,837 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2002-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ */
+
+#include <common.h>
+#include <api.h>
+#include <bootstage.h>
+#include <cpu_func.h>
+#include <exports.h>
+#include <flash.h>
+#include <hang.h>
+#include <image.h>
+#include <irq_func.h>
+#include <log.h>
+#include <net.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <u-boot/crc.h>
+/* TODO: can we just include all these headers whether needed or not? */
+#if defined(CONFIG_CMD_BEDBUG)
+#include <bedbug/type.h>
+#endif
+#include <binman.h>
+#include <command.h>
+#include <console.h>
+#include <dm.h>
+#include <env.h>
+#include <env_internal.h>
+#include <fdtdec.h>
+#include <ide.h>
+#include <init.h>
+#include <initcall.h>
+#if defined(CONFIG_CMD_KGDB)
+#include <kgdb.h>
+#endif
+#include <irq_func.h>
+#include <malloc.h>
+#include <mapmem.h>
+#ifdef CONFIG_BITBANGMII
+#include <miiphy.h>
+#endif
+#include <mmc.h>
+#include <mux.h>
+#include <nand.h>
+#include <of_live.h>
+#include <onenand_uboot.h>
+#include <pvblock.h>
+#include <scsi.h>
+#include <serial.h>
+#include <status_led.h>
+#include <stdio_dev.h>
+#include <timer.h>
+#include <trace.h>
+#include <watchdog.h>
+#ifdef CONFIG_XEN
+#include <xen.h>
+#endif
+#ifdef CONFIG_ADDR_MAP
+#include <asm/mmu.h>
+#endif
+#include <asm/sections.h>
+#include <dm/root.h>
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <efi_loader.h>
+#include <wdt.h>
+#if defined(CONFIG_GPIO_HOG)
+#include <asm/gpio.h>
+#endif
+#ifdef CONFIG_EFI_SETUP_EARLY
+#include <efi_loader.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+ulong monitor_flash_len;
+
+__weak int board_flash_wp_on(void)
+{
+ /*
+ * Most flashes can't be detected when write protection is enabled,
+ * so provide a way to let U-Boot gracefully ignore write protected
+ * devices.
+ */
+ return 0;
+}
+
+__weak int cpu_secondary_init_r(void)
+{
+ return 0;
+}
+
+static int initr_trace(void)
+{
+#ifdef CONFIG_TRACE
+ trace_init(gd->trace_buff, CONFIG_TRACE_BUFFER_SIZE);
+#endif
+
+ return 0;
+}
+
+static int initr_reloc(void)
+{
+ /* tell others: relocation done */
+ gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;
+
+ return 0;
+}
+
+#ifdef CONFIG_ARM
+/*
+ * Some of these functions are needed purely because the functions they
+ * call return void. If we change them to return 0, these stubs can go away.
+ */
+static int initr_caches(void)
+{
+ /* Enable caches */
+ enable_caches();
+ return 0;
+}
+#endif
+
+__weak int fixup_cpu(void)
+{
+ return 0;
+}
+
+static int initr_reloc_global_data(void)
+{
+#ifdef __ARM__
+ monitor_flash_len = _end - __image_copy_start;
+#elif defined(CONFIG_NDS32) || defined(CONFIG_RISCV)
+ monitor_flash_len = (ulong)&_end - (ulong)&_start;
+#elif !defined(CONFIG_SANDBOX) && !defined(CONFIG_NIOS2)
+ monitor_flash_len = (ulong)&__init_end - gd->relocaddr;
+#endif
+#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
+ /*
+ * The gd->cpu pointer is set to an address in flash before relocation.
+ * We need to update it to point to the same CPU entry in RAM.
+ * TODO: why not just add gd->reloc_ofs?
+ */
+ gd->arch.cpu += gd->relocaddr - CONFIG_SYS_MONITOR_BASE;
+
+ /*
+ * If we didn't know the cpu mask & # cores, we can save them of
+ * now rather than 'computing' them constantly
+ */
+ fixup_cpu();
+#endif
+#ifdef CONFIG_SYS_RELOC_GD_ENV_ADDR
+ /*
+ * Relocate the early env_addr pointer unless we know it is not inside
+ * the binary. Some systems need this and for the rest, it doesn't hurt.
+ */
+ gd->env_addr += gd->reloc_off;
+#endif
+#ifdef CONFIG_OF_EMBED
+ /*
+ * The fdt_blob needs to be moved to new relocation address
+ * incase of FDT blob is embedded with in image
+ */
+ gd->fdt_blob += gd->reloc_off;
+#endif
+#ifdef CONFIG_EFI_LOADER
+ /*
+ * On the ARM architecture gd is mapped to a fixed register (r9 or x18).
+ * As this register may be overwritten by an EFI payload we save it here
+ * and restore it on every callback entered.
+ */
+ efi_save_gd();
+
+ efi_runtime_relocate(gd->relocaddr, NULL);
+#endif
+
+ return 0;
+}
+
+__weak int arch_initr_trap(void)
+{
+ return 0;
+}
+
+#ifdef CONFIG_ADDR_MAP
+static int initr_addr_map(void)
+{
+ init_addr_map();
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)
+static int initr_unlock_ram_in_cache(void)
+{
+ unlock_ram_in_cache(); /* it's time to unlock D-cache in e500 */
+ return 0;
+}
+#endif
+
+static int initr_barrier(void)
+{
+#ifdef CONFIG_PPC
+ /* TODO: Can we not use dmb() macros for this? */
+ asm("sync ; isync");
+#endif
+ return 0;
+}
+
+static int initr_malloc(void)
+{
+ ulong malloc_start;
+
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ debug("Pre-reloc malloc() used %#lx bytes (%ld KB)\n", gd->malloc_ptr,
+ gd->malloc_ptr / 1024);
+#endif
+ /* The malloc area is immediately below the monitor copy in DRAM */
+ /*
+ * This value MUST match the value of gd->start_addr_sp in board_f.c:
+ * reserve_noncached().
+ */
+ malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
+ mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN),
+ TOTAL_MALLOC_LEN);
+ return 0;
+}
+
+static int initr_of_live(void)
+{
+ if (CONFIG_IS_ENABLED(OF_LIVE)) {
+ int ret;
+
+ bootstage_start(BOOTSTAGE_ID_ACCUM_OF_LIVE, "of_live");
+ ret = of_live_build(gd->fdt_blob,
+ (struct device_node **)gd_of_root_ptr());
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_OF_LIVE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_DM
+static int initr_dm(void)
+{
+ int ret;
+
+ /* Save the pre-reloc driver model and start a new one */
+ gd->dm_root_f = gd->dm_root;
+ gd->dm_root = NULL;
+#ifdef CONFIG_TIMER
+ gd->timer = NULL;
+#endif
+ bootstage_start(BOOTSTAGE_ID_ACCUM_DM_R, "dm_r");
+ ret = dm_init_and_scan(false);
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_R);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif
+
+static int initr_dm_devices(void)
+{
+ int ret;
+
+ if (IS_ENABLED(CONFIG_TIMER_EARLY)) {
+ ret = dm_timer_init();
+ if (ret)
+ return ret;
+ }
+
+ if (IS_ENABLED(CONFIG_MULTIPLEXER)) {
+ /*
+ * Initialize the multiplexer controls to their default state.
+ * This must be done early as other drivers may unknowingly
+ * rely on it.
+ */
+ ret = dm_mux_init();
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int initr_bootstage(void)
+{
+ bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");
+
+ return 0;
+}
+
+__weak int power_init_board(void)
+{
+ return 0;
+}
+
+static int initr_announce(void)
+{
+ debug("Now running in RAM - U-Boot at: %08lx\n", gd->relocaddr);
+ return 0;
+}
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+static int initr_manual_reloc_cmdtable(void)
+{
+ fixup_cmdtable(ll_entry_start(struct cmd_tbl, cmd),
+ ll_entry_count(struct cmd_tbl, cmd));
+ return 0;
+}
+#endif
+
+static int initr_binman(void)
+{
+ if (!CONFIG_IS_ENABLED(BINMAN_FDT))
+ return 0;
+
+ return binman_init();
+}
+
+#if defined(CONFIG_MTD_NOR_FLASH)
+__weak int is_flash_available(void)
+{
+ return 1;
+}
+
+static int initr_flash(void)
+{
+ ulong flash_size = 0;
+ struct bd_info *bd = gd->bd;
+
+ if (!is_flash_available())
+ return 0;
+
+ puts("Flash: ");
+
+ if (board_flash_wp_on())
+ printf("Uninitialized - Write Protect On\n");
+ else
+ flash_size = flash_init();
+
+ print_size(flash_size, "");
+#ifdef CONFIG_SYS_FLASH_CHECKSUM
+ /*
+ * Compute and print flash CRC if flashchecksum is set to 'y'
+ *
+ * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
+ */
+ if (env_get_yesno("flashchecksum") == 1) {
+ const uchar *flash_base = (const uchar *)CONFIG_SYS_FLASH_BASE;
+
+ printf(" CRC: %08X", crc32(0,
+ flash_base,
+ flash_size));
+ }
+#endif /* CONFIG_SYS_FLASH_CHECKSUM */
+ putc('\n');
+
+ /* update start of FLASH memory */
+#ifdef CONFIG_SYS_FLASH_BASE
+ bd->bi_flashstart = CONFIG_SYS_FLASH_BASE;
+#endif
+ /* size of FLASH memory (final value) */
+ bd->bi_flashsize = flash_size;
+
+#if defined(CONFIG_SYS_UPDATE_FLASH_SIZE)
+ /* Make a update of the Memctrl. */
+ update_flash_size(flash_size);
+#endif
+
+#if defined(CONFIG_OXC) || defined(CONFIG_RMU)
+ /* flash mapped at end of memory map */
+ bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
+#elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
+ bd->bi_flashoffset = monitor_flash_len; /* reserved area for monitor */
+#endif
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_CMD_NAND
+/* go init the NAND */
+static int initr_nand(void)
+{
+ puts("NAND: ");
+ nand_init();
+ printf("%lu MiB\n", nand_size() / 1024);
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_CMD_ONENAND)
+/* go init the NAND */
+static int initr_onenand(void)
+{
+ puts("NAND: ");
+ onenand_init();
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_MMC
+static int initr_mmc(void)
+{
+ puts("MMC: ");
+ mmc_initialize(gd->bd);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PVBLOCK
+static int initr_pvblock(void)
+{
+ puts("PVBLOCK: ");
+ pvblock_init();
+ return 0;
+}
+#endif
+
+/*
+ * Tell if it's OK to load the environment early in boot.
+ *
+ * If CONFIG_OF_CONTROL is defined, we'll check with the FDT to see
+ * if this is OK (defaulting to saying it's OK).
+ *
+ * NOTE: Loading the environment early can be a bad idea if security is
+ * important, since no verification is done on the environment.
+ *
+ * @return 0 if environment should not be loaded, !=0 if it is ok to load
+ */
+static int should_load_env(void)
+{
+ if (IS_ENABLED(CONFIG_OF_CONTROL))
+ return fdtdec_get_config_int(gd->fdt_blob,
+ "load-environment", 1);
+
+ if (IS_ENABLED(CONFIG_DELAY_ENVIRONMENT))
+ return 0;
+
+ return 1;
+}
+
+static int initr_env(void)
+{
+ /* initialize environment */
+ if (should_load_env())
+ env_relocate();
+ else
+ env_set_default(NULL, 0);
+
+ env_import_fdt();
+
+ if (IS_ENABLED(CONFIG_OF_CONTROL))
+ env_set_hex("fdtcontroladdr",
+ (unsigned long)map_to_sysmem(gd->fdt_blob));
+
+ /* Initialize from environment */
+ image_load_addr = env_get_ulong("loadaddr", 16, image_load_addr);
+
+ return 0;
+}
+
+#ifdef CONFIG_SYS_BOOTPARAMS_LEN
+static int initr_malloc_bootparams(void)
+{
+ gd->bd->bi_boot_params = (ulong)malloc(CONFIG_SYS_BOOTPARAMS_LEN);
+ if (!gd->bd->bi_boot_params) {
+ puts("WARNING: Cannot allocate space for boot parameters\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_CMD_NET
+static int initr_ethaddr(void)
+{
+ struct bd_info *bd = gd->bd;
+
+ /* kept around for legacy kernels only ... ignore the next section */
+ eth_env_get_enetaddr("ethaddr", bd->bi_enetaddr);
+
+ return 0;
+}
+#endif /* CONFIG_CMD_NET */
+
+#ifdef CONFIG_CMD_KGDB
+static int initr_kgdb(void)
+{
+ puts("KGDB: ");
+ kgdb_init();
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_LED_STATUS)
+static int initr_status_led(void)
+{
+#if defined(CONFIG_LED_STATUS_BOOT)
+ status_led_set(CONFIG_LED_STATUS_BOOT, CONFIG_LED_STATUS_BLINKING);
+#else
+ status_led_init();
+#endif
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI)
+static int initr_scsi(void)
+{
+ puts("SCSI: ");
+ scsi_init();
+ puts("\n");
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_CMD_NET
+static int initr_net(void)
+{
+ puts("Net: ");
+ eth_initialize();
+#if defined(CONFIG_RESET_PHY_R)
+ debug("Reset Ethernet PHY\n");
+ reset_phy();
+#endif
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_POST
+static int initr_post(void)
+{
+ post_run(NULL, POST_RAM | post_bootmode_get(0));
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_IDE) && !defined(CONFIG_BLK)
+static int initr_ide(void)
+{
+ puts("IDE: ");
+#if defined(CONFIG_START_IDE)
+ if (board_start_ide())
+ ide_init();
+#else
+ ide_init();
+#endif
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_PRAM)
+/*
+ * Export available size of memory for Linux, taking into account the
+ * protected RAM at top of memory
+ */
+int initr_mem(void)
+{
+ ulong pram = 0;
+ char memsz[32];
+
+ pram = env_get_ulong("pram", 10, CONFIG_PRAM);
+ sprintf(memsz, "%ldk", (long int)((gd->ram_size / 1024) - pram));
+ env_set("mem", memsz);
+
+ return 0;
+}
+#endif
+
+static int run_main_loop(void)
+{
+#ifdef CONFIG_SANDBOX
+ sandbox_main_loop_init();
+#endif
+ /* main_loop() can return to retry autoboot, if so just run it again */
+ for (;;)
+ main_loop();
+ return 0;
+}
+
+/*
+ * We hope to remove most of the driver-related init and do it if/when
+ * the driver is later used.
+ *
+ * TODO: perhaps reset the watchdog in the initcall function after each call?
+ */
+static init_fnc_t init_sequence_r[] = {
+ initr_trace,
+ initr_reloc,
+ /* TODO: could x86/PPC have this also perhaps? */
+#ifdef CONFIG_ARM
+ initr_caches,
+ /* Note: For Freescale LS2 SoCs, new MMU table is created in DDR.
+ * A temporary mapping of IFC high region is since removed,
+ * so environmental variables in NOR flash is not available
+ * until board_init() is called below to remap IFC to high
+ * region.
+ */
+#endif
+ initr_reloc_global_data,
+#if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)
+ initr_unlock_ram_in_cache,
+#endif
+ initr_barrier,
+ initr_malloc,
+ log_init,
+ initr_bootstage, /* Needs malloc() but has its own timer */
+#if defined(CONFIG_CONSOLE_RECORD)
+ console_record_init,
+#endif
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+ noncached_init,
+#endif
+ initr_of_live,
+#ifdef CONFIG_DM
+ initr_dm,
+#endif
+#ifdef CONFIG_ADDR_MAP
+ initr_addr_map,
+#endif
+#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \
+ defined(CONFIG_SANDBOX)
+ board_init, /* Setup chipselects */
+#endif
+ /*
+ * TODO: printing of the clock inforamtion of the board is now
+ * implemented as part of bdinfo command. Currently only support for
+ * davinci SOC's is added. Remove this check once all the board
+ * implement this.
+ */
+#ifdef CONFIG_CLOCKS
+ set_cpu_clk_info, /* Setup clock information */
+#endif
+#ifdef CONFIG_EFI_LOADER
+ efi_memory_init,
+#endif
+ initr_binman,
+#ifdef CONFIG_FSP_VERSION2
+ arch_fsp_init_r,
+#endif
+ initr_dm_devices,
+ stdio_init_tables,
+ serial_initialize,
+ initr_announce,
+#if CONFIG_IS_ENABLED(WDT)
+ initr_watchdog,
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+#if defined(CONFIG_NEEDS_MANUAL_RELOC) && defined(CONFIG_BLOCK_CACHE)
+ blkcache_init,
+#endif
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ initr_manual_reloc_cmdtable,
+#endif
+ arch_initr_trap,
+#if defined(CONFIG_BOARD_EARLY_INIT_R)
+ board_early_init_r,
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+#ifdef CONFIG_POST
+ post_output_backlog,
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+#if defined(CONFIG_PCI_INIT_R) && defined(CONFIG_SYS_EARLY_PCI_INIT)
+ /*
+ * Do early PCI configuration _before_ the flash gets initialised,
+ * because PCU resources are crucial for flash access on some boards.
+ */
+ pci_init,
+#endif
+#ifdef CONFIG_ARCH_EARLY_INIT_R
+ arch_early_init_r,
+#endif
+ power_init_board,
+#ifdef CONFIG_MTD_NOR_FLASH
+ initr_flash,
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86)
+ /* initialize higher level parts of CPU like time base and timers */
+ cpu_init_r,
+#endif
+#ifdef CONFIG_CMD_NAND
+ initr_nand,
+#endif
+#ifdef CONFIG_CMD_ONENAND
+ initr_onenand,
+#endif
+#ifdef CONFIG_MMC
+ initr_mmc,
+#endif
+#ifdef CONFIG_XEN
+ xen_init,
+#endif
+#ifdef CONFIG_PVBLOCK
+ initr_pvblock,
+#endif
+ initr_env,
+#ifdef CONFIG_SYS_BOOTPARAMS_LEN
+ initr_malloc_bootparams,
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+ cpu_secondary_init_r,
+#if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)
+ mac_read_from_eeprom,
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+#if defined(CONFIG_PCI_INIT_R) && !defined(CONFIG_SYS_EARLY_PCI_INIT)
+ /*
+ * Do pci configuration
+ */
+ pci_init,
+#endif
+ stdio_add_devices,
+ jumptable_init,
+#ifdef CONFIG_API
+ api_init,
+#endif
+ console_init_r, /* fully init console as a device */
+#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
+ console_announce_r,
+ show_board_info,
+#endif
+#ifdef CONFIG_ARCH_MISC_INIT
+ arch_misc_init, /* miscellaneous arch-dependent init */
+#endif
+#ifdef CONFIG_MISC_INIT_R
+ misc_init_r, /* miscellaneous platform-dependent init */
+#endif
+ INIT_FUNC_WATCHDOG_RESET
+#ifdef CONFIG_CMD_KGDB
+ initr_kgdb,
+#endif
+ interrupt_init,
+#if defined(CONFIG_MICROBLAZE) || defined(CONFIG_M68K)
+ timer_init, /* initialize timer */
+#endif
+#if defined(CONFIG_LED_STATUS)
+ initr_status_led,
+#endif
+ /* PPC has a udelay(20) here dating from 2002. Why? */
+#ifdef CONFIG_CMD_NET
+ initr_ethaddr,
+#endif
+#if defined(CONFIG_GPIO_HOG)
+ gpio_hog_probe_all,
+#endif
+#ifdef CONFIG_BOARD_LATE_INIT
+ board_late_init,
+#endif
+#if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI)
+ INIT_FUNC_WATCHDOG_RESET
+ initr_scsi,
+#endif
+#ifdef CONFIG_BITBANGMII
+ bb_miiphy_init,
+#endif
+#ifdef CONFIG_PCI_ENDPOINT
+ pci_ep_init,
+#endif
+#ifdef CONFIG_CMD_NET
+ INIT_FUNC_WATCHDOG_RESET
+ initr_net,
+#endif
+#ifdef CONFIG_POST
+ initr_post,
+#endif
+#if defined(CONFIG_IDE) && !defined(CONFIG_BLK)
+ initr_ide,
+#endif
+#ifdef CONFIG_LAST_STAGE_INIT
+ INIT_FUNC_WATCHDOG_RESET
+ /*
+ * Some parts can be only initialized if all others (like
+ * Interrupts) are up and running (i.e. the PC-style ISA
+ * keyboard).
+ */
+ last_stage_init,
+#endif
+#ifdef CONFIG_CMD_BEDBUG
+ INIT_FUNC_WATCHDOG_RESET
+ bedbug_init,
+#endif
+#if defined(CONFIG_PRAM)
+ initr_mem,
+#endif
+#ifdef CONFIG_EFI_SETUP_EARLY
+ (init_fnc_t)efi_init_obj_list,
+#endif
+ run_main_loop,
+};
+
+void board_init_r(gd_t *new_gd, ulong dest_addr)
+{
+ /*
+ * Set up the new global data pointer. So far only x86 does this
+ * here.
+ * TODO(sjg@chromium.org): Consider doing this for all archs, or
+ * dropping the new_gd parameter.
+ */
+#if CONFIG_IS_ENABLED(X86_64)
+ arch_setup_gd(new_gd);
+#endif
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ int i;
+#endif
+
+#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
+ gd = new_gd;
+#endif
+ gd->flags &= ~GD_FLG_LOG_READY;
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ for (i = 0; i < ARRAY_SIZE(init_sequence_r); i++)
+ init_sequence_r[i] += gd->reloc_off;
+#endif
+
+ if (initcall_run_list(init_sequence_r))
+ hang();
+
+ /* NOTREACHED - run_main_loop() does not return */
+ hang();
+}
diff --git a/roms/u-boot/common/boot_fit.c b/roms/u-boot/common/boot_fit.c
new file mode 100644
index 000000000..dfc2a3117
--- /dev/null
+++ b/roms/u-boot/common/boot_fit.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017
+ * Texas Instruments, <www.ti.com>
+ *
+ * Franklin S Cooper Jr. <fcooper@ti.com>
+ */
+
+#include <boot_fit.h>
+#include <common.h>
+#include <errno.h>
+#include <image.h>
+#include <log.h>
+#include <linux/libfdt.h>
+
+static int fdt_offset(const void *fit)
+{
+ int images, node, fdt_len, fdt_node, fdt_offset;
+ const char *fdt_name;
+
+ node = fit_find_config_node(fit);
+ if (node < 0)
+ return node;
+
+ images = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images < 0) {
+ debug("%s: Cannot find /images node: %d\n", __func__, images);
+ return -EINVAL;
+ }
+
+ fdt_name = fdt_getprop(fit, node, FIT_FDT_PROP, &fdt_len);
+ if (!fdt_name) {
+ debug("%s: Cannot find fdt name property: %d\n",
+ __func__, fdt_len);
+ return -EINVAL;
+ }
+
+ fdt_node = fdt_subnode_offset(fit, images, fdt_name);
+ if (fdt_node < 0) {
+ debug("%s: Cannot find fdt node '%s': %d\n",
+ __func__, fdt_name, fdt_node);
+ return -EINVAL;
+ }
+
+ fdt_offset = fdt_getprop_u32(fit, fdt_node, "data-offset");
+
+ if (fdt_offset == FDT_ERROR)
+ return -ENOENT;
+
+ fdt_len = fdt_getprop_u32(fit, fdt_node, "data-size");
+
+ if (fdt_len < 0)
+ return fdt_len;
+
+ return fdt_offset;
+}
+
+void *locate_dtb_in_fit(const void *fit)
+{
+ struct image_header *header;
+ int size;
+ int ret;
+
+ size = fdt_totalsize(fit);
+ size = (size + 3) & ~3;
+
+ header = (struct image_header *)fit;
+
+ if (image_get_magic(header) != FDT_MAGIC) {
+ debug("No FIT image appended to U-boot\n");
+ return NULL;
+ }
+
+ ret = fdt_offset(fit);
+
+ if (ret < 0)
+ return NULL;
+ else
+ return (void *)fit+size+ret;
+}
diff --git a/roms/u-boot/common/bootm.c b/roms/u-boot/common/bootm.c
new file mode 100644
index 000000000..ea71522d0
--- /dev/null
+++ b/roms/u-boot/common/bootm.c
@@ -0,0 +1,1038 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#ifndef USE_HOSTCC
+#include <common.h>
+#include <bootstage.h>
+#include <cli.h>
+#include <cpu_func.h>
+#include <env.h>
+#include <errno.h>
+#include <fdt_support.h>
+#include <irq_func.h>
+#include <lmb.h>
+#include <log.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <net.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/sizes.h>
+#if defined(CONFIG_CMD_USB)
+#include <usb.h>
+#endif
+#else
+#include "mkimage.h"
+#endif
+
+#include <command.h>
+#include <bootm.h>
+#include <image.h>
+
+#ifndef CONFIG_SYS_BOOTM_LEN
+/* use 8MByte as default max gunzip size */
+#define CONFIG_SYS_BOOTM_LEN 0x800000
+#endif
+
+#define MAX_CMDLINE_SIZE SZ_4K
+
+#define IH_INITRD_ARCH IH_ARCH_DEFAULT
+
+#ifndef USE_HOSTCC
+
+DECLARE_GLOBAL_DATA_PTR;
+
+bootm_headers_t images; /* pointers to os/initrd/fdt images */
+
+static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], bootm_headers_t *images,
+ ulong *os_data, ulong *os_len);
+
+__weak void board_quiesce_devices(void)
+{
+}
+
+#ifdef CONFIG_LMB
+static void boot_start_lmb(bootm_headers_t *images)
+{
+ ulong mem_start;
+ phys_size_t mem_size;
+
+ mem_start = env_get_bootm_low();
+ mem_size = env_get_bootm_size();
+
+ lmb_init_and_reserve_range(&images->lmb, (phys_addr_t)mem_start,
+ mem_size, NULL);
+}
+#else
+#define lmb_reserve(lmb, base, size)
+static inline void boot_start_lmb(bootm_headers_t *images) { }
+#endif
+
+static int bootm_start(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ memset((void *)&images, 0, sizeof(images));
+ images.verify = env_get_yesno("verify");
+
+ boot_start_lmb(&images);
+
+ bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start");
+ images.state = BOOTM_STATE_START;
+
+ return 0;
+}
+
+static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ const void *os_hdr;
+ bool ep_found = false;
+ int ret;
+
+ /* get kernel image header, start address and length */
+ os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
+ &images, &images.os.image_start, &images.os.image_len);
+ if (images.os.image_len == 0) {
+ puts("ERROR: can't get kernel image!\n");
+ return 1;
+ }
+
+ /* get image parameters */
+ switch (genimg_get_format(os_hdr)) {
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+ case IMAGE_FORMAT_LEGACY:
+ images.os.type = image_get_type(os_hdr);
+ images.os.comp = image_get_comp(os_hdr);
+ images.os.os = image_get_os(os_hdr);
+
+ images.os.end = image_get_image_end(os_hdr);
+ images.os.load = image_get_load(os_hdr);
+ images.os.arch = image_get_arch(os_hdr);
+ break;
+#endif
+#if IMAGE_ENABLE_FIT
+ case IMAGE_FORMAT_FIT:
+ if (fit_image_get_type(images.fit_hdr_os,
+ images.fit_noffset_os,
+ &images.os.type)) {
+ puts("Can't get image type!\n");
+ bootstage_error(BOOTSTAGE_ID_FIT_TYPE);
+ return 1;
+ }
+
+ if (fit_image_get_comp(images.fit_hdr_os,
+ images.fit_noffset_os,
+ &images.os.comp)) {
+ puts("Can't get image compression!\n");
+ bootstage_error(BOOTSTAGE_ID_FIT_COMPRESSION);
+ return 1;
+ }
+
+ if (fit_image_get_os(images.fit_hdr_os, images.fit_noffset_os,
+ &images.os.os)) {
+ puts("Can't get image OS!\n");
+ bootstage_error(BOOTSTAGE_ID_FIT_OS);
+ return 1;
+ }
+
+ if (fit_image_get_arch(images.fit_hdr_os,
+ images.fit_noffset_os,
+ &images.os.arch)) {
+ puts("Can't get image ARCH!\n");
+ return 1;
+ }
+
+ images.os.end = fit_get_end(images.fit_hdr_os);
+
+ if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os,
+ &images.os.load)) {
+ puts("Can't get image load address!\n");
+ bootstage_error(BOOTSTAGE_ID_FIT_LOADADDR);
+ return 1;
+ }
+ break;
+#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ case IMAGE_FORMAT_ANDROID:
+ images.os.type = IH_TYPE_KERNEL;
+ images.os.comp = android_image_get_kcomp(os_hdr);
+ images.os.os = IH_OS_LINUX;
+
+ images.os.end = android_image_get_end(os_hdr);
+ images.os.load = android_image_get_kload(os_hdr);
+ images.ep = images.os.load;
+ ep_found = true;
+ break;
+#endif
+ default:
+ puts("ERROR: unknown image format type!\n");
+ return 1;
+ }
+
+ /* If we have a valid setup.bin, we will use that for entry (x86) */
+ if (images.os.arch == IH_ARCH_I386 ||
+ images.os.arch == IH_ARCH_X86_64) {
+ ulong len;
+
+ ret = boot_get_setup(&images, IH_ARCH_I386, &images.ep, &len);
+ if (ret < 0 && ret != -ENOENT) {
+ puts("Could not find a valid setup.bin for x86\n");
+ return 1;
+ }
+ /* Kernel entry point is the setup.bin */
+ } else if (images.legacy_hdr_valid) {
+ images.ep = image_get_ep(&images.legacy_hdr_os_copy);
+#if IMAGE_ENABLE_FIT
+ } else if (images.fit_uname_os) {
+ int ret;
+
+ ret = fit_image_get_entry(images.fit_hdr_os,
+ images.fit_noffset_os, &images.ep);
+ if (ret) {
+ puts("Can't get entry point property!\n");
+ return 1;
+ }
+#endif
+ } else if (!ep_found) {
+ puts("Could not find kernel entry point!\n");
+ return 1;
+ }
+
+ if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {
+ if (CONFIG_IS_ENABLED(CMD_BOOTI) &&
+ images.os.arch == IH_ARCH_ARM64) {
+ ulong image_addr;
+ ulong image_size;
+
+ ret = booti_setup(images.os.image_start, &image_addr,
+ &image_size, true);
+ if (ret != 0)
+ return 1;
+
+ images.os.type = IH_TYPE_KERNEL;
+ images.os.load = image_addr;
+ images.ep = image_addr;
+ } else {
+ images.os.load = images.os.image_start;
+ images.ep += images.os.image_start;
+ }
+ }
+
+ images.os.start = map_to_sysmem(os_hdr);
+
+ return 0;
+}
+
+/**
+ * bootm_find_images - wrapper to find and locate various images
+ * @flag: Ignored Argument
+ * @argc: command argument count
+ * @argv: command argument list
+ * @start: OS image start address
+ * @size: OS image size
+ *
+ * boot_find_images() will attempt to load an available ramdisk,
+ * flattened device tree, as well as specifically marked
+ * "loadable" images (loadables are FIT only)
+ *
+ * Note: bootm_find_images will skip an image if it is not found
+ *
+ * @return:
+ * 0, if all existing images were loaded correctly
+ * 1, if an image is found but corrupted, or invalid
+ */
+int bootm_find_images(int flag, int argc, char *const argv[], ulong start,
+ ulong size)
+{
+ int ret;
+
+ /* find ramdisk */
+ ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH,
+ &images.rd_start, &images.rd_end);
+ if (ret) {
+ puts("Ramdisk image is corrupt or invalid\n");
+ return 1;
+ }
+
+ /* check if ramdisk overlaps OS image */
+ if (images.rd_start && (((ulong)images.rd_start >= start &&
+ (ulong)images.rd_start < start + size) ||
+ ((ulong)images.rd_end > start &&
+ (ulong)images.rd_end <= start + size) ||
+ ((ulong)images.rd_start < start &&
+ (ulong)images.rd_end >= start + size))) {
+ printf("ERROR: RD image overlaps OS image (OS=0x%lx..0x%lx)\n",
+ start, start + size);
+ return 1;
+ }
+
+#if IMAGE_ENABLE_OF_LIBFDT
+ /* find flattened device tree */
+ ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,
+ &images.ft_addr, &images.ft_len);
+ if (ret) {
+ puts("Could not find a valid device tree\n");
+ return 1;
+ }
+
+ /* check if FDT overlaps OS image */
+ if (images.ft_addr &&
+ (((ulong)images.ft_addr >= start &&
+ (ulong)images.ft_addr <= start + size) ||
+ ((ulong)images.ft_addr + images.ft_len >= start &&
+ (ulong)images.ft_addr + images.ft_len <= start + size))) {
+ printf("ERROR: FDT image overlaps OS image (OS=0x%lx..0x%lx)\n",
+ start, start + size);
+ return 1;
+ }
+
+ if (CONFIG_IS_ENABLED(CMD_FDT))
+ set_working_fdt_addr(map_to_sysmem(images.ft_addr));
+#endif
+
+#if IMAGE_ENABLE_FIT
+#if defined(CONFIG_FPGA)
+ /* find bitstreams */
+ ret = boot_get_fpga(argc, argv, &images, IH_ARCH_DEFAULT,
+ NULL, NULL);
+ if (ret) {
+ printf("FPGA image is corrupted or invalid\n");
+ return 1;
+ }
+#endif
+
+ /* find all of the loadables */
+ ret = boot_get_loadable(argc, argv, &images, IH_ARCH_DEFAULT,
+ NULL, NULL);
+ if (ret) {
+ printf("Loadable(s) is corrupt or invalid\n");
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
+static int bootm_find_other(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ if (((images.os.type == IH_TYPE_KERNEL) ||
+ (images.os.type == IH_TYPE_KERNEL_NOLOAD) ||
+ (images.os.type == IH_TYPE_MULTI)) &&
+ (images.os.os == IH_OS_LINUX ||
+ images.os.os == IH_OS_VXWORKS))
+ return bootm_find_images(flag, argc, argv, 0, 0);
+
+ return 0;
+}
+#endif /* USE_HOSTC */
+
+#if !defined(USE_HOSTCC) || defined(CONFIG_FIT_SIGNATURE)
+/**
+ * handle_decomp_error() - display a decompression error
+ *
+ * This function tries to produce a useful message. In the case where the
+ * uncompressed size is the same as the available space, we can assume that
+ * the image is too large for the buffer.
+ *
+ * @comp_type: Compression type being used (IH_COMP_...)
+ * @uncomp_size: Number of bytes uncompressed
+ * @ret: errno error code received from compression library
+ * @return Appropriate BOOTM_ERR_ error code
+ */
+static int handle_decomp_error(int comp_type, size_t uncomp_size, int ret)
+{
+ const char *name = genimg_get_comp_name(comp_type);
+
+ /* ENOSYS means unimplemented compression type, don't reset. */
+ if (ret == -ENOSYS)
+ return BOOTM_ERR_UNIMPLEMENTED;
+
+ if (uncomp_size >= CONFIG_SYS_BOOTM_LEN)
+ printf("Image too large: increase CONFIG_SYS_BOOTM_LEN\n");
+ else
+ printf("%s: uncompress error %d\n", name, ret);
+
+ /*
+ * The decompression routines are now safe, so will not write beyond
+ * their bounds. Probably it is not necessary to reset, but maintain
+ * the current behaviour for now.
+ */
+ printf("Must RESET board to recover\n");
+#ifndef USE_HOSTCC
+ bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE);
+#endif
+
+ return BOOTM_ERR_RESET;
+}
+#endif
+
+#ifndef USE_HOSTCC
+static int bootm_load_os(bootm_headers_t *images, int boot_progress)
+{
+ image_info_t os = images->os;
+ ulong load = os.load;
+ ulong load_end;
+ ulong blob_start = os.start;
+ ulong blob_end = os.end;
+ ulong image_start = os.image_start;
+ ulong image_len = os.image_len;
+ ulong flush_start = ALIGN_DOWN(load, ARCH_DMA_MINALIGN);
+ bool no_overlap;
+ void *load_buf, *image_buf;
+ int err;
+
+ load_buf = map_sysmem(load, 0);
+ image_buf = map_sysmem(os.image_start, image_len);
+ err = image_decomp(os.comp, load, os.image_start, os.type,
+ load_buf, image_buf, image_len,
+ CONFIG_SYS_BOOTM_LEN, &load_end);
+ if (err) {
+ err = handle_decomp_error(os.comp, load_end - load, err);
+ bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE);
+ return err;
+ }
+ /* We need the decompressed image size in the next steps */
+ images->os.image_len = load_end - load;
+
+ flush_cache(flush_start, ALIGN(load_end, ARCH_DMA_MINALIGN) - flush_start);
+
+ debug(" kernel loaded at 0x%08lx, end = 0x%08lx\n", load, load_end);
+ bootstage_mark(BOOTSTAGE_ID_KERNEL_LOADED);
+
+ no_overlap = (os.comp == IH_COMP_NONE && load == image_start);
+
+ if (!no_overlap && load < blob_end && load_end > blob_start) {
+ debug("images.os.start = 0x%lX, images.os.end = 0x%lx\n",
+ blob_start, blob_end);
+ debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load,
+ load_end);
+
+ /* Check what type of image this is. */
+ if (images->legacy_hdr_valid) {
+ if (image_get_type(&images->legacy_hdr_os_copy)
+ == IH_TYPE_MULTI)
+ puts("WARNING: legacy format multi component image overwritten\n");
+ return BOOTM_ERR_OVERLAP;
+ } else {
+ puts("ERROR: new format image overwritten - must RESET the board to recover\n");
+ bootstage_error(BOOTSTAGE_ID_OVERWRITTEN);
+ return BOOTM_ERR_RESET;
+ }
+ }
+
+ lmb_reserve(&images->lmb, images->os.load, (load_end -
+ images->os.load));
+ return 0;
+}
+
+/**
+ * bootm_disable_interrupts() - Disable interrupts in preparation for load/boot
+ *
+ * @return interrupt flag (0 if interrupts were disabled, non-zero if they were
+ * enabled)
+ */
+ulong bootm_disable_interrupts(void)
+{
+ ulong iflag;
+
+ /*
+ * We have reached the point of no return: we are going to
+ * overwrite all exception vector code, so we cannot easily
+ * recover from any failures any more...
+ */
+ iflag = disable_interrupts();
+#ifdef CONFIG_NETCONSOLE
+ /* Stop the ethernet stack if NetConsole could have left it up */
+ eth_halt();
+# ifndef CONFIG_DM_ETH
+ eth_unregister(eth_get_dev());
+# endif
+#endif
+
+#if defined(CONFIG_CMD_USB)
+ /*
+ * turn off USB to prevent the host controller from writing to the
+ * SDRAM while Linux is booting. This could happen (at least for OHCI
+ * controller), because the HCCA (Host Controller Communication Area)
+ * lies within the SDRAM and the host controller writes continously to
+ * this area (as busmaster!). The HccaFrameNumber is for example
+ * updated every 1 ms within the HCCA structure in SDRAM! For more
+ * details see the OpenHCI specification.
+ */
+ usb_stop();
+#endif
+ return iflag;
+}
+
+#define CONSOLE_ARG "console="
+#define CONSOLE_ARG_SIZE sizeof(CONSOLE_ARG)
+
+/**
+ * fixup_silent_linux() - Handle silencing the linux boot if required
+ *
+ * This uses the silent_linux envvar to control whether to add/set a "console="
+ * parameter to the command line
+ *
+ * @buf: Buffer containing the string to process
+ * @maxlen: Maximum length of buffer
+ * @return 0 if OK, -ENOSPC if @maxlen is too small
+ */
+static int fixup_silent_linux(char *buf, int maxlen)
+{
+ int want_silent;
+ char *cmdline;
+ int size;
+
+ /*
+ * Move the input string to the end of buffer. The output string will be
+ * built up at the start.
+ */
+ size = strlen(buf) + 1;
+ if (size * 2 > maxlen)
+ return -ENOSPC;
+ cmdline = buf + maxlen - size;
+ memmove(cmdline, buf, size);
+ /*
+ * Only fix cmdline when requested. The environment variable can be:
+ *
+ * no - we never fixup
+ * yes - we always fixup
+ * unset - we rely on the console silent flag
+ */
+ want_silent = env_get_yesno("silent_linux");
+ if (want_silent == 0)
+ return 0;
+ else if (want_silent == -1 && !(gd->flags & GD_FLG_SILENT))
+ return 0;
+
+ debug("before silent fix-up: %s\n", cmdline);
+ if (*cmdline) {
+ char *start = strstr(cmdline, CONSOLE_ARG);
+
+ /* Check space for maximum possible new command line */
+ if (size + CONSOLE_ARG_SIZE > maxlen)
+ return -ENOSPC;
+
+ if (start) {
+ char *end = strchr(start, ' ');
+ int start_bytes;
+
+ start_bytes = start - cmdline + CONSOLE_ARG_SIZE - 1;
+ strncpy(buf, cmdline, start_bytes);
+ if (end)
+ strcpy(buf + start_bytes, end);
+ else
+ buf[start_bytes] = '\0';
+ } else {
+ sprintf(buf, "%s %s", cmdline, CONSOLE_ARG);
+ }
+ if (buf + strlen(buf) >= cmdline)
+ return -ENOSPC;
+ } else {
+ if (maxlen < sizeof(CONSOLE_ARG))
+ return -ENOSPC;
+ strcpy(buf, CONSOLE_ARG);
+ }
+ debug("after silent fix-up: %s\n", buf);
+
+ return 0;
+}
+
+/**
+ * process_subst() - Handle substitution of ${...} fields in the environment
+ *
+ * Handle variable substitution in the provided buffer
+ *
+ * @buf: Buffer containing the string to process
+ * @maxlen: Maximum length of buffer
+ * @return 0 if OK, -ENOSPC if @maxlen is too small
+ */
+static int process_subst(char *buf, int maxlen)
+{
+ char *cmdline;
+ int size;
+ int ret;
+
+ /* Move to end of buffer */
+ size = strlen(buf) + 1;
+ cmdline = buf + maxlen - size;
+ if (buf + size > cmdline)
+ return -ENOSPC;
+ memmove(cmdline, buf, size);
+
+ ret = cli_simple_process_macros(cmdline, buf, cmdline - buf);
+
+ return ret;
+}
+
+int bootm_process_cmdline(char *buf, int maxlen, int flags)
+{
+ int ret;
+
+ /* Check config first to enable compiler to eliminate code */
+ if (IS_ENABLED(CONFIG_SILENT_CONSOLE) &&
+ !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY) &&
+ (flags & BOOTM_CL_SILENT)) {
+ ret = fixup_silent_linux(buf, maxlen);
+ if (ret)
+ return log_msg_ret("silent", ret);
+ }
+ if (IS_ENABLED(CONFIG_BOOTARGS_SUBST) && IS_ENABLED(CONFIG_CMDLINE) &&
+ (flags & BOOTM_CL_SUBST)) {
+ ret = process_subst(buf, maxlen);
+ if (ret)
+ return log_msg_ret("subst", ret);
+ }
+
+ return 0;
+}
+
+int bootm_process_cmdline_env(int flags)
+{
+ const int maxlen = MAX_CMDLINE_SIZE;
+ bool do_silent;
+ const char *env;
+ char *buf;
+ int ret;
+
+ /* First check if any action is needed */
+ do_silent = IS_ENABLED(CONFIG_SILENT_CONSOLE) &&
+ !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY) && (flags & BOOTM_CL_SILENT);
+ if (!do_silent && !IS_ENABLED(CONFIG_BOOTARGS_SUBST))
+ return 0;
+
+ env = env_get("bootargs");
+ if (env && strlen(env) >= maxlen)
+ return -E2BIG;
+ buf = malloc(maxlen);
+ if (!buf)
+ return -ENOMEM;
+ if (env)
+ strcpy(buf, env);
+ else
+ *buf = '\0';
+ ret = bootm_process_cmdline(buf, maxlen, flags);
+ if (!ret) {
+ ret = env_set("bootargs", buf);
+
+ /*
+ * If buf is "" and bootargs does not exist, this will produce
+ * an error trying to delete bootargs. Ignore it
+ */
+ if (ret == -ENOENT)
+ ret = 0;
+ }
+ free(buf);
+ if (ret)
+ return log_msg_ret("env", ret);
+
+ return 0;
+}
+
+/**
+ * Execute selected states of the bootm command.
+ *
+ * Note the arguments to this state must be the first argument, Any 'bootm'
+ * or sub-command arguments must have already been taken.
+ *
+ * Note that if states contains more than one flag it MUST contain
+ * BOOTM_STATE_START, since this handles and consumes the command line args.
+ *
+ * Also note that aside from boot_os_fn functions and bootm_load_os no other
+ * functions we store the return value of in 'ret' may use a negative return
+ * value, without special handling.
+ *
+ * @param cmdtp Pointer to bootm command table entry
+ * @param flag Command flags (CMD_FLAG_...)
+ * @param argc Number of subcommand arguments (0 = no arguments)
+ * @param argv Arguments
+ * @param states Mask containing states to run (BOOTM_STATE_...)
+ * @param images Image header information
+ * @param boot_progress 1 to show boot progress, 0 to not do this
+ * @return 0 if ok, something else on error. Some errors will cause this
+ * function to perform a reboot! If states contains BOOTM_STATE_OS_GO
+ * then the intent is to boot an OS, so this function will not return
+ * unless the image type is standalone.
+ */
+int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], int states, bootm_headers_t *images,
+ int boot_progress)
+{
+ boot_os_fn *boot_fn;
+ ulong iflag = 0;
+ int ret = 0, need_boot_fn;
+
+ images->state |= states;
+
+ /*
+ * Work through the states and see how far we get. We stop on
+ * any error.
+ */
+ if (states & BOOTM_STATE_START)
+ ret = bootm_start(cmdtp, flag, argc, argv);
+
+ if (!ret && (states & BOOTM_STATE_FINDOS))
+ ret = bootm_find_os(cmdtp, flag, argc, argv);
+
+ if (!ret && (states & BOOTM_STATE_FINDOTHER))
+ ret = bootm_find_other(cmdtp, flag, argc, argv);
+
+ /* Load the OS */
+ if (!ret && (states & BOOTM_STATE_LOADOS)) {
+ iflag = bootm_disable_interrupts();
+ ret = bootm_load_os(images, 0);
+ if (ret && ret != BOOTM_ERR_OVERLAP)
+ goto err;
+ else if (ret == BOOTM_ERR_OVERLAP)
+ ret = 0;
+ }
+
+ /* Relocate the ramdisk */
+#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
+ if (!ret && (states & BOOTM_STATE_RAMDISK)) {
+ ulong rd_len = images->rd_end - images->rd_start;
+
+ ret = boot_ramdisk_high(&images->lmb, images->rd_start,
+ rd_len, &images->initrd_start, &images->initrd_end);
+ if (!ret) {
+ env_set_hex("initrd_start", images->initrd_start);
+ env_set_hex("initrd_end", images->initrd_end);
+ }
+ }
+#endif
+#if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB)
+ if (!ret && (states & BOOTM_STATE_FDT)) {
+ boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
+ ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
+ &images->ft_len);
+ }
+#endif
+
+ /* From now on, we need the OS boot function */
+ if (ret)
+ return ret;
+ boot_fn = bootm_os_get_boot_func(images->os.os);
+ need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |
+ BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |
+ BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);
+ if (boot_fn == NULL && need_boot_fn) {
+ if (iflag)
+ enable_interrupts();
+ printf("ERROR: booting os '%s' (%d) is not supported\n",
+ genimg_get_os_name(images->os.os), images->os.os);
+ bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
+ return 1;
+ }
+
+
+ /* Call various other states that are not generally used */
+ if (!ret && (states & BOOTM_STATE_OS_CMDLINE))
+ ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);
+ if (!ret && (states & BOOTM_STATE_OS_BD_T))
+ ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
+ if (!ret && (states & BOOTM_STATE_OS_PREP)) {
+ ret = bootm_process_cmdline_env(images->os.os == IH_OS_LINUX);
+ if (ret) {
+ printf("Cmdline setup failed (err=%d)\n", ret);
+ ret = CMD_RET_FAILURE;
+ goto err;
+ }
+ ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
+ }
+
+#ifdef CONFIG_TRACE
+ /* Pretend to run the OS, then run a user command */
+ if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {
+ char *cmd_list = env_get("fakegocmd");
+
+ ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
+ images, boot_fn);
+ if (!ret && cmd_list)
+ ret = run_command_list(cmd_list, -1, flag);
+ }
+#endif
+
+ /* Check for unsupported subcommand. */
+ if (ret) {
+ puts("subcommand not supported\n");
+ return ret;
+ }
+
+ /* Now run the OS! We hope this doesn't return */
+ if (!ret && (states & BOOTM_STATE_OS_GO))
+ ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,
+ images, boot_fn);
+
+ /* Deal with any fallout */
+err:
+ if (iflag)
+ enable_interrupts();
+
+ if (ret == BOOTM_ERR_UNIMPLEMENTED)
+ bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
+ else if (ret == BOOTM_ERR_RESET)
+ do_reset(cmdtp, flag, argc, argv);
+
+ return ret;
+}
+
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+/**
+ * image_get_kernel - verify legacy format kernel image
+ * @img_addr: in RAM address of the legacy format image to be verified
+ * @verify: data CRC verification flag
+ *
+ * image_get_kernel() verifies legacy image integrity and returns pointer to
+ * legacy image header if image verification was completed successfully.
+ *
+ * returns:
+ * pointer to a legacy image header if valid image was found
+ * otherwise return NULL
+ */
+static image_header_t *image_get_kernel(ulong img_addr, int verify)
+{
+ image_header_t *hdr = (image_header_t *)img_addr;
+
+ if (!image_check_magic(hdr)) {
+ puts("Bad Magic Number\n");
+ bootstage_error(BOOTSTAGE_ID_CHECK_MAGIC);
+ return NULL;
+ }
+ bootstage_mark(BOOTSTAGE_ID_CHECK_HEADER);
+
+ if (!image_check_hcrc(hdr)) {
+ puts("Bad Header Checksum\n");
+ bootstage_error(BOOTSTAGE_ID_CHECK_HEADER);
+ return NULL;
+ }
+
+ bootstage_mark(BOOTSTAGE_ID_CHECK_CHECKSUM);
+ image_print_contents(hdr);
+
+ if (verify) {
+ puts(" Verifying Checksum ... ");
+ if (!image_check_dcrc(hdr)) {
+ printf("Bad Data CRC\n");
+ bootstage_error(BOOTSTAGE_ID_CHECK_CHECKSUM);
+ return NULL;
+ }
+ puts("OK\n");
+ }
+ bootstage_mark(BOOTSTAGE_ID_CHECK_ARCH);
+
+ if (!image_check_target_arch(hdr)) {
+ printf("Unsupported Architecture 0x%x\n", image_get_arch(hdr));
+ bootstage_error(BOOTSTAGE_ID_CHECK_ARCH);
+ return NULL;
+ }
+ return hdr;
+}
+#endif
+
+/**
+ * boot_get_kernel - find kernel image
+ * @os_data: pointer to a ulong variable, will hold os data start address
+ * @os_len: pointer to a ulong variable, will hold os data length
+ *
+ * boot_get_kernel() tries to find a kernel image, verifies its integrity
+ * and locates kernel data.
+ *
+ * returns:
+ * pointer to image header if valid image was found, plus kernel start
+ * address and length, otherwise NULL
+ */
+static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], bootm_headers_t *images,
+ ulong *os_data, ulong *os_len)
+{
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+ image_header_t *hdr;
+#endif
+ ulong img_addr;
+ const void *buf;
+ const char *fit_uname_config = NULL;
+ const char *fit_uname_kernel = NULL;
+#if IMAGE_ENABLE_FIT
+ int os_noffset;
+#endif
+
+ img_addr = genimg_get_kernel_addr_fit(argc < 1 ? NULL : argv[0],
+ &fit_uname_config,
+ &fit_uname_kernel);
+
+ bootstage_mark(BOOTSTAGE_ID_CHECK_MAGIC);
+
+ /* check image type, for FIT images get FIT kernel node */
+ *os_data = *os_len = 0;
+ buf = map_sysmem(img_addr, 0);
+ switch (genimg_get_format(buf)) {
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+ case IMAGE_FORMAT_LEGACY:
+ printf("## Booting kernel from Legacy Image at %08lx ...\n",
+ img_addr);
+ hdr = image_get_kernel(img_addr, images->verify);
+ if (!hdr)
+ return NULL;
+ bootstage_mark(BOOTSTAGE_ID_CHECK_IMAGETYPE);
+
+ /* get os_data and os_len */
+ switch (image_get_type(hdr)) {
+ case IH_TYPE_KERNEL:
+ case IH_TYPE_KERNEL_NOLOAD:
+ *os_data = image_get_data(hdr);
+ *os_len = image_get_data_size(hdr);
+ break;
+ case IH_TYPE_MULTI:
+ image_multi_getimg(hdr, 0, os_data, os_len);
+ break;
+ case IH_TYPE_STANDALONE:
+ *os_data = image_get_data(hdr);
+ *os_len = image_get_data_size(hdr);
+ break;
+ default:
+ printf("Wrong Image Type for %s command\n",
+ cmdtp->name);
+ bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE);
+ return NULL;
+ }
+
+ /*
+ * copy image header to allow for image overwrites during
+ * kernel decompression.
+ */
+ memmove(&images->legacy_hdr_os_copy, hdr,
+ sizeof(image_header_t));
+
+ /* save pointer to image header */
+ images->legacy_hdr_os = hdr;
+
+ images->legacy_hdr_valid = 1;
+ bootstage_mark(BOOTSTAGE_ID_DECOMP_IMAGE);
+ break;
+#endif
+#if IMAGE_ENABLE_FIT
+ case IMAGE_FORMAT_FIT:
+ os_noffset = fit_image_load(images, img_addr,
+ &fit_uname_kernel, &fit_uname_config,
+ IH_ARCH_DEFAULT, IH_TYPE_KERNEL,
+ BOOTSTAGE_ID_FIT_KERNEL_START,
+ FIT_LOAD_IGNORED, os_data, os_len);
+ if (os_noffset < 0)
+ return NULL;
+
+ images->fit_hdr_os = map_sysmem(img_addr, 0);
+ images->fit_uname_os = fit_uname_kernel;
+ images->fit_uname_cfg = fit_uname_config;
+ images->fit_noffset_os = os_noffset;
+ break;
+#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ case IMAGE_FORMAT_ANDROID:
+ printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
+ if (android_image_get_kernel(buf, images->verify,
+ os_data, os_len))
+ return NULL;
+ break;
+#endif
+ default:
+ printf("Wrong Image Format for %s command\n", cmdtp->name);
+ bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO);
+ return NULL;
+ }
+
+ debug(" kernel data at 0x%08lx, len = 0x%08lx (%ld)\n",
+ *os_data, *os_len, *os_len);
+
+ return buf;
+}
+
+/**
+ * switch_to_non_secure_mode() - switch to non-secure mode
+ *
+ * This routine is overridden by architectures requiring this feature.
+ */
+void __weak switch_to_non_secure_mode(void)
+{
+}
+
+#else /* USE_HOSTCC */
+
+#if defined(CONFIG_FIT_SIGNATURE)
+static int bootm_host_load_image(const void *fit, int req_image_type,
+ int cfg_noffset)
+{
+ const char *fit_uname_config = NULL;
+ ulong data, len;
+ bootm_headers_t images;
+ int noffset;
+ ulong load_end;
+ uint8_t image_type;
+ uint8_t imape_comp;
+ void *load_buf;
+ int ret;
+
+ fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
+ memset(&images, '\0', sizeof(images));
+ images.verify = 1;
+ noffset = fit_image_load(&images, (ulong)fit,
+ NULL, &fit_uname_config,
+ IH_ARCH_DEFAULT, req_image_type, -1,
+ FIT_LOAD_IGNORED, &data, &len);
+ if (noffset < 0)
+ return noffset;
+ if (fit_image_get_type(fit, noffset, &image_type)) {
+ puts("Can't get image type!\n");
+ return -EINVAL;
+ }
+
+ if (fit_image_get_comp(fit, noffset, &imape_comp)) {
+ puts("Can't get image compression!\n");
+ return -EINVAL;
+ }
+
+ /* Allow the image to expand by a factor of 4, should be safe */
+ load_buf = malloc((1 << 20) + len * 4);
+ ret = image_decomp(imape_comp, 0, data, image_type, load_buf,
+ (void *)data, len, CONFIG_SYS_BOOTM_LEN,
+ &load_end);
+ free(load_buf);
+
+ if (ret) {
+ ret = handle_decomp_error(imape_comp, load_end - 0, ret);
+ if (ret != BOOTM_ERR_UNIMPLEMENTED)
+ return ret;
+ }
+
+ return 0;
+}
+
+int bootm_host_load_images(const void *fit, int cfg_noffset)
+{
+ static uint8_t image_types[] = {
+ IH_TYPE_KERNEL,
+ IH_TYPE_FLATDT,
+ IH_TYPE_RAMDISK,
+ };
+ int err = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(image_types); i++) {
+ int ret;
+
+ ret = bootm_host_load_image(fit, image_types[i], cfg_noffset);
+ if (!err && ret && ret != -ENOENT)
+ err = ret;
+ }
+
+ /* Return the first error we found */
+ return err;
+}
+#endif
+
+#endif /* ndef USE_HOSTCC */
diff --git a/roms/u-boot/common/bootm_os.c b/roms/u-boot/common/bootm_os.c
new file mode 100644
index 000000000..0b6325db6
--- /dev/null
+++ b/roms/u-boot/common/bootm_os.c
@@ -0,0 +1,646 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <common.h>
+#include <bootm.h>
+#include <bootstage.h>
+#include <cpu_func.h>
+#include <efi_loader.h>
+#include <env.h>
+#include <fdt_support.h>
+#include <image.h>
+#include <lmb.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/libfdt.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <vxworks.h>
+#include <tee/optee.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int do_bootm_standalone(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ char *s;
+ int (*appl)(int, char *const[]);
+
+ /* Don't start if "autostart" is set to "no" */
+ s = env_get("autostart");
+ if ((s != NULL) && !strcmp(s, "no")) {
+ env_set_hex("filesize", images->os.image_len);
+ return 0;
+ }
+ appl = (int (*)(int, char * const []))images->ep;
+ appl(argc, argv);
+ return 0;
+}
+
+/*******************************************************************/
+/* OS booting routines */
+/*******************************************************************/
+
+#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9)
+static void copy_args(char *dest, int argc, char *const argv[], char delim)
+{
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (i > 0)
+ *dest++ = delim;
+ strcpy(dest, argv[i]);
+ dest += strlen(argv[i]);
+ }
+}
+#endif
+
+#ifdef CONFIG_BOOTM_NETBSD
+static int do_bootm_netbsd(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ void (*loader)(struct bd_info *, image_header_t *, char *, char *);
+ image_header_t *os_hdr, *hdr;
+ ulong kernel_data, kernel_len;
+ char *cmdline;
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset("NetBSD");
+ return 1;
+ }
+#endif
+ hdr = images->legacy_hdr_os;
+
+ /*
+ * Booting a (NetBSD) kernel image
+ *
+ * This process is pretty similar to a standalone application:
+ * The (first part of an multi-) image must be a stage-2 loader,
+ * which in turn is responsible for loading & invoking the actual
+ * kernel. The only differences are the parameters being passed:
+ * besides the board info strucure, the loader expects a command
+ * line, the name of the console device, and (optionally) the
+ * address of the original image header.
+ */
+ os_hdr = NULL;
+ if (image_check_type(&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) {
+ image_multi_getimg(hdr, 1, &kernel_data, &kernel_len);
+ if (kernel_len)
+ os_hdr = hdr;
+ }
+
+ if (argc > 0) {
+ ulong len;
+ int i;
+
+ for (i = 0, len = 0; i < argc; i += 1)
+ len += strlen(argv[i]) + 1;
+ cmdline = malloc(len);
+ copy_args(cmdline, argc, argv, ' ');
+ } else {
+ cmdline = env_get("bootargs");
+ if (cmdline == NULL)
+ cmdline = "";
+ }
+
+ loader = (void (*)(struct bd_info *, image_header_t *, char *, char *))images->ep;
+
+ printf("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
+ (ulong)loader);
+
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ /*
+ * NetBSD Stage-2 Loader Parameters:
+ * arg[0]: pointer to board info data
+ * arg[1]: image load address
+ * arg[2]: char pointer to the console device to use
+ * arg[3]: char pointer to the boot arguments
+ */
+ (*loader)(gd->bd, os_hdr, "", cmdline);
+
+ return 1;
+}
+#endif /* CONFIG_BOOTM_NETBSD*/
+
+#ifdef CONFIG_LYNXKDI
+static int do_bootm_lynxkdi(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ image_header_t *hdr = &images->legacy_hdr_os_copy;
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset("Lynx");
+ return 1;
+ }
+#endif
+
+ lynxkdi_boot((image_header_t *)hdr);
+
+ return 1;
+}
+#endif /* CONFIG_LYNXKDI */
+
+#ifdef CONFIG_BOOTM_RTEMS
+static int do_bootm_rtems(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ void (*entry_point)(struct bd_info *);
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset("RTEMS");
+ return 1;
+ }
+#endif
+
+ entry_point = (void (*)(struct bd_info *))images->ep;
+
+ printf("## Transferring control to RTEMS (at address %08lx) ...\n",
+ (ulong)entry_point);
+
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ /*
+ * RTEMS Parameters:
+ * r3: ptr to board info data
+ */
+ (*entry_point)(gd->bd);
+
+ return 1;
+}
+#endif /* CONFIG_BOOTM_RTEMS */
+
+#if defined(CONFIG_BOOTM_OSE)
+static int do_bootm_ose(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ void (*entry_point)(void);
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset("OSE");
+ return 1;
+ }
+#endif
+
+ entry_point = (void (*)(void))images->ep;
+
+ printf("## Transferring control to OSE (at address %08lx) ...\n",
+ (ulong)entry_point);
+
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ /*
+ * OSE Parameters:
+ * None
+ */
+ (*entry_point)();
+
+ return 1;
+}
+#endif /* CONFIG_BOOTM_OSE */
+
+#if defined(CONFIG_BOOTM_PLAN9)
+static int do_bootm_plan9(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ void (*entry_point)(void);
+ char *s;
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset("Plan 9");
+ return 1;
+ }
+#endif
+
+ /* See README.plan9 */
+ s = env_get("confaddr");
+ if (s != NULL) {
+ char *confaddr = (char *)simple_strtoul(s, NULL, 16);
+
+ if (argc > 0) {
+ copy_args(confaddr, argc, argv, '\n');
+ } else {
+ s = env_get("bootargs");
+ if (s != NULL)
+ strcpy(confaddr, s);
+ }
+ }
+
+ entry_point = (void (*)(void))images->ep;
+
+ printf("## Transferring control to Plan 9 (at address %08lx) ...\n",
+ (ulong)entry_point);
+
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ /*
+ * Plan 9 Parameters:
+ * None
+ */
+ (*entry_point)();
+
+ return 1;
+}
+#endif /* CONFIG_BOOTM_PLAN9 */
+
+#if defined(CONFIG_BOOTM_VXWORKS) && \
+ (defined(CONFIG_PPC) || defined(CONFIG_ARM))
+
+static void do_bootvx_fdt(bootm_headers_t *images)
+{
+#if defined(CONFIG_OF_LIBFDT)
+ int ret;
+ char *bootline;
+ ulong of_size = images->ft_len;
+ char **of_flat_tree = &images->ft_addr;
+ struct lmb *lmb = &images->lmb;
+
+ if (*of_flat_tree) {
+ boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);
+
+ ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
+ if (ret)
+ return;
+
+ /* Update ethernet nodes */
+ fdt_fixup_ethernet(*of_flat_tree);
+
+ ret = fdt_add_subnode(*of_flat_tree, 0, "chosen");
+ if ((ret >= 0 || ret == -FDT_ERR_EXISTS)) {
+ bootline = env_get("bootargs");
+ if (bootline) {
+ ret = fdt_find_and_setprop(*of_flat_tree,
+ "/chosen", "bootargs",
+ bootline,
+ strlen(bootline) + 1, 1);
+ if (ret < 0) {
+ printf("## ERROR: %s : %s\n", __func__,
+ fdt_strerror(ret));
+ return;
+ }
+ }
+ } else {
+ printf("## ERROR: %s : %s\n", __func__,
+ fdt_strerror(ret));
+ return;
+ }
+ }
+#endif
+
+ boot_prep_vxworks(images);
+
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+#if defined(CONFIG_OF_LIBFDT)
+ printf("## Starting vxWorks at 0x%08lx, device tree at 0x%08lx ...\n",
+ (ulong)images->ep, (ulong)*of_flat_tree);
+#else
+ printf("## Starting vxWorks at 0x%08lx\n", (ulong)images->ep);
+#endif
+
+ boot_jump_vxworks(images);
+
+ puts("## vxWorks terminated\n");
+}
+
+static int do_bootm_vxworks_legacy(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset("VxWorks");
+ return 1;
+ }
+#endif
+
+ do_bootvx_fdt(images);
+
+ return 1;
+}
+
+int do_bootm_vxworks(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ char *bootargs;
+ int pos;
+ unsigned long vxflags;
+ bool std_dtb = false;
+
+ /* get bootargs env */
+ bootargs = env_get("bootargs");
+
+ if (bootargs != NULL) {
+ for (pos = 0; pos < strlen(bootargs); pos++) {
+ /* find f=0xnumber flag */
+ if ((bootargs[pos] == '=') && (pos >= 1) &&
+ (bootargs[pos - 1] == 'f')) {
+ vxflags = simple_strtoul(&bootargs[pos + 1],
+ NULL, 16);
+ if (vxflags & VXWORKS_SYSFLG_STD_DTB)
+ std_dtb = true;
+ }
+ }
+ }
+
+ if (std_dtb) {
+ if (flag & BOOTM_STATE_OS_PREP)
+ printf(" Using standard DTB\n");
+ return do_bootm_linux(flag, argc, argv, images);
+ } else {
+ if (flag & BOOTM_STATE_OS_PREP)
+ printf(" !!! WARNING !!! Using legacy DTB\n");
+ return do_bootm_vxworks_legacy(flag, argc, argv, images);
+ }
+}
+#endif
+
+#if defined(CONFIG_CMD_ELF)
+static int do_bootm_qnxelf(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ char *local_args[2];
+ char str[16];
+ int dcache;
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset("QNX");
+ return 1;
+ }
+#endif
+
+ sprintf(str, "%lx", images->ep); /* write entry-point into string */
+ local_args[0] = argv[0];
+ local_args[1] = str; /* and provide it via the arguments */
+
+ /*
+ * QNX images require the data cache is disabled.
+ */
+ dcache = dcache_status();
+ if (dcache)
+ dcache_disable();
+
+ do_bootelf(NULL, 0, 2, local_args);
+
+ if (dcache)
+ dcache_enable();
+
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_INTEGRITY
+static int do_bootm_integrity(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ void (*entry_point)(void);
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset("INTEGRITY");
+ return 1;
+ }
+#endif
+
+ entry_point = (void (*)(void))images->ep;
+
+ printf("## Transferring control to INTEGRITY (at address %08lx) ...\n",
+ (ulong)entry_point);
+
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ /*
+ * INTEGRITY Parameters:
+ * None
+ */
+ (*entry_point)();
+
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_BOOTM_OPENRTOS
+static int do_bootm_openrtos(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ void (*entry_point)(void);
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+ entry_point = (void (*)(void))images->ep;
+
+ printf("## Transferring control to OpenRTOS (at address %08lx) ...\n",
+ (ulong)entry_point);
+
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ /*
+ * OpenRTOS Parameters:
+ * None
+ */
+ (*entry_point)();
+
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_BOOTM_OPTEE
+static int do_bootm_tee(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ int ret;
+
+ /* Verify OS type */
+ if (images->os.os != IH_OS_TEE) {
+ return 1;
+ };
+
+ /* Validate OPTEE header */
+ ret = optee_verify_bootm_image(images->os.image_start,
+ images->os.load,
+ images->os.image_len);
+ if (ret)
+ return ret;
+
+ /* Locate FDT etc */
+ ret = bootm_find_images(flag, argc, argv, 0, 0);
+ if (ret)
+ return ret;
+
+ /* From here we can run the regular linux boot path */
+ return do_bootm_linux(flag, argc, argv, images);
+}
+#endif
+
+#ifdef CONFIG_BOOTM_EFI
+static int do_bootm_efi(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ int ret;
+ efi_status_t efi_ret;
+ void *image_buf;
+
+ if (flag != BOOTM_STATE_OS_GO)
+ return 0;
+
+ /* Locate FDT, if provided */
+ ret = bootm_find_images(flag, argc, argv, 0, 0);
+ if (ret)
+ return ret;
+
+ /* Initialize EFI drivers */
+ efi_ret = efi_init_obj_list();
+ if (efi_ret != EFI_SUCCESS) {
+ printf("## Failed to initialize UEFI sub-system: r = %lu\n",
+ efi_ret & ~EFI_ERROR_MASK);
+ return 1;
+ }
+
+ /* Install device tree */
+ efi_ret = efi_install_fdt(images->ft_len
+ ? images->ft_addr : EFI_FDT_USE_INTERNAL);
+ if (efi_ret != EFI_SUCCESS) {
+ printf("## Failed to install device tree: r = %lu\n",
+ efi_ret & ~EFI_ERROR_MASK);
+ return 1;
+ }
+
+ /* Run EFI image */
+ printf("## Transferring control to EFI (at address %08lx) ...\n",
+ images->ep);
+ bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+ /* We expect to return */
+ images->os.type = IH_TYPE_STANDALONE;
+
+ image_buf = map_sysmem(images->ep, images->os.image_len);
+
+ efi_ret = efi_run_image(image_buf, images->os.image_len);
+ if (efi_ret != EFI_SUCCESS)
+ return 1;
+ return 0;
+}
+#endif
+
+static boot_os_fn *boot_os[] = {
+ [IH_OS_U_BOOT] = do_bootm_standalone,
+#ifdef CONFIG_BOOTM_LINUX
+ [IH_OS_LINUX] = do_bootm_linux,
+#endif
+#ifdef CONFIG_BOOTM_NETBSD
+ [IH_OS_NETBSD] = do_bootm_netbsd,
+#endif
+#ifdef CONFIG_LYNXKDI
+ [IH_OS_LYNXOS] = do_bootm_lynxkdi,
+#endif
+#ifdef CONFIG_BOOTM_RTEMS
+ [IH_OS_RTEMS] = do_bootm_rtems,
+#endif
+#if defined(CONFIG_BOOTM_OSE)
+ [IH_OS_OSE] = do_bootm_ose,
+#endif
+#if defined(CONFIG_BOOTM_PLAN9)
+ [IH_OS_PLAN9] = do_bootm_plan9,
+#endif
+#if defined(CONFIG_BOOTM_VXWORKS) && \
+ (defined(CONFIG_PPC) || defined(CONFIG_ARM) || defined(CONFIG_RISCV))
+ [IH_OS_VXWORKS] = do_bootm_vxworks,
+#endif
+#if defined(CONFIG_CMD_ELF)
+ [IH_OS_QNX] = do_bootm_qnxelf,
+#endif
+#ifdef CONFIG_INTEGRITY
+ [IH_OS_INTEGRITY] = do_bootm_integrity,
+#endif
+#ifdef CONFIG_BOOTM_OPENRTOS
+ [IH_OS_OPENRTOS] = do_bootm_openrtos,
+#endif
+#ifdef CONFIG_BOOTM_OPTEE
+ [IH_OS_TEE] = do_bootm_tee,
+#endif
+#ifdef CONFIG_BOOTM_EFI
+ [IH_OS_EFI] = do_bootm_efi,
+#endif
+};
+
+/* Allow for arch specific config before we boot */
+__weak void arch_preboot_os(void)
+{
+ /* please define platform specific arch_preboot_os() */
+}
+
+/* Allow for board specific config before we boot */
+__weak void board_preboot_os(void)
+{
+ /* please define board specific board_preboot_os() */
+}
+
+int boot_selected_os(int argc, char *const argv[], int state,
+ bootm_headers_t *images, boot_os_fn *boot_fn)
+{
+ arch_preboot_os();
+ board_preboot_os();
+ boot_fn(state, argc, argv, images);
+
+ /* Stand-alone may return when 'autostart' is 'no' */
+ if (images->os.type == IH_TYPE_STANDALONE ||
+ IS_ENABLED(CONFIG_SANDBOX) ||
+ state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
+ return 0;
+ bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
+ debug("\n## Control returned to monitor - resetting...\n");
+
+ return BOOTM_ERR_RESET;
+}
+
+boot_os_fn *bootm_os_get_boot_func(int os)
+{
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ static bool relocated;
+
+ if (!relocated) {
+ int i;
+
+ /* relocate boot function table */
+ for (i = 0; i < ARRAY_SIZE(boot_os); i++)
+ if (boot_os[i] != NULL)
+ boot_os[i] += gd->reloc_off;
+
+ relocated = true;
+ }
+#endif
+ return boot_os[os];
+}
diff --git a/roms/u-boot/common/bootretry.c b/roms/u-boot/common/bootretry.c
new file mode 100644
index 000000000..dac891fbc
--- /dev/null
+++ b/roms/u-boot/common/bootretry.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <common.h>
+#include <bootretry.h>
+#include <cli.h>
+#include <env.h>
+#include <errno.h>
+#include <time.h>
+#include <watchdog.h>
+
+#ifndef CONFIG_BOOT_RETRY_MIN
+#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
+#endif
+
+static uint64_t endtime; /* must be set, default is instant timeout */
+static int retry_time = -1; /* -1 so can call readline before main_loop */
+
+/***************************************************************************
+ * initialize command line timeout
+ */
+void bootretry_init_cmd_timeout(void)
+{
+ char *s = env_get("bootretry");
+
+ if (s != NULL)
+ retry_time = (int)simple_strtol(s, NULL, 10);
+ else
+ retry_time = CONFIG_BOOT_RETRY_TIME;
+
+ if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
+ retry_time = CONFIG_BOOT_RETRY_MIN;
+}
+
+/***************************************************************************
+ * reset command line timeout to retry_time seconds
+ */
+void bootretry_reset_cmd_timeout(void)
+{
+ endtime = endtick(retry_time);
+}
+
+int bootretry_tstc_timeout(void)
+{
+ while (!tstc()) { /* while no incoming data */
+ if (retry_time >= 0 && get_ticks() > endtime)
+ return -ETIMEDOUT;
+ WATCHDOG_RESET();
+ }
+
+ return 0;
+}
+
+void bootretry_dont_retry(void)
+{
+ retry_time = -1;
+}
diff --git a/roms/u-boot/common/bootstage.c b/roms/u-boot/common/bootstage.c
new file mode 100644
index 000000000..462110568
--- /dev/null
+++ b/roms/u-boot/common/bootstage.c
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011, Google Inc. All rights reserved.
+ */
+
+
+/*
+ * This module records the progress of boot and arbitrary commands, and
+ * permits accurate timestamping of each.
+ */
+
+#define LOG_CATEGORY LOGC_BOOT
+
+#include <common.h>
+#include <bootstage.h>
+#include <hang.h>
+#include <log.h>
+#include <malloc.h>
+#include <sort.h>
+#include <spl.h>
+#include <asm/global_data.h>
+#include <linux/compiler.h>
+#include <linux/libfdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+ RECORD_COUNT = CONFIG_VAL(BOOTSTAGE_RECORD_COUNT),
+};
+
+struct bootstage_record {
+ ulong time_us;
+ uint32_t start_us;
+ const char *name;
+ int flags; /* see enum bootstage_flags */
+ enum bootstage_id id;
+};
+
+struct bootstage_data {
+ uint rec_count;
+ uint next_id;
+ struct bootstage_record record[RECORD_COUNT];
+};
+
+enum {
+ BOOTSTAGE_VERSION = 0,
+ BOOTSTAGE_MAGIC = 0xb00757a3,
+ BOOTSTAGE_DIGITS = 9,
+};
+
+struct bootstage_hdr {
+ u32 version; /* BOOTSTAGE_VERSION */
+ u32 count; /* Number of records */
+ u32 size; /* Total data size (non-zero if valid) */
+ u32 magic; /* Magic number */
+ u32 next_id; /* Next ID to use for bootstage */
+};
+
+int bootstage_relocate(void)
+{
+ struct bootstage_data *data = gd->bootstage;
+ int i;
+ char *ptr;
+
+ /* Figure out where to relocate the strings to */
+ ptr = (char *)(data + 1);
+
+ /*
+ * Duplicate all strings. They may point to an old location in the
+ * program .text section that can eventually get trashed.
+ */
+ debug("Relocating %d records\n", data->rec_count);
+ for (i = 0; i < data->rec_count; i++) {
+ const char *from = data->record[i].name;
+
+ strcpy(ptr, from);
+ data->record[i].name = ptr;
+ ptr += strlen(ptr) + 1;
+ }
+
+ return 0;
+}
+
+struct bootstage_record *find_id(struct bootstage_data *data,
+ enum bootstage_id id)
+{
+ struct bootstage_record *rec;
+ struct bootstage_record *end;
+
+ for (rec = data->record, end = rec + data->rec_count; rec < end;
+ rec++) {
+ if (rec->id == id)
+ return rec;
+ }
+
+ return NULL;
+}
+
+struct bootstage_record *ensure_id(struct bootstage_data *data,
+ enum bootstage_id id)
+{
+ struct bootstage_record *rec;
+
+ rec = find_id(data, id);
+ if (!rec && data->rec_count < RECORD_COUNT) {
+ rec = &data->record[data->rec_count++];
+ rec->id = id;
+ return rec;
+ }
+
+ return rec;
+}
+
+ulong bootstage_add_record(enum bootstage_id id, const char *name,
+ int flags, ulong mark)
+{
+ struct bootstage_data *data = gd->bootstage;
+ struct bootstage_record *rec;
+
+ /*
+ * initf_bootstage() is called very early during boot but since hang()
+ * calls bootstage_error() we can be called before bootstage is set up.
+ * Add a check to avoid this.
+ */
+ if (!data)
+ return mark;
+ if (flags & BOOTSTAGEF_ALLOC)
+ id = data->next_id++;
+
+ /* Only record the first event for each */
+ rec = find_id(data, id);
+ if (!rec) {
+ if (data->rec_count < RECORD_COUNT) {
+ rec = &data->record[data->rec_count++];
+ rec->time_us = mark;
+ rec->name = name;
+ rec->flags = flags;
+ rec->id = id;
+ } else {
+ log_warning("Bootstage space exhasuted\n");
+ }
+ }
+
+ /* Tell the board about this progress */
+ show_boot_progress(flags & BOOTSTAGEF_ERROR ? -id : id);
+
+ return mark;
+}
+
+
+ulong bootstage_mark(enum bootstage_id id)
+{
+ return bootstage_add_record(id, NULL, 0, timer_get_boot_us());
+}
+
+ulong bootstage_error(enum bootstage_id id)
+{
+ return bootstage_add_record(id, NULL, BOOTSTAGEF_ERROR,
+ timer_get_boot_us());
+}
+
+ulong bootstage_mark_name(enum bootstage_id id, const char *name)
+{
+ int flags = 0;
+
+ if (id == BOOTSTAGE_ID_ALLOC)
+ flags = BOOTSTAGEF_ALLOC;
+
+ return bootstage_add_record(id, name, flags, timer_get_boot_us());
+}
+
+ulong bootstage_mark_code(const char *file, const char *func, int linenum)
+{
+ char *str, *p;
+ __maybe_unused char *end;
+ int len = 0;
+
+ /* First work out the length we need to allocate */
+ if (linenum != -1)
+ len = 11;
+ if (func)
+ len += strlen(func);
+ if (file)
+ len += strlen(file);
+
+ str = malloc(len + 1);
+ p = str;
+ end = p + len;
+ if (file)
+ p += snprintf(p, end - p, "%s,", file);
+ if (linenum != -1)
+ p += snprintf(p, end - p, "%d", linenum);
+ if (func)
+ p += snprintf(p, end - p, ": %s", func);
+
+ return bootstage_mark_name(BOOTSTAGE_ID_ALLOC, str);
+}
+
+uint32_t bootstage_start(enum bootstage_id id, const char *name)
+{
+ struct bootstage_data *data = gd->bootstage;
+ struct bootstage_record *rec = ensure_id(data, id);
+ ulong start_us = timer_get_boot_us();
+
+ if (rec) {
+ rec->start_us = start_us;
+ rec->name = name;
+ }
+
+ return start_us;
+}
+
+uint32_t bootstage_accum(enum bootstage_id id)
+{
+ struct bootstage_data *data = gd->bootstage;
+ struct bootstage_record *rec = ensure_id(data, id);
+ uint32_t duration;
+
+ if (!rec)
+ return 0;
+ duration = (uint32_t)timer_get_boot_us() - rec->start_us;
+ rec->time_us += duration;
+
+ return duration;
+}
+
+/**
+ * Get a record name as a printable string
+ *
+ * @param buf Buffer to put name if needed
+ * @param len Length of buffer
+ * @param rec Boot stage record to get the name from
+ * @return pointer to name, either from the record or pointing to buf.
+ */
+static const char *get_record_name(char *buf, int len,
+ const struct bootstage_record *rec)
+{
+ if (rec->name)
+ return rec->name;
+ else if (rec->id >= BOOTSTAGE_ID_USER)
+ snprintf(buf, len, "user_%d", rec->id - BOOTSTAGE_ID_USER);
+ else
+ snprintf(buf, len, "id=%d", rec->id);
+
+ return buf;
+}
+
+static uint32_t print_time_record(struct bootstage_record *rec, uint32_t prev)
+{
+ char buf[20];
+
+ if (prev == -1U) {
+ printf("%11s", "");
+ print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);
+ } else {
+ print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);
+ print_grouped_ull(rec->time_us - prev, BOOTSTAGE_DIGITS);
+ }
+ printf(" %s\n", get_record_name(buf, sizeof(buf), rec));
+
+ return rec->time_us;
+}
+
+static int h_compare_record(const void *r1, const void *r2)
+{
+ const struct bootstage_record *rec1 = r1, *rec2 = r2;
+
+ return rec1->time_us > rec2->time_us ? 1 : -1;
+}
+
+#ifdef CONFIG_OF_LIBFDT
+/**
+ * Add all bootstage timings to a device tree.
+ *
+ * @param blob Device tree blob
+ * @return 0 on success, != 0 on failure.
+ */
+static int add_bootstages_devicetree(struct fdt_header *blob)
+{
+ struct bootstage_data *data = gd->bootstage;
+ int bootstage;
+ char buf[20];
+ int recnum;
+ int i;
+
+ if (!blob)
+ return 0;
+
+ /*
+ * Create the node for bootstage.
+ * The address of flat device tree is set up by the command bootm.
+ */
+ bootstage = fdt_add_subnode(blob, 0, "bootstage");
+ if (bootstage < 0)
+ return -EINVAL;
+
+ /*
+ * Insert the timings to the device tree in the reverse order so
+ * that they can be printed in the Linux kernel in the right order.
+ */
+ for (recnum = data->rec_count - 1, i = 0; recnum >= 0; recnum--, i++) {
+ struct bootstage_record *rec = &data->record[recnum];
+ int node;
+
+ if (rec->id != BOOTSTAGE_ID_AWAKE && rec->time_us == 0)
+ continue;
+
+ node = fdt_add_subnode(blob, bootstage, simple_itoa(i));
+ if (node < 0)
+ break;
+
+ /* add properties to the node. */
+ if (fdt_setprop_string(blob, node, "name",
+ get_record_name(buf, sizeof(buf), rec)))
+ return -EINVAL;
+
+ /* Check if this is a 'mark' or 'accum' record */
+ if (fdt_setprop_cell(blob, node,
+ rec->start_us ? "accum" : "mark",
+ rec->time_us))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int bootstage_fdt_add_report(void)
+{
+ if (add_bootstages_devicetree(working_fdt))
+ puts("bootstage: Failed to add to device tree\n");
+
+ return 0;
+}
+#endif
+
+void bootstage_report(void)
+{
+ struct bootstage_data *data = gd->bootstage;
+ struct bootstage_record *rec = data->record;
+ uint32_t prev;
+ int i;
+
+ printf("Timer summary in microseconds (%d records):\n",
+ data->rec_count);
+ printf("%11s%11s %s\n", "Mark", "Elapsed", "Stage");
+
+ prev = print_time_record(rec, 0);
+
+ /* Sort records by increasing time */
+ qsort(data->record, data->rec_count, sizeof(*rec), h_compare_record);
+
+ for (i = 1, rec++; i < data->rec_count; i++, rec++) {
+ if (rec->id && !rec->start_us)
+ prev = print_time_record(rec, prev);
+ }
+ if (data->rec_count > RECORD_COUNT)
+ printf("Overflowed internal boot id table by %d entries\n"
+ "Please increase CONFIG_(SPL_TPL_)BOOTSTAGE_RECORD_COUNT\n",
+ data->rec_count - RECORD_COUNT);
+
+ puts("\nAccumulated time:\n");
+ for (i = 0, rec = data->record; i < data->rec_count; i++, rec++) {
+ if (rec->start_us)
+ prev = print_time_record(rec, -1);
+ }
+}
+
+/**
+ * Append data to a memory buffer
+ *
+ * Write data to the buffer if there is space. Whether there is space or not,
+ * the buffer pointer is incremented.
+ *
+ * @param ptrp Pointer to buffer, updated by this function
+ * @param end Pointer to end of buffer
+ * @param data Data to write to buffer
+ * @param size Size of data
+ */
+static void append_data(char **ptrp, char *end, const void *data, int size)
+{
+ char *ptr = *ptrp;
+
+ *ptrp += size;
+ if (*ptrp > end)
+ return;
+
+ memcpy(ptr, data, size);
+}
+
+int bootstage_stash(void *base, int size)
+{
+ const struct bootstage_data *data = gd->bootstage;
+ struct bootstage_hdr *hdr = (struct bootstage_hdr *)base;
+ const struct bootstage_record *rec;
+ char buf[20];
+ char *ptr = base, *end = ptr + size;
+ int i;
+
+ if (hdr + 1 > (struct bootstage_hdr *)end) {
+ debug("%s: Not enough space for bootstage hdr\n", __func__);
+ return -ENOSPC;
+ }
+
+ /* Write an arbitrary version number */
+ hdr->version = BOOTSTAGE_VERSION;
+
+ hdr->count = data->rec_count;
+ hdr->size = 0;
+ hdr->magic = BOOTSTAGE_MAGIC;
+ hdr->next_id = data->next_id;
+ ptr += sizeof(*hdr);
+
+ /* Write the records, silently stopping when we run out of space */
+ for (rec = data->record, i = 0; i < data->rec_count; i++, rec++)
+ append_data(&ptr, end, rec, sizeof(*rec));
+
+ /* Write the name strings */
+ for (rec = data->record, i = 0; i < data->rec_count; i++, rec++) {
+ const char *name;
+
+ name = get_record_name(buf, sizeof(buf), rec);
+ append_data(&ptr, end, name, strlen(name) + 1);
+ }
+
+ /* Check for buffer overflow */
+ if (ptr > end) {
+ debug("%s: Not enough space for bootstage stash\n", __func__);
+ return -ENOSPC;
+ }
+
+ /* Update total data size */
+ hdr->size = ptr - (char *)base;
+ debug("Stashed %d records\n", hdr->count);
+
+ return 0;
+}
+
+int bootstage_unstash(const void *base, int size)
+{
+ const struct bootstage_hdr *hdr = (struct bootstage_hdr *)base;
+ struct bootstage_data *data = gd->bootstage;
+ const char *ptr = base, *end = ptr + size;
+ struct bootstage_record *rec;
+ uint rec_size;
+ int i;
+
+ if (size == -1)
+ end = (char *)(~(uintptr_t)0);
+
+ if (hdr + 1 > (struct bootstage_hdr *)end) {
+ debug("%s: Not enough space for bootstage hdr\n", __func__);
+ return -EPERM;
+ }
+
+ if (hdr->magic != BOOTSTAGE_MAGIC) {
+ debug("%s: Invalid bootstage magic\n", __func__);
+ return -ENOENT;
+ }
+
+ if (ptr + hdr->size > end) {
+ debug("%s: Bootstage data runs past buffer end\n", __func__);
+ return -ENOSPC;
+ }
+
+ if (hdr->count * sizeof(*rec) > hdr->size) {
+ debug("%s: Bootstage has %d records needing %lu bytes, but "
+ "only %d bytes is available\n", __func__, hdr->count,
+ (ulong)hdr->count * sizeof(*rec), hdr->size);
+ return -ENOSPC;
+ }
+
+ if (hdr->version != BOOTSTAGE_VERSION) {
+ debug("%s: Bootstage data version %#0x unrecognised\n",
+ __func__, hdr->version);
+ return -EINVAL;
+ }
+
+ if (data->rec_count + hdr->count > RECORD_COUNT) {
+ debug("%s: Bootstage has %d records, we have space for %d\n"
+ "Please increase CONFIG_(SPL_)BOOTSTAGE_RECORD_COUNT\n",
+ __func__, hdr->count, RECORD_COUNT - data->rec_count);
+ return -ENOSPC;
+ }
+
+ ptr += sizeof(*hdr);
+
+ /* Read the records */
+ rec_size = hdr->count * sizeof(*data->record);
+ memcpy(data->record + data->rec_count, ptr, rec_size);
+
+ /* Read the name strings */
+ ptr += rec_size;
+ for (rec = data->record + data->next_id, i = 0; i < hdr->count;
+ i++, rec++) {
+ rec->name = ptr;
+ if (spl_phase() == PHASE_SPL)
+ rec->name = strdup(ptr);
+
+ /* Assume no data corruption here */
+ ptr += strlen(ptr) + 1;
+ }
+
+ /* Mark the records as read */
+ data->rec_count += hdr->count;
+ data->next_id = hdr->next_id;
+ debug("Unstashed %d records\n", hdr->count);
+
+ return 0;
+}
+
+int bootstage_get_size(void)
+{
+ struct bootstage_data *data = gd->bootstage;
+ struct bootstage_record *rec;
+ int size;
+ int i;
+
+ size = sizeof(struct bootstage_data);
+ for (rec = data->record, i = 0; i < data->rec_count;
+ i++, rec++)
+ size += strlen(rec->name) + 1;
+
+ return size;
+}
+
+int bootstage_init(bool first)
+{
+ struct bootstage_data *data;
+ int size = sizeof(struct bootstage_data);
+
+ gd->bootstage = (struct bootstage_data *)malloc(size);
+ if (!gd->bootstage)
+ return -ENOMEM;
+ data = gd->bootstage;
+ memset(data, '\0', size);
+ if (first) {
+ data->next_id = BOOTSTAGE_ID_USER;
+ bootstage_add_record(BOOTSTAGE_ID_AWAKE, "reset", 0, 0);
+ }
+
+ return 0;
+}
diff --git a/roms/u-boot/common/bouncebuf.c b/roms/u-boot/common/bouncebuf.c
new file mode 100644
index 000000000..6d98920de
--- /dev/null
+++ b/roms/u-boot/common/bouncebuf.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Generic bounce buffer implementation
+ *
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <malloc.h>
+#include <errno.h>
+#include <bouncebuf.h>
+#include <asm/cache.h>
+
+static int addr_aligned(struct bounce_buffer *state)
+{
+ const ulong align_mask = ARCH_DMA_MINALIGN - 1;
+
+ /* Check if start is aligned */
+ if ((ulong)state->user_buffer & align_mask) {
+ debug("Unaligned buffer address %p\n", state->user_buffer);
+ return 0;
+ }
+
+ /* Check if length is aligned */
+ if (state->len != state->len_aligned) {
+ debug("Unaligned buffer length %zu\n", state->len);
+ return 0;
+ }
+
+ /* Aligned */
+ return 1;
+}
+
+int bounce_buffer_start_extalign(struct bounce_buffer *state, void *data,
+ size_t len, unsigned int flags,
+ size_t alignment,
+ int (*addr_is_aligned)(struct bounce_buffer *state))
+{
+ state->user_buffer = data;
+ state->bounce_buffer = data;
+ state->len = len;
+ state->len_aligned = roundup(len, alignment);
+ state->flags = flags;
+
+ if (!addr_is_aligned(state)) {
+ state->bounce_buffer = memalign(alignment,
+ state->len_aligned);
+ if (!state->bounce_buffer)
+ return -ENOMEM;
+
+ if (state->flags & GEN_BB_READ)
+ memcpy(state->bounce_buffer, state->user_buffer,
+ state->len);
+ }
+
+ /*
+ * Flush data to RAM so DMA reads can pick it up,
+ * and any CPU writebacks don't race with DMA writes
+ */
+ flush_dcache_range((unsigned long)state->bounce_buffer,
+ (unsigned long)(state->bounce_buffer) +
+ state->len_aligned);
+
+ return 0;
+}
+
+int bounce_buffer_start(struct bounce_buffer *state, void *data,
+ size_t len, unsigned int flags)
+{
+ return bounce_buffer_start_extalign(state, data, len, flags,
+ ARCH_DMA_MINALIGN,
+ addr_aligned);
+}
+
+int bounce_buffer_stop(struct bounce_buffer *state)
+{
+ if (state->flags & GEN_BB_WRITE) {
+ /* Invalidate cache so that CPU can see any newly DMA'd data */
+ invalidate_dcache_range((unsigned long)state->bounce_buffer,
+ (unsigned long)(state->bounce_buffer) +
+ state->len_aligned);
+ }
+
+ if (state->bounce_buffer == state->user_buffer)
+ return 0;
+
+ if (state->flags & GEN_BB_WRITE)
+ memcpy(state->user_buffer, state->bounce_buffer, state->len);
+
+ free(state->bounce_buffer);
+
+ return 0;
+}
diff --git a/roms/u-boot/common/cli.c b/roms/u-boot/common/cli.c
new file mode 100644
index 000000000..048eacb9e
--- /dev/null
+++ b/roms/u-boot/common/cli.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Add to readline cmdline-editing by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
+ */
+
+#include <common.h>
+#include <bootstage.h>
+#include <cli.h>
+#include <cli_hush.h>
+#include <command.h>
+#include <console.h>
+#include <env.h>
+#include <fdtdec.h>
+#include <hang.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_CMDLINE
+/*
+ * Run a command using the selected parser.
+ *
+ * @param cmd Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+int run_command(const char *cmd, int flag)
+{
+#if !CONFIG_IS_ENABLED(HUSH_PARSER)
+ /*
+ * cli_run_command can return 0 or 1 for success, so clean up
+ * its result.
+ */
+ if (cli_simple_run_command(cmd, flag) == -1)
+ return 1;
+
+ return 0;
+#else
+ int hush_flags = FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP;
+
+ if (flag & CMD_FLAG_ENV)
+ hush_flags |= FLAG_CONT_ON_NEWLINE;
+ return parse_string_outer(cmd, hush_flags);
+#endif
+}
+
+/*
+ * Run a command using the selected parser, and check if it is repeatable.
+ *
+ * @param cmd Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 (not repeatable) or 1 (repeatable) on success, -1 on error.
+ */
+int run_command_repeatable(const char *cmd, int flag)
+{
+#ifndef CONFIG_HUSH_PARSER
+ return cli_simple_run_command(cmd, flag);
+#else
+ /*
+ * parse_string_outer() returns 1 for failure, so clean up
+ * its result.
+ */
+ if (parse_string_outer(cmd,
+ FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP))
+ return -1;
+
+ return 0;
+#endif
+}
+#else
+__weak int board_run_command(const char *cmdline)
+{
+ printf("## Commands are disabled. Please enable CONFIG_CMDLINE.\n");
+
+ return 1;
+}
+#endif /* CONFIG_CMDLINE */
+
+int run_command_list(const char *cmd, int len, int flag)
+{
+ int need_buff = 1;
+ char *buff = (char *)cmd; /* cast away const */
+ int rcode = 0;
+
+ if (len == -1) {
+ len = strlen(cmd);
+#ifdef CONFIG_HUSH_PARSER
+ /* hush will never change our string */
+ need_buff = 0;
+#else
+ /* the built-in parser will change our string if it sees \n */
+ need_buff = strchr(cmd, '\n') != NULL;
+#endif
+ }
+ if (need_buff) {
+ buff = malloc(len + 1);
+ if (!buff)
+ return 1;
+ memcpy(buff, cmd, len);
+ buff[len] = '\0';
+ }
+#ifdef CONFIG_HUSH_PARSER
+ rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
+#else
+ /*
+ * This function will overwrite any \n it sees with a \0, which
+ * is why it can't work with a const char *. Here we are making
+ * using of internal knowledge of this function, to avoid always
+ * doing a malloc() which is actually required only in a case that
+ * is pretty rare.
+ */
+#ifdef CONFIG_CMDLINE
+ rcode = cli_simple_run_command_list(buff, flag);
+#else
+ rcode = board_run_command(buff);
+#endif
+#endif
+ if (need_buff)
+ free(buff);
+
+ return rcode;
+}
+
+/****************************************************************************/
+
+#if defined(CONFIG_CMD_RUN)
+int do_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ int i;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ for (i = 1; i < argc; ++i) {
+ char *arg;
+
+ arg = env_get(argv[i]);
+ if (arg == NULL) {
+ printf("## Error: \"%s\" not defined\n", argv[i]);
+ return 1;
+ }
+
+ if (run_command(arg, flag | CMD_FLAG_ENV) != 0)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+bool cli_process_fdt(const char **cmdp)
+{
+ /* Allow the fdt to override the boot command */
+ char *env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd");
+ if (env)
+ *cmdp = env;
+ /*
+ * If the bootsecure option was chosen, use secure_boot_cmd().
+ * Always use 'env' in this case, since bootsecure requres that the
+ * bootcmd was specified in the FDT too.
+ */
+ return fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0) != 0;
+}
+
+/*
+ * Runs the given boot command securely. Specifically:
+ * - Doesn't run the command with the shell (run_command or parse_string_outer),
+ * since that's a lot of code surface that an attacker might exploit.
+ * Because of this, we don't do any argument parsing--the secure boot command
+ * has to be a full-fledged u-boot command.
+ * - Doesn't check for keypresses before booting, since that could be a
+ * security hole; also disables Ctrl-C.
+ * - Doesn't allow the command to return.
+ *
+ * Upon any failures, this function will drop into an infinite loop after
+ * printing the error message to console.
+ */
+void cli_secure_boot_cmd(const char *cmd)
+{
+#ifdef CONFIG_CMDLINE
+ struct cmd_tbl *cmdtp;
+#endif
+ int rc;
+
+ if (!cmd) {
+ printf("## Error: Secure boot command not specified\n");
+ goto err;
+ }
+
+ /* Disable Ctrl-C just in case some command is used that checks it. */
+ disable_ctrlc(1);
+
+ /* Find the command directly. */
+#ifdef CONFIG_CMDLINE
+ cmdtp = find_cmd(cmd);
+ if (!cmdtp) {
+ printf("## Error: \"%s\" not defined\n", cmd);
+ goto err;
+ }
+
+ /* Run the command, forcing no flags and faking argc and argv. */
+ rc = (cmdtp->cmd)(cmdtp, 0, 1, (char **)&cmd);
+
+#else
+ rc = board_run_command(cmd);
+#endif
+
+ /* Shouldn't ever return from boot command. */
+ printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
+
+err:
+ /*
+ * Not a whole lot to do here. Rebooting won't help much, since we'll
+ * just end up right back here. Just loop.
+ */
+ hang();
+}
+#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
+
+void cli_loop(void)
+{
+ bootstage_mark(BOOTSTAGE_ID_ENTER_CLI_LOOP);
+#ifdef CONFIG_HUSH_PARSER
+ parse_file_outer();
+ /* This point is never reached */
+ for (;;);
+#elif defined(CONFIG_CMDLINE)
+ cli_simple_loop();
+#else
+ printf("## U-Boot command line is disabled. Please enable CONFIG_CMDLINE\n");
+#endif /*CONFIG_HUSH_PARSER*/
+}
+
+void cli_init(void)
+{
+#ifdef CONFIG_HUSH_PARSER
+ u_boot_hush_start();
+#endif
+
+#if defined(CONFIG_HUSH_INIT_VAR)
+ hush_init_var();
+#endif
+}
diff --git a/roms/u-boot/common/cli_hush.c b/roms/u-boot/common/cli_hush.c
new file mode 100644
index 000000000..1467ff81b
--- /dev/null
+++ b/roms/u-boot/common/cli_hush.c
@@ -0,0 +1,3705 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * sh.c -- a prototype Bourne shell grammar parser
+ * Intended to follow the original Thompson and Ritchie
+ * "small and simple is beautiful" philosophy, which
+ * incidentally is a good match to today's BusyBox.
+ *
+ * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
+ *
+ * Credits:
+ * The parser routines proper are all original material, first
+ * written Dec 2000 and Jan 2001 by Larry Doolittle.
+ * The execution engine, the builtins, and much of the underlying
+ * support has been adapted from busybox-0.49pre's lash,
+ * which is Copyright (C) 2000 by Lineo, Inc., and
+ * written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
+ * That, in turn, is based in part on ladsh.c, by Michael K. Johnson and
+ * Erik W. Troan, which they placed in the public domain. I don't know
+ * how much of the Johnson/Troan code has survived the repeated rewrites.
+ * Other credits:
+ * b_addchr() derived from similar w_addchar function in glibc-2.2
+ * setup_redirect(), redirect_opt_num(), and big chunks of main()
+ * and many builtins derived from contributions by Erik Andersen
+ * miscellaneous bugfixes from Matt Kraai
+ *
+ * There are two big (and related) architecture differences between
+ * this parser and the lash parser. One is that this version is
+ * actually designed from the ground up to understand nearly all
+ * of the Bourne grammar. The second, consequential change is that
+ * the parser and input reader have been turned inside out. Now,
+ * the parser is in control, and asks for input as needed. The old
+ * way had the input reader in control, and it asked for parsing to
+ * take place as needed. The new way makes it much easier to properly
+ * handle the recursion implicit in the various substitutions, especially
+ * across continuation lines.
+ *
+ * Bash grammar not implemented: (how many of these were in original sh?)
+ * $@ (those sure look like weird quoting rules)
+ * $_
+ * ! negation operator for pipes
+ * &> and >& redirection of stdout+stderr
+ * Brace Expansion
+ * Tilde Expansion
+ * fancy forms of Parameter Expansion
+ * aliases
+ * Arithmetic Expansion
+ * <(list) and >(list) Process Substitution
+ * reserved words: case, esac, select, function
+ * Here Documents ( << word )
+ * Functions
+ * Major bugs:
+ * job handling woefully incomplete and buggy
+ * reserved word execution woefully incomplete and buggy
+ * to-do:
+ * port selected bugfixes from post-0.49 busybox lash - done?
+ * finish implementing reserved words: for, while, until, do, done
+ * change { and } from special chars to reserved words
+ * builtins: break, continue, eval, return, set, trap, ulimit
+ * test magic exec
+ * handle children going into background
+ * clean up recognition of null pipes
+ * check setting of global_argc and global_argv
+ * control-C handling, probably with longjmp
+ * follow IFS rules more precisely, including update semantics
+ * figure out what to do with backslash-newline
+ * explain why we use signal instead of sigaction
+ * propagate syntax errors, die on resource errors?
+ * continuation lines, both explicit and implicit - done?
+ * memory leak finding and plugging - done?
+ * more testing, especially quoting rules and redirection
+ * document how quoting rules not precisely followed for variable assignments
+ * maybe change map[] to use 2-bit entries
+ * (eventually) remove all the printf's
+ */
+
+#define __U_BOOT__
+#ifdef __U_BOOT__
+#include <common.h> /* readline */
+#include <env.h>
+#include <malloc.h> /* malloc, free, realloc*/
+#include <linux/ctype.h> /* isalpha, isdigit */
+#include <console.h>
+#include <bootretry.h>
+#include <cli.h>
+#include <cli_hush.h>
+#include <command.h> /* find_cmd */
+#include <asm/global_data.h>
+#endif
+#ifndef __U_BOOT__
+#include <ctype.h> /* isalpha, isdigit */
+#include <unistd.h> /* getpid */
+#include <stdlib.h> /* getenv, atoi */
+#include <string.h> /* strchr */
+#include <stdio.h> /* popen etc. */
+#include <glob.h> /* glob, of course */
+#include <stdarg.h> /* va_list */
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h> /* should be pretty obvious */
+
+#include <sys/stat.h> /* ulimit */
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+/* #include <dmalloc.h> */
+
+#if 1
+#include "busybox.h"
+#include "cmdedit.h"
+#else
+#define applet_name "hush"
+#include "standalone.h"
+#define hush_main main
+#undef CONFIG_FEATURE_SH_FANCY_PROMPT
+#define BB_BANNER
+#endif
+#endif
+#define SPECIAL_VAR_SYMBOL 03
+#define SUBSTED_VAR_SYMBOL 04
+#ifndef __U_BOOT__
+#define FLAG_EXIT_FROM_LOOP 1
+#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
+#define FLAG_REPARSING (1 << 2) /* >= 2nd pass */
+
+#endif
+
+#ifdef __U_BOOT__
+DECLARE_GLOBAL_DATA_PTR;
+
+#define EXIT_SUCCESS 0
+#define EOF -1
+#define syntax() syntax_err()
+#define xstrdup strdup
+#define error_msg printf
+#else
+typedef enum {
+ REDIRECT_INPUT = 1,
+ REDIRECT_OVERWRITE = 2,
+ REDIRECT_APPEND = 3,
+ REDIRECT_HEREIS = 4,
+ REDIRECT_IO = 5
+} redir_type;
+
+/* The descrip member of this structure is only used to make debugging
+ * output pretty */
+struct {int mode; int default_fd; char *descrip;} redir_table[] = {
+ { 0, 0, "()" },
+ { O_RDONLY, 0, "<" },
+ { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
+ { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
+ { O_RDONLY, -1, "<<" },
+ { O_RDWR, 1, "<>" }
+};
+#endif
+
+typedef enum {
+ PIPE_SEQ = 1,
+ PIPE_AND = 2,
+ PIPE_OR = 3,
+ PIPE_BG = 4,
+} pipe_style;
+
+/* might eventually control execution */
+typedef enum {
+ RES_NONE = 0,
+ RES_IF = 1,
+ RES_THEN = 2,
+ RES_ELIF = 3,
+ RES_ELSE = 4,
+ RES_FI = 5,
+ RES_FOR = 6,
+ RES_WHILE = 7,
+ RES_UNTIL = 8,
+ RES_DO = 9,
+ RES_DONE = 10,
+ RES_XXXX = 11,
+ RES_IN = 12,
+ RES_SNTX = 13
+} reserved_style;
+#define FLAG_END (1<<RES_NONE)
+#define FLAG_IF (1<<RES_IF)
+#define FLAG_THEN (1<<RES_THEN)
+#define FLAG_ELIF (1<<RES_ELIF)
+#define FLAG_ELSE (1<<RES_ELSE)
+#define FLAG_FI (1<<RES_FI)
+#define FLAG_FOR (1<<RES_FOR)
+#define FLAG_WHILE (1<<RES_WHILE)
+#define FLAG_UNTIL (1<<RES_UNTIL)
+#define FLAG_DO (1<<RES_DO)
+#define FLAG_DONE (1<<RES_DONE)
+#define FLAG_IN (1<<RES_IN)
+#define FLAG_START (1<<RES_XXXX)
+
+/* This holds pointers to the various results of parsing */
+struct p_context {
+ struct child_prog *child;
+ struct pipe *list_head;
+ struct pipe *pipe;
+#ifndef __U_BOOT__
+ struct redir_struct *pending_redirect;
+#endif
+ reserved_style w;
+ int old_flag; /* for figuring out valid reserved words */
+ struct p_context *stack;
+ int type; /* define type of parser : ";$" common or special symbol */
+ /* How about quoting status? */
+};
+
+#ifndef __U_BOOT__
+struct redir_struct {
+ redir_type type; /* type of redirection */
+ int fd; /* file descriptor being redirected */
+ int dup; /* -1, or file descriptor being duplicated */
+ struct redir_struct *next; /* pointer to the next redirect in the list */
+ glob_t word; /* *word.gl_pathv is the filename */
+};
+#endif
+
+struct child_prog {
+#ifndef __U_BOOT__
+ pid_t pid; /* 0 if exited */
+#endif
+ char **argv; /* program name and arguments */
+ /* was quoted when parsed; copy of struct o_string.nonnull field */
+ int *argv_nonnull;
+#ifdef __U_BOOT__
+ int argc; /* number of program arguments */
+#endif
+ struct pipe *group; /* if non-NULL, first in group or subshell */
+#ifndef __U_BOOT__
+ int subshell; /* flag, non-zero if group must be forked */
+ struct redir_struct *redirects; /* I/O redirections */
+ glob_t glob_result; /* result of parameter globbing */
+ int is_stopped; /* is the program currently running? */
+ struct pipe *family; /* pointer back to the child's parent pipe */
+#endif
+ int sp; /* number of SPECIAL_VAR_SYMBOL */
+ int type;
+};
+
+struct pipe {
+#ifndef __U_BOOT__
+ int jobid; /* job number */
+#endif
+ int num_progs; /* total number of programs in job */
+#ifndef __U_BOOT__
+ int running_progs; /* number of programs running */
+ char *text; /* name of job */
+ char *cmdbuf; /* buffer various argv's point into */
+ pid_t pgrp; /* process group ID for the job */
+#endif
+ struct child_prog *progs; /* array of commands in pipe */
+ struct pipe *next; /* to track background commands */
+#ifndef __U_BOOT__
+ int stopped_progs; /* number of programs alive, but stopped */
+ int job_context; /* bitmask defining current context */
+#endif
+ pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
+ reserved_style r_mode; /* supports if, for, while, until */
+};
+
+#ifndef __U_BOOT__
+struct close_me {
+ int fd;
+ struct close_me *next;
+};
+#endif
+
+struct variables {
+ char *name;
+ char *value;
+ int flg_export;
+ int flg_read_only;
+ struct variables *next;
+};
+
+/* globals, connect us to the outside world
+ * the first three support $?, $#, and $1 */
+#ifndef __U_BOOT__
+char **global_argv;
+unsigned int global_argc;
+#endif
+static unsigned int last_return_code;
+#ifndef __U_BOOT__
+extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
+#endif
+
+/* "globals" within this file */
+static uchar *ifs;
+static char map[256];
+#ifndef __U_BOOT__
+static int fake_mode;
+static int interactive;
+static struct close_me *close_me_head;
+static const char *cwd;
+static struct pipe *job_list;
+static unsigned int last_bg_pid;
+static unsigned int last_jobid;
+static unsigned int shell_terminal;
+static char *PS1;
+static char *PS2;
+struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
+struct variables *top_vars = &shell_ver;
+#else
+static int flag_repeat = 0;
+static int do_repeat = 0;
+static struct variables *top_vars = NULL ;
+#endif /*__U_BOOT__ */
+
+#define B_CHUNK (100)
+#define B_NOSPAC 1
+
+typedef struct {
+ char *data;
+ int length;
+ int maxlen;
+ int quote;
+ int nonnull;
+} o_string;
+#define NULL_O_STRING {NULL,0,0,0,0}
+/* used for initialization:
+ o_string foo = NULL_O_STRING; */
+
+/* I can almost use ordinary FILE *. Is open_memstream() universally
+ * available? Where is it documented? */
+struct in_str {
+ const char *p;
+#ifndef __U_BOOT__
+ char peek_buf[2];
+#endif
+ int __promptme;
+ int promptmode;
+#ifndef __U_BOOT__
+ FILE *file;
+#endif
+ int (*get) (struct in_str *);
+ int (*peek) (struct in_str *);
+};
+#define b_getch(input) ((input)->get(input))
+#define b_peek(input) ((input)->peek(input))
+
+#ifndef __U_BOOT__
+#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
+
+struct built_in_command {
+ char *cmd; /* name */
+ char *descr; /* description */
+ int (*function) (struct child_prog *); /* function ptr */
+};
+#endif
+
+/* define DEBUG_SHELL for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG_SHELL
+#endif
+
+/* This should be in utility.c */
+#ifdef DEBUG_SHELL
+#ifndef __U_BOOT__
+static void debug_printf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+#else
+#define debug_printf(fmt,args...) printf (fmt ,##args)
+#endif
+#else
+static inline void debug_printf(const char *format, ...) { }
+#endif
+#define final_printf debug_printf
+
+#ifdef __U_BOOT__
+static void syntax_err(void) {
+ printf("syntax error\n");
+}
+#else
+static void __syntax(char *file, int line) {
+ error_msg("syntax error %s:%d", file, line);
+}
+#define syntax() __syntax(__FILE__, __LINE__)
+#endif
+
+#ifdef __U_BOOT__
+static void *xmalloc(size_t size);
+static void *xrealloc(void *ptr, size_t size);
+#else
+/* Index of subroutines: */
+/* function prototypes for builtins */
+static int builtin_cd(struct child_prog *child);
+static int builtin_env(struct child_prog *child);
+static int builtin_eval(struct child_prog *child);
+static int builtin_exec(struct child_prog *child);
+static int builtin_exit(struct child_prog *child);
+static int builtin_export(struct child_prog *child);
+static int builtin_fg_bg(struct child_prog *child);
+static int builtin_help(struct child_prog *child);
+static int builtin_jobs(struct child_prog *child);
+static int builtin_pwd(struct child_prog *child);
+static int builtin_read(struct child_prog *child);
+static int builtin_set(struct child_prog *child);
+static int builtin_shift(struct child_prog *child);
+static int builtin_source(struct child_prog *child);
+static int builtin_umask(struct child_prog *child);
+static int builtin_unset(struct child_prog *child);
+static int builtin_not_written(struct child_prog *child);
+#endif
+/* o_string manipulation: */
+static int b_check_space(o_string *o, int len);
+static int b_addchr(o_string *o, int ch);
+static void b_reset(o_string *o);
+static int b_addqchr(o_string *o, int ch, int quote);
+#ifndef __U_BOOT__
+static int b_adduint(o_string *o, unsigned int i);
+#endif
+/* in_str manipulations: */
+static int static_get(struct in_str *i);
+static int static_peek(struct in_str *i);
+static int file_get(struct in_str *i);
+static int file_peek(struct in_str *i);
+#ifndef __U_BOOT__
+static void setup_file_in_str(struct in_str *i, FILE *f);
+#else
+static void setup_file_in_str(struct in_str *i);
+#endif
+static void setup_string_in_str(struct in_str *i, const char *s);
+#ifndef __U_BOOT__
+/* close_me manipulations: */
+static void mark_open(int fd);
+static void mark_closed(int fd);
+static void close_all(void);
+#endif
+/* "run" the final data structures: */
+static char *indenter(int i);
+static int free_pipe_list(struct pipe *head, int indent);
+static int free_pipe(struct pipe *pi, int indent);
+/* really run the final data structures: */
+#ifndef __U_BOOT__
+static int setup_redirects(struct child_prog *prog, int squirrel[]);
+#endif
+static int run_list_real(struct pipe *pi);
+#ifndef __U_BOOT__
+static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn));
+#endif
+static int run_pipe_real(struct pipe *pi);
+/* extended glob support: */
+#ifndef __U_BOOT__
+static int globhack(const char *src, int flags, glob_t *pglob);
+static int glob_needed(const char *s);
+static int xglob(o_string *dest, int flags, glob_t *pglob);
+#endif
+/* variable assignment: */
+static int is_assignment(const char *s);
+/* data structure manipulation: */
+#ifndef __U_BOOT__
+static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
+#endif
+static void initialize_context(struct p_context *ctx);
+static int done_word(o_string *dest, struct p_context *ctx);
+static int done_command(struct p_context *ctx);
+static int done_pipe(struct p_context *ctx, pipe_style type);
+/* primary string parsing: */
+#ifndef __U_BOOT__
+static int redirect_dup_num(struct in_str *input);
+static int redirect_opt_num(o_string *o);
+static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
+static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
+#endif
+static char *lookup_param(char *src);
+static char *make_string(char **inp, int *nonnull);
+static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
+#ifndef __U_BOOT__
+static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
+#endif
+static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
+/* setup: */
+static int parse_stream_outer(struct in_str *inp, int flag);
+#ifndef __U_BOOT__
+static int parse_string_outer(const char *s, int flag);
+static int parse_file_outer(FILE *f);
+#endif
+#ifndef __U_BOOT__
+/* job management: */
+static int checkjobs(struct pipe* fg_pipe);
+static void insert_bg_job(struct pipe *pi);
+static void remove_bg_job(struct pipe *pi);
+#endif
+/* local variable support */
+static char **make_list_in(char **inp, char *name);
+static char *insert_var_value(char *inp);
+static char *insert_var_value_sub(char *inp, int tag_subst);
+
+#ifndef __U_BOOT__
+/* Table of built-in functions. They can be forked or not, depending on
+ * context: within pipes, they fork. As simple commands, they do not.
+ * When used in non-forking context, they can change global variables
+ * in the parent shell process. If forked, of course they can not.
+ * For example, 'unset foo | whatever' will parse and run, but foo will
+ * still be set at the end. */
+static struct built_in_command bltins[] = {
+ {"bg", "Resume a job in the background", builtin_fg_bg},
+ {"break", "Exit for, while or until loop", builtin_not_written},
+ {"cd", "Change working directory", builtin_cd},
+ {"continue", "Continue for, while or until loop", builtin_not_written},
+ {"env", "Print all environment variables", builtin_env},
+ {"eval", "Construct and run shell command", builtin_eval},
+ {"exec", "Exec command, replacing this shell with the exec'd process",
+ builtin_exec},
+ {"exit", "Exit from shell()", builtin_exit},
+ {"export", "Set environment variable", builtin_export},
+ {"fg", "Bring job into the foreground", builtin_fg_bg},
+ {"jobs", "Lists the active jobs", builtin_jobs},
+ {"pwd", "Print current directory", builtin_pwd},
+ {"read", "Input environment variable", builtin_read},
+ {"return", "Return from a function", builtin_not_written},
+ {"set", "Set/unset shell local variables", builtin_set},
+ {"shift", "Shift positional parameters", builtin_shift},
+ {"trap", "Trap signals", builtin_not_written},
+ {"ulimit","Controls resource limits", builtin_not_written},
+ {"umask","Sets file creation mask", builtin_umask},
+ {"unset", "Unset environment variable", builtin_unset},
+ {".", "Source-in and run commands in a file", builtin_source},
+ {"help", "List shell built-in commands", builtin_help},
+ {NULL, NULL, NULL}
+};
+
+static const char *set_cwd(void)
+{
+ if(cwd==unknown)
+ cwd = NULL; /* xgetcwd(arg) called free(arg) */
+ cwd = xgetcwd((char *)cwd);
+ if (!cwd)
+ cwd = unknown;
+ return cwd;
+}
+
+/* built-in 'eval' handler */
+static int builtin_eval(struct child_prog *child)
+{
+ char *str = NULL;
+ int rcode = EXIT_SUCCESS;
+
+ if (child->argv[1]) {
+ str = make_string(child->argv + 1);
+ parse_string_outer(str, FLAG_EXIT_FROM_LOOP |
+ FLAG_PARSE_SEMICOLON);
+ free(str);
+ rcode = last_return_code;
+ }
+ return rcode;
+}
+
+/* built-in 'cd <path>' handler */
+static int builtin_cd(struct child_prog *child)
+{
+ char *newdir;
+ if (child->argv[1] == NULL)
+ newdir = env_get("HOME");
+ else
+ newdir = child->argv[1];
+ if (chdir(newdir)) {
+ printf("cd: %s: %s\n", newdir, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ set_cwd();
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'env' handler */
+static int builtin_env(struct child_prog *dummy)
+{
+ char **e = environ;
+ if (e == NULL) return EXIT_FAILURE;
+ for (; *e; e++) {
+ puts(*e);
+ }
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'exec' handler */
+static int builtin_exec(struct child_prog *child)
+{
+ if (child->argv[1] == NULL)
+ return EXIT_SUCCESS; /* Really? */
+ child->argv++;
+ pseudo_exec(child);
+ /* never returns */
+}
+
+/* built-in 'exit' handler */
+static int builtin_exit(struct child_prog *child)
+{
+ if (child->argv[1] == NULL)
+ exit(last_return_code);
+ exit (atoi(child->argv[1]));
+}
+
+/* built-in 'export VAR=value' handler */
+static int builtin_export(struct child_prog *child)
+{
+ int res = 0;
+ char *name = child->argv[1];
+
+ if (name == NULL) {
+ return (builtin_env(child));
+ }
+
+ name = strdup(name);
+
+ if(name) {
+ char *value = strchr(name, '=');
+
+ if (!value) {
+ char *tmp;
+ /* They are exporting something without an =VALUE */
+
+ value = get_local_var(name);
+ if (value) {
+ size_t ln = strlen(name);
+
+ tmp = realloc(name, ln+strlen(value)+2);
+ if(tmp==NULL)
+ res = -1;
+ else {
+ sprintf(tmp+ln, "=%s", value);
+ name = tmp;
+ }
+ } else {
+ /* bash does not return an error when trying to export
+ * an undefined variable. Do likewise. */
+ res = 1;
+ }
+ }
+ }
+ if (res<0)
+ perror_msg("export");
+ else if(res==0)
+ res = set_local_var(name, 1);
+ else
+ res = 0;
+ free(name);
+ return res;
+}
+
+/* built-in 'fg' and 'bg' handler */
+static int builtin_fg_bg(struct child_prog *child)
+{
+ int i, jobnum;
+ struct pipe *pi=NULL;
+
+ if (!interactive)
+ return EXIT_FAILURE;
+ /* If they gave us no args, assume they want the last backgrounded task */
+ if (!child->argv[1]) {
+ for (pi = job_list; pi; pi = pi->next) {
+ if (pi->jobid == last_jobid) {
+ break;
+ }
+ }
+ if (!pi) {
+ error_msg("%s: no current job", child->argv[0]);
+ return EXIT_FAILURE;
+ }
+ } else {
+ if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
+ error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
+ return EXIT_FAILURE;
+ }
+ for (pi = job_list; pi; pi = pi->next) {
+ if (pi->jobid == jobnum) {
+ break;
+ }
+ }
+ if (!pi) {
+ error_msg("%s: %d: no such job", child->argv[0], jobnum);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (*child->argv[0] == 'f') {
+ /* Put the job into the foreground. */
+ tcsetpgrp(shell_terminal, pi->pgrp);
+ }
+
+ /* Restart the processes in the job */
+ for (i = 0; i < pi->num_progs; i++)
+ pi->progs[i].is_stopped = 0;
+
+ if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) {
+ if (i == ESRCH) {
+ remove_bg_job(pi);
+ } else {
+ perror_msg("kill (SIGCONT)");
+ }
+ }
+
+ pi->stopped_progs = 0;
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'help' handler */
+static int builtin_help(struct child_prog *dummy)
+{
+ struct built_in_command *x;
+
+ printf("\nBuilt-in commands:\n");
+ printf("-------------------\n");
+ for (x = bltins; x->cmd; x++) {
+ if (x->descr==NULL)
+ continue;
+ printf("%s\t%s\n", x->cmd, x->descr);
+ }
+ printf("\n\n");
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'jobs' handler */
+static int builtin_jobs(struct child_prog *child)
+{
+ struct pipe *job;
+ char *status_string;
+
+ for (job = job_list; job; job = job->next) {
+ if (job->running_progs == job->stopped_progs)
+ status_string = "Stopped";
+ else
+ status_string = "Running";
+
+ printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
+ }
+ return EXIT_SUCCESS;
+}
+
+
+/* built-in 'pwd' handler */
+static int builtin_pwd(struct child_prog *dummy)
+{
+ puts(set_cwd());
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'read VAR' handler */
+static int builtin_read(struct child_prog *child)
+{
+ int res;
+
+ if (child->argv[1]) {
+ char string[BUFSIZ];
+ char *var = 0;
+
+ string[0] = 0; /* In case stdin has only EOF */
+ /* read string */
+ fgets(string, sizeof(string), stdin);
+ chomp(string);
+ var = malloc(strlen(child->argv[1])+strlen(string)+2);
+ if(var) {
+ sprintf(var, "%s=%s", child->argv[1], string);
+ res = set_local_var(var, 0);
+ } else
+ res = -1;
+ if (res)
+ fprintf(stderr, "read: %m\n");
+ free(var); /* So not move up to avoid breaking errno */
+ return res;
+ } else {
+ do res=getchar(); while(res!='\n' && res!=EOF);
+ return 0;
+ }
+}
+
+/* built-in 'set VAR=value' handler */
+static int builtin_set(struct child_prog *child)
+{
+ char *temp = child->argv[1];
+ struct variables *e;
+
+ if (temp == NULL)
+ for(e = top_vars; e; e=e->next)
+ printf("%s=%s\n", e->name, e->value);
+ else
+ set_local_var(temp, 0);
+
+ return EXIT_SUCCESS;
+}
+
+
+/* Built-in 'shift' handler */
+static int builtin_shift(struct child_prog *child)
+{
+ int n=1;
+ if (child->argv[1]) {
+ n=atoi(child->argv[1]);
+ }
+ if (n>=0 && n<global_argc) {
+ /* XXX This probably breaks $0 */
+ global_argc -= n;
+ global_argv += n;
+ return EXIT_SUCCESS;
+ } else {
+ return EXIT_FAILURE;
+ }
+}
+
+/* Built-in '.' handler (read-in and execute commands from file) */
+static int builtin_source(struct child_prog *child)
+{
+ FILE *input;
+ int status;
+
+ if (child->argv[1] == NULL)
+ return EXIT_FAILURE;
+
+ /* XXX search through $PATH is missing */
+ input = fopen(child->argv[1], "r");
+ if (!input) {
+ error_msg("Couldn't open file '%s'", child->argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ /* Now run the file */
+ /* XXX argv and argc are broken; need to save old global_argv
+ * (pointer only is OK!) on this stack frame,
+ * set global_argv=child->argv+1, recurse, and restore. */
+ mark_open(fileno(input));
+ status = parse_file_outer(input);
+ mark_closed(fileno(input));
+ fclose(input);
+ return (status);
+}
+
+static int builtin_umask(struct child_prog *child)
+{
+ mode_t new_umask;
+ const char *arg = child->argv[1];
+ char *end;
+ if (arg) {
+ new_umask=strtoul(arg, &end, 8);
+ if (*end!='\0' || end == arg) {
+ return EXIT_FAILURE;
+ }
+ } else {
+ printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
+ }
+ umask(new_umask);
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'unset VAR' handler */
+static int builtin_unset(struct child_prog *child)
+{
+ /* bash returned already true */
+ unset_local_var(child->argv[1]);
+ return EXIT_SUCCESS;
+}
+
+static int builtin_not_written(struct child_prog *child)
+{
+ printf("builtin_%s not written\n",child->argv[0]);
+ return EXIT_FAILURE;
+}
+#endif
+
+static int b_check_space(o_string *o, int len)
+{
+ /* It would be easy to drop a more restrictive policy
+ * in here, such as setting a maximum string length */
+ if (o->length + len > o->maxlen) {
+ char *old_data = o->data;
+ /* assert (data == NULL || o->maxlen != 0); */
+ o->maxlen += max(2*len, B_CHUNK);
+ o->data = realloc(o->data, 1 + o->maxlen);
+ if (o->data == NULL) {
+ free(old_data);
+ }
+ }
+ return o->data == NULL;
+}
+
+static int b_addchr(o_string *o, int ch)
+{
+ debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
+ if (b_check_space(o, 1)) return B_NOSPAC;
+ o->data[o->length] = ch;
+ o->length++;
+ o->data[o->length] = '\0';
+ return 0;
+}
+
+static void b_reset(o_string *o)
+{
+ o->length = 0;
+ o->nonnull = 0;
+ if (o->data != NULL) *o->data = '\0';
+}
+
+static void b_free(o_string *o)
+{
+ b_reset(o);
+ free(o->data);
+ o->data = NULL;
+ o->maxlen = 0;
+}
+
+/* My analysis of quoting semantics tells me that state information
+ * is associated with a destination, not a source.
+ */
+static int b_addqchr(o_string *o, int ch, int quote)
+{
+ if (quote && strchr("*?[\\",ch)) {
+ int rc;
+ rc = b_addchr(o, '\\');
+ if (rc) return rc;
+ }
+ return b_addchr(o, ch);
+}
+
+#ifndef __U_BOOT__
+static int b_adduint(o_string *o, unsigned int i)
+{
+ int r;
+ char *p = simple_itoa(i);
+ /* no escape checking necessary */
+ do r=b_addchr(o, *p++); while (r==0 && *p);
+ return r;
+}
+#endif
+
+static int static_get(struct in_str *i)
+{
+ int ch = *i->p++;
+ if (ch=='\0') return EOF;
+ return ch;
+}
+
+static int static_peek(struct in_str *i)
+{
+ return *i->p;
+}
+
+#ifndef __U_BOOT__
+static inline void cmdedit_set_initial_prompt(void)
+{
+#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
+ PS1 = NULL;
+#else
+ PS1 = env_get("PS1");
+ if(PS1==0)
+ PS1 = "\\w \\$ ";
+#endif
+}
+
+static inline void setup_prompt_string(int promptmode, char **prompt_str)
+{
+ debug_printf("setup_prompt_string %d ",promptmode);
+#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
+ /* Set up the prompt */
+ if (promptmode == 1) {
+ free(PS1);
+ PS1=xmalloc(strlen(cwd)+4);
+ sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# ");
+ *prompt_str = PS1;
+ } else {
+ *prompt_str = PS2;
+ }
+#else
+ *prompt_str = (promptmode==1)? PS1 : PS2;
+#endif
+ debug_printf("result %s\n",*prompt_str);
+}
+#endif
+
+#ifdef __U_BOOT__
+static int uboot_cli_readline(struct in_str *i)
+{
+ char *prompt;
+ char __maybe_unused *ps_prompt = NULL;
+
+ if (i->promptmode == 1)
+ prompt = CONFIG_SYS_PROMPT;
+ else
+ prompt = CONFIG_SYS_PROMPT_HUSH_PS2;
+
+#ifdef CONFIG_CMDLINE_PS_SUPPORT
+ if (i->promptmode == 1)
+ ps_prompt = env_get("PS1");
+ else
+ ps_prompt = env_get("PS2");
+ if (ps_prompt)
+ prompt = ps_prompt;
+#endif
+
+ return cli_readline(prompt);
+}
+#endif
+
+static void get_user_input(struct in_str *i)
+{
+#ifndef __U_BOOT__
+ char *prompt_str;
+ static char the_command[BUFSIZ];
+
+ setup_prompt_string(i->promptmode, &prompt_str);
+#ifdef CONFIG_FEATURE_COMMAND_EDITING
+ /*
+ ** enable command line editing only while a command line
+ ** is actually being read; otherwise, we'll end up bequeathing
+ ** atexit() handlers and other unwanted stuff to our
+ ** child processes (rob@sysgo.de)
+ */
+ cmdedit_read_input(prompt_str, the_command);
+#else
+ fputs(prompt_str, stdout);
+ fflush(stdout);
+ the_command[0]=fgetc(i->file);
+ the_command[1]='\0';
+#endif
+ fflush(stdout);
+ i->p = the_command;
+#else
+ int n;
+ static char the_command[CONFIG_SYS_CBSIZE + 1];
+
+ bootretry_reset_cmd_timeout();
+ i->__promptme = 1;
+ n = uboot_cli_readline(i);
+
+#ifdef CONFIG_BOOT_RETRY_TIME
+ if (n == -2) {
+ puts("\nTimeout waiting for command\n");
+# ifdef CONFIG_RESET_TO_RETRY
+ do_reset(NULL, 0, 0, NULL);
+# else
+# error "This currently only works with CONFIG_RESET_TO_RETRY enabled"
+# endif
+ }
+#endif
+ if (n == -1 ) {
+ flag_repeat = 0;
+ i->__promptme = 0;
+ }
+ n = strlen(console_buffer);
+ console_buffer[n] = '\n';
+ console_buffer[n+1]= '\0';
+ if (had_ctrlc()) flag_repeat = 0;
+ clear_ctrlc();
+ do_repeat = 0;
+ if (i->promptmode == 1) {
+ if (console_buffer[0] == '\n'&& flag_repeat == 0) {
+ strcpy(the_command,console_buffer);
+ }
+ else {
+ if (console_buffer[0] != '\n') {
+ strcpy(the_command,console_buffer);
+ flag_repeat = 1;
+ }
+ else {
+ do_repeat = 1;
+ }
+ }
+ i->p = the_command;
+ }
+ else {
+ if (console_buffer[0] != '\n') {
+ if (strlen(the_command) + strlen(console_buffer)
+ < CONFIG_SYS_CBSIZE) {
+ n = strlen(the_command);
+ the_command[n-1] = ' ';
+ strcpy(&the_command[n],console_buffer);
+ }
+ else {
+ the_command[0] = '\n';
+ the_command[1] = '\0';
+ flag_repeat = 0;
+ }
+ }
+ if (i->__promptme == 0) {
+ the_command[0] = '\n';
+ the_command[1] = '\0';
+ }
+ i->p = console_buffer;
+ }
+#endif
+}
+
+/* This is the magic location that prints prompts
+ * and gets data back from the user */
+static int file_get(struct in_str *i)
+{
+ int ch;
+
+ ch = 0;
+ /* If there is data waiting, eat it up */
+ if (i->p && *i->p) {
+ ch = *i->p++;
+ } else {
+ /* need to double check i->file because we might be doing something
+ * more complicated by now, like sourcing or substituting. */
+#ifndef __U_BOOT__
+ if (i->__promptme && interactive && i->file == stdin) {
+ while(! i->p || (interactive && strlen(i->p)==0) ) {
+#else
+ while(! i->p || strlen(i->p)==0 ) {
+#endif
+ get_user_input(i);
+ }
+ i->promptmode=2;
+#ifndef __U_BOOT__
+ i->__promptme = 0;
+#endif
+ if (i->p && *i->p) {
+ ch = *i->p++;
+ }
+#ifndef __U_BOOT__
+ } else {
+ ch = fgetc(i->file);
+ }
+
+#endif
+ debug_printf("b_getch: got a %d\n", ch);
+ }
+#ifndef __U_BOOT__
+ if (ch == '\n') i->__promptme=1;
+#endif
+ return ch;
+}
+
+/* All the callers guarantee this routine will never be
+ * used right after a newline, so prompting is not needed.
+ */
+static int file_peek(struct in_str *i)
+{
+#ifndef __U_BOOT__
+ if (i->p && *i->p) {
+#endif
+ return *i->p;
+#ifndef __U_BOOT__
+ } else {
+ i->peek_buf[0] = fgetc(i->file);
+ i->peek_buf[1] = '\0';
+ i->p = i->peek_buf;
+ debug_printf("b_peek: got a %d\n", *i->p);
+ return *i->p;
+ }
+#endif
+}
+
+#ifndef __U_BOOT__
+static void setup_file_in_str(struct in_str *i, FILE *f)
+#else
+static void setup_file_in_str(struct in_str *i)
+#endif
+{
+ i->peek = file_peek;
+ i->get = file_get;
+ i->__promptme=1;
+ i->promptmode=1;
+#ifndef __U_BOOT__
+ i->file = f;
+#endif
+ i->p = NULL;
+}
+
+static void setup_string_in_str(struct in_str *i, const char *s)
+{
+ i->peek = static_peek;
+ i->get = static_get;
+ i->__promptme=1;
+ i->promptmode=1;
+ i->p = s;
+}
+
+#ifndef __U_BOOT__
+static void mark_open(int fd)
+{
+ struct close_me *new = xmalloc(sizeof(struct close_me));
+ new->fd = fd;
+ new->next = close_me_head;
+ close_me_head = new;
+}
+
+static void mark_closed(int fd)
+{
+ struct close_me *tmp;
+ if (close_me_head == NULL || close_me_head->fd != fd)
+ error_msg_and_die("corrupt close_me");
+ tmp = close_me_head;
+ close_me_head = close_me_head->next;
+ free(tmp);
+}
+
+static void close_all(void)
+{
+ struct close_me *c;
+ for (c=close_me_head; c; c=c->next) {
+ close(c->fd);
+ }
+ close_me_head = NULL;
+}
+
+/* squirrel != NULL means we squirrel away copies of stdin, stdout,
+ * and stderr if they are redirected. */
+static int setup_redirects(struct child_prog *prog, int squirrel[])
+{
+ int openfd, mode;
+ struct redir_struct *redir;
+
+ for (redir=prog->redirects; redir; redir=redir->next) {
+ if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
+ /* something went wrong in the parse. Pretend it didn't happen */
+ continue;
+ }
+ if (redir->dup == -1) {
+ mode=redir_table[redir->type].mode;
+ openfd = open(redir->word.gl_pathv[0], mode, 0666);
+ if (openfd < 0) {
+ /* this could get lost if stderr has been redirected, but
+ bash and ash both lose it as well (though zsh doesn't!) */
+ perror_msg("error opening %s", redir->word.gl_pathv[0]);
+ return 1;
+ }
+ } else {
+ openfd = redir->dup;
+ }
+
+ if (openfd != redir->fd) {
+ if (squirrel && redir->fd < 3) {
+ squirrel[redir->fd] = dup(redir->fd);
+ }
+ if (openfd == -3) {
+ close(openfd);
+ } else {
+ dup2(openfd, redir->fd);
+ if (redir->dup == -1)
+ close (openfd);
+ }
+ }
+ }
+ return 0;
+}
+
+static void restore_redirects(int squirrel[])
+{
+ int i, fd;
+ for (i=0; i<3; i++) {
+ fd = squirrel[i];
+ if (fd != -1) {
+ /* No error checking. I sure wouldn't know what
+ * to do with an error if I found one! */
+ dup2(fd, i);
+ close(fd);
+ }
+ }
+}
+
+/* never returns */
+/* XXX no exit() here. If you don't exec, use _exit instead.
+ * The at_exit handlers apparently confuse the calling process,
+ * in particular stdin handling. Not sure why? */
+static void pseudo_exec(struct child_prog *child)
+{
+ int i, rcode;
+ char *p;
+ struct built_in_command *x;
+ if (child->argv) {
+ for (i=0; is_assignment(child->argv[i]); i++) {
+ debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
+ p = insert_var_value(child->argv[i]);
+ putenv(strdup(p));
+ if (p != child->argv[i]) free(p);
+ }
+ child->argv+=i; /* XXX this hack isn't so horrible, since we are about
+ to exit, and therefore don't need to keep data
+ structures consistent for free() use. */
+ /* If a variable is assigned in a forest, and nobody listens,
+ * was it ever really set?
+ */
+ if (child->argv[0] == NULL) {
+ _exit(EXIT_SUCCESS);
+ }
+
+ /*
+ * Check if the command matches any of the builtins.
+ * Depending on context, this might be redundant. But it's
+ * easier to waste a few CPU cycles than it is to figure out
+ * if this is one of those cases.
+ */
+ for (x = bltins; x->cmd; x++) {
+ if (strcmp(child->argv[0], x->cmd) == 0 ) {
+ debug_printf("builtin exec %s\n", child->argv[0]);
+ rcode = x->function(child);
+ fflush(stdout);
+ _exit(rcode);
+ }
+ }
+
+ /* Check if the command matches any busybox internal commands
+ * ("applets") here.
+ * FIXME: This feature is not 100% safe, since
+ * BusyBox is not fully reentrant, so we have no guarantee the things
+ * from the .bss are still zeroed, or that things from .data are still
+ * at their defaults. We could exec ourself from /proc/self/exe, but I
+ * really dislike relying on /proc for things. We could exec ourself
+ * from global_argv[0], but if we are in a chroot, we may not be able
+ * to find ourself... */
+#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
+ {
+ int argc_l;
+ char** argv_l=child->argv;
+ char *name = child->argv[0];
+
+#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
+ /* Following discussions from November 2000 on the busybox mailing
+ * list, the default configuration, (without
+ * get_last_path_component()) lets the user force use of an
+ * external command by specifying the full (with slashes) filename.
+ * If you enable CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN then applets
+ * _aways_ override external commands, so if you want to run
+ * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the
+ * filesystem and is _not_ busybox. Some systems may want this,
+ * most do not. */
+ name = get_last_path_component(name);
+#endif
+ /* Count argc for use in a second... */
+ for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
+ optind = 1;
+ debug_printf("running applet %s\n", name);
+ run_applet_by_name(name, argc_l, child->argv);
+ }
+#endif
+ debug_printf("exec of %s\n",child->argv[0]);
+ execvp(child->argv[0],child->argv);
+ perror_msg("couldn't exec: %s",child->argv[0]);
+ _exit(1);
+ } else if (child->group) {
+ debug_printf("runtime nesting to group\n");
+ interactive=0; /* crucial!!!! */
+ rcode = run_list_real(child->group);
+ /* OK to leak memory by not calling free_pipe_list,
+ * since this process is about to exit */
+ _exit(rcode);
+ } else {
+ /* Can happen. See what bash does with ">foo" by itself. */
+ debug_printf("trying to pseudo_exec null command\n");
+ _exit(EXIT_SUCCESS);
+ }
+}
+
+static void insert_bg_job(struct pipe *pi)
+{
+ struct pipe *thejob;
+
+ /* Linear search for the ID of the job to use */
+ pi->jobid = 1;
+ for (thejob = job_list; thejob; thejob = thejob->next)
+ if (thejob->jobid >= pi->jobid)
+ pi->jobid = thejob->jobid + 1;
+
+ /* add thejob to the list of running jobs */
+ if (!job_list) {
+ thejob = job_list = xmalloc(sizeof(*thejob));
+ } else {
+ for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
+ thejob->next = xmalloc(sizeof(*thejob));
+ thejob = thejob->next;
+ }
+
+ /* physically copy the struct job */
+ memcpy(thejob, pi, sizeof(struct pipe));
+ thejob->next = NULL;
+ thejob->running_progs = thejob->num_progs;
+ thejob->stopped_progs = 0;
+ thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
+
+ /*if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) */
+ {
+ char *bar=thejob->text;
+ char **foo=pi->progs[0].argv;
+ while(foo && *foo) {
+ bar += sprintf(bar, "%s ", *foo++);
+ }
+ }
+
+ /* we don't wait for background thejobs to return -- append it
+ to the list of backgrounded thejobs and leave it alone */
+ printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
+ last_bg_pid = thejob->progs[0].pid;
+ last_jobid = thejob->jobid;
+}
+
+/* remove a backgrounded job */
+static void remove_bg_job(struct pipe *pi)
+{
+ struct pipe *prev_pipe;
+
+ if (pi == job_list) {
+ job_list = pi->next;
+ } else {
+ prev_pipe = job_list;
+ while (prev_pipe->next != pi)
+ prev_pipe = prev_pipe->next;
+ prev_pipe->next = pi->next;
+ }
+ if (job_list)
+ last_jobid = job_list->jobid;
+ else
+ last_jobid = 0;
+
+ pi->stopped_progs = 0;
+ free_pipe(pi, 0);
+ free(pi);
+}
+
+/* Checks to see if any processes have exited -- if they
+ have, figure out why and see if a job has completed */
+static int checkjobs(struct pipe* fg_pipe)
+{
+ int attributes;
+ int status;
+ int prognum = 0;
+ struct pipe *pi;
+ pid_t childpid;
+
+ attributes = WUNTRACED;
+ if (fg_pipe==NULL) {
+ attributes |= WNOHANG;
+ }
+
+ while ((childpid = waitpid(-1, &status, attributes)) > 0) {
+ if (fg_pipe) {
+ int i, rcode = 0;
+ for (i=0; i < fg_pipe->num_progs; i++) {
+ if (fg_pipe->progs[i].pid == childpid) {
+ if (i==fg_pipe->num_progs-1)
+ rcode=WEXITSTATUS(status);
+ (fg_pipe->num_progs)--;
+ return(rcode);
+ }
+ }
+ }
+
+ for (pi = job_list; pi; pi = pi->next) {
+ prognum = 0;
+ while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
+ prognum++;
+ }
+ if (prognum < pi->num_progs)
+ break;
+ }
+
+ if(pi==NULL) {
+ debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
+ continue;
+ }
+
+ if (WIFEXITED(status) || WIFSIGNALED(status)) {
+ /* child exited */
+ pi->running_progs--;
+ pi->progs[prognum].pid = 0;
+
+ if (!pi->running_progs) {
+ printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
+ remove_bg_job(pi);
+ }
+ } else {
+ /* child stopped */
+ pi->stopped_progs++;
+ pi->progs[prognum].is_stopped = 1;
+
+#if 0
+ /* Printing this stuff is a pain, since it tends to
+ * overwrite the prompt an inconveinient moments. So
+ * don't do that. */
+ if (pi->stopped_progs == pi->num_progs) {
+ printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
+ }
+#endif
+ }
+ }
+
+ if (childpid == -1 && errno != ECHILD)
+ perror_msg("waitpid");
+
+ /* move the shell to the foreground */
+ /*if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) */
+ /* perror_msg("tcsetpgrp-2"); */
+ return -1;
+}
+
+/* Figure out our controlling tty, checking in order stderr,
+ * stdin, and stdout. If check_pgrp is set, also check that
+ * we belong to the foreground process group associated with
+ * that tty. The value of shell_terminal is needed in order to call
+ * tcsetpgrp(shell_terminal, ...); */
+void controlling_tty(int check_pgrp)
+{
+ pid_t curpgrp;
+
+ if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0
+ && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0
+ && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0)
+ goto shell_terminal_error;
+
+ if (check_pgrp && curpgrp != getpgid(0))
+ goto shell_terminal_error;
+
+ return;
+
+shell_terminal_error:
+ shell_terminal = -1;
+ return;
+}
+#endif
+
+/* run_pipe_real() starts all the jobs, but doesn't wait for anything
+ * to finish. See checkjobs().
+ *
+ * return code is normally -1, when the caller has to wait for children
+ * to finish to determine the exit status of the pipe. If the pipe
+ * is a simple builtin command, however, the action is done by the
+ * time run_pipe_real returns, and the exit code is provided as the
+ * return value.
+ *
+ * The input of the pipe is always stdin, the output is always
+ * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
+ * because it tries to avoid running the command substitution in
+ * subshell, when that is in fact necessary. The subshell process
+ * now has its stdout directed to the input of the appropriate pipe,
+ * so this routine is noticeably simpler.
+ */
+static int run_pipe_real(struct pipe *pi)
+{
+ int i;
+#ifndef __U_BOOT__
+ int nextin, nextout;
+ int pipefds[2]; /* pipefds[0] is for reading */
+ struct child_prog *child;
+ struct built_in_command *x;
+ char *p;
+# if __GNUC__
+ /* Avoid longjmp clobbering */
+ (void) &i;
+ (void) &nextin;
+ (void) &nextout;
+ (void) &child;
+# endif
+#else
+ int nextin;
+ int flag = do_repeat ? CMD_FLAG_REPEAT : 0;
+ struct child_prog *child;
+ char *p;
+# if __GNUC__
+ /* Avoid longjmp clobbering */
+ (void) &i;
+ (void) &nextin;
+ (void) &child;
+# endif
+#endif /* __U_BOOT__ */
+
+ nextin = 0;
+#ifndef __U_BOOT__
+ pi->pgrp = -1;
+#endif
+
+ /* Check if this is a simple builtin (not part of a pipe).
+ * Builtins within pipes have to fork anyway, and are handled in
+ * pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
+ */
+ if (pi->num_progs == 1) child = & (pi->progs[0]);
+#ifndef __U_BOOT__
+ if (pi->num_progs == 1 && child->group && child->subshell == 0) {
+ int squirrel[] = {-1, -1, -1};
+ int rcode;
+ debug_printf("non-subshell grouping\n");
+ setup_redirects(child, squirrel);
+ /* XXX could we merge code with following builtin case,
+ * by creating a pseudo builtin that calls run_list_real? */
+ rcode = run_list_real(child->group);
+ restore_redirects(squirrel);
+#else
+ if (pi->num_progs == 1 && child->group) {
+ int rcode;
+ debug_printf("non-subshell grouping\n");
+ rcode = run_list_real(child->group);
+#endif
+ return rcode;
+ } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
+ for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
+ if (i!=0 && child->argv[i]==NULL) {
+ /* assignments, but no command: set the local environment */
+ for (i=0; child->argv[i]!=NULL; i++) {
+
+ /* Ok, this case is tricky. We have to decide if this is a
+ * local variable, or an already exported variable. If it is
+ * already exported, we have to export the new value. If it is
+ * not exported, we need only set this as a local variable.
+ * This junk is all to decide whether or not to export this
+ * variable. */
+ int export_me=0;
+ char *name, *value;
+ name = xstrdup(child->argv[i]);
+ debug_printf("Local environment set: %s\n", name);
+ value = strchr(name, '=');
+ if (value)
+ *value=0;
+#ifndef __U_BOOT__
+ if ( get_local_var(name)) {
+ export_me=1;
+ }
+#endif
+ free(name);
+ p = insert_var_value(child->argv[i]);
+ set_local_var(p, export_me);
+ if (p != child->argv[i]) free(p);
+ }
+ return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
+ }
+ for (i = 0; is_assignment(child->argv[i]); i++) {
+ p = insert_var_value(child->argv[i]);
+#ifndef __U_BOOT__
+ putenv(strdup(p));
+#else
+ set_local_var(p, 0);
+#endif
+ if (p != child->argv[i]) {
+ child->sp--;
+ free(p);
+ }
+ }
+ if (child->sp) {
+ char * str = NULL;
+
+ str = make_string(child->argv + i,
+ child->argv_nonnull + i);
+ parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
+ free(str);
+ return last_return_code;
+ }
+#ifndef __U_BOOT__
+ for (x = bltins; x->cmd; x++) {
+ if (strcmp(child->argv[i], x->cmd) == 0 ) {
+ int squirrel[] = {-1, -1, -1};
+ int rcode;
+ if (x->function == builtin_exec && child->argv[i+1]==NULL) {
+ debug_printf("magic exec\n");
+ setup_redirects(child,NULL);
+ return EXIT_SUCCESS;
+ }
+ debug_printf("builtin inline %s\n", child->argv[0]);
+ /* XXX setup_redirects acts on file descriptors, not FILEs.
+ * This is perfect for work that comes after exec().
+ * Is it really safe for inline use? Experimentally,
+ * things seem to work with glibc. */
+ setup_redirects(child, squirrel);
+
+ child->argv += i; /* XXX horrible hack */
+ rcode = x->function(child);
+ /* XXX restore hack so free() can work right */
+ child->argv -= i;
+ restore_redirects(squirrel);
+ }
+ return rcode;
+ }
+#else
+ /* check ";", because ,example , argv consist from
+ * "help;flinfo" must not execute
+ */
+ if (strchr(child->argv[i], ';')) {
+ printf("Unknown command '%s' - try 'help' or use "
+ "'run' command\n", child->argv[i]);
+ return -1;
+ }
+ /* Process the command */
+ return cmd_process(flag, child->argc - i, child->argv + i,
+ &flag_repeat, NULL);
+#endif
+ }
+#ifndef __U_BOOT__
+
+ for (i = 0; i < pi->num_progs; i++) {
+ child = & (pi->progs[i]);
+
+ /* pipes are inserted between pairs of commands */
+ if ((i + 1) < pi->num_progs) {
+ if (pipe(pipefds)<0) perror_msg_and_die("pipe");
+ nextout = pipefds[1];
+ } else {
+ nextout=1;
+ pipefds[0] = -1;
+ }
+
+ /* XXX test for failed fork()? */
+ if (!(child->pid = fork())) {
+ /* Set the handling for job control signals back to the default. */
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGTSTP, SIG_DFL);
+ signal(SIGTTIN, SIG_DFL);
+ signal(SIGTTOU, SIG_DFL);
+ signal(SIGCHLD, SIG_DFL);
+
+ close_all();
+
+ if (nextin != 0) {
+ dup2(nextin, 0);
+ close(nextin);
+ }
+ if (nextout != 1) {
+ dup2(nextout, 1);
+ close(nextout);
+ }
+ if (pipefds[0]!=-1) {
+ close(pipefds[0]); /* opposite end of our output pipe */
+ }
+
+ /* Like bash, explicit redirects override pipes,
+ * and the pipe fd is available for dup'ing. */
+ setup_redirects(child,NULL);
+
+ if (interactive && pi->followup!=PIPE_BG) {
+ /* If we (the child) win the race, put ourselves in the process
+ * group whose leader is the first process in this pipe. */
+ if (pi->pgrp < 0) {
+ pi->pgrp = getpid();
+ }
+ if (setpgid(0, pi->pgrp) == 0) {
+ tcsetpgrp(2, pi->pgrp);
+ }
+ }
+
+ pseudo_exec(child);
+ }
+
+
+ /* put our child in the process group whose leader is the
+ first process in this pipe */
+ if (pi->pgrp < 0) {
+ pi->pgrp = child->pid;
+ }
+ /* Don't check for errors. The child may be dead already,
+ * in which case setpgid returns error code EACCES. */
+ setpgid(child->pid, pi->pgrp);
+
+ if (nextin != 0)
+ close(nextin);
+ if (nextout != 1)
+ close(nextout);
+
+ /* If there isn't another process, nextin is garbage
+ but it doesn't matter */
+ nextin = pipefds[0];
+ }
+#endif
+ return -1;
+}
+
+static int run_list_real(struct pipe *pi)
+{
+ char *save_name = NULL;
+ char **list = NULL;
+ char **save_list = NULL;
+ struct pipe *rpipe;
+ int flag_rep = 0;
+#ifndef __U_BOOT__
+ int save_num_progs;
+#endif
+ int rcode=0, flag_skip=1;
+ int flag_restore = 0;
+ int if_code=0, next_if_code=0; /* need double-buffer to handle elif */
+ reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
+ /* check syntax for "for" */
+ for (rpipe = pi; rpipe; rpipe = rpipe->next) {
+ if ((rpipe->r_mode == RES_IN ||
+ rpipe->r_mode == RES_FOR) &&
+ (rpipe->next == NULL)) {
+ syntax();
+#ifdef __U_BOOT__
+ flag_repeat = 0;
+#endif
+ return 1;
+ }
+ if ((rpipe->r_mode == RES_IN &&
+ (rpipe->next->r_mode == RES_IN &&
+ rpipe->next->progs->argv != NULL))||
+ (rpipe->r_mode == RES_FOR &&
+ rpipe->next->r_mode != RES_IN)) {
+ syntax();
+#ifdef __U_BOOT__
+ flag_repeat = 0;
+#endif
+ return 1;
+ }
+ }
+ for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
+ if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL ||
+ pi->r_mode == RES_FOR) {
+#ifdef __U_BOOT__
+ /* check Ctrl-C */
+ ctrlc();
+ if ((had_ctrlc())) {
+ return 1;
+ }
+#endif
+ flag_restore = 0;
+ if (!rpipe) {
+ flag_rep = 0;
+ rpipe = pi;
+ }
+ }
+ rmode = pi->r_mode;
+ debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode);
+ if (rmode == skip_more_in_this_rmode && flag_skip) {
+ if (pi->followup == PIPE_SEQ) flag_skip=0;
+ continue;
+ }
+ flag_skip = 1;
+ skip_more_in_this_rmode = RES_XXXX;
+ if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
+ if (rmode == RES_THEN && if_code) continue;
+ if (rmode == RES_ELSE && !if_code) continue;
+ if (rmode == RES_ELIF && !if_code) break;
+ if (rmode == RES_FOR && pi->num_progs) {
+ if (!list) {
+ /* if no variable values after "in" we skip "for" */
+ if (!pi->next->progs->argv) continue;
+ /* create list of variable values */
+ list = make_list_in(pi->next->progs->argv,
+ pi->progs->argv[0]);
+ save_list = list;
+ save_name = pi->progs->argv[0];
+ pi->progs->argv[0] = NULL;
+ flag_rep = 1;
+ }
+ if (!(*list)) {
+ free(pi->progs->argv[0]);
+ free(save_list);
+ list = NULL;
+ flag_rep = 0;
+ pi->progs->argv[0] = save_name;
+#ifndef __U_BOOT__
+ pi->progs->glob_result.gl_pathv[0] =
+ pi->progs->argv[0];
+#endif
+ continue;
+ } else {
+ /* insert new value from list for variable */
+ free(pi->progs->argv[0]);
+ pi->progs->argv[0] = *list++;
+#ifndef __U_BOOT__
+ pi->progs->glob_result.gl_pathv[0] =
+ pi->progs->argv[0];
+#endif
+ }
+ }
+ if (rmode == RES_IN) continue;
+ if (rmode == RES_DO) {
+ if (!flag_rep) continue;
+ }
+ if (rmode == RES_DONE) {
+ if (flag_rep) {
+ flag_restore = 1;
+ } else {
+ rpipe = NULL;
+ }
+ }
+ if (pi->num_progs == 0) continue;
+#ifndef __U_BOOT__
+ save_num_progs = pi->num_progs; /* save number of programs */
+#endif
+ rcode = run_pipe_real(pi);
+ debug_printf("run_pipe_real returned %d\n",rcode);
+#ifndef __U_BOOT__
+ if (rcode!=-1) {
+ /* We only ran a builtin: rcode was set by the return value
+ * of run_pipe_real(), and we don't need to wait for anything. */
+ } else if (pi->followup==PIPE_BG) {
+ /* XXX check bash's behavior with nontrivial pipes */
+ /* XXX compute jobid */
+ /* XXX what does bash do with attempts to background builtins? */
+ insert_bg_job(pi);
+ rcode = EXIT_SUCCESS;
+ } else {
+ if (interactive) {
+ /* move the new process group into the foreground */
+ if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
+ perror_msg("tcsetpgrp-3");
+ rcode = checkjobs(pi);
+ /* move the shell to the foreground */
+ if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY)
+ perror_msg("tcsetpgrp-4");
+ } else {
+ rcode = checkjobs(pi);
+ }
+ debug_printf("checkjobs returned %d\n",rcode);
+ }
+ last_return_code=rcode;
+#else
+ if (rcode < -1) {
+ last_return_code = -rcode - 2;
+ return -2; /* exit */
+ }
+ last_return_code=(rcode == 0) ? 0 : 1;
+#endif
+#ifndef __U_BOOT__
+ pi->num_progs = save_num_progs; /* restore number of programs */
+#endif
+ if ( rmode == RES_IF || rmode == RES_ELIF )
+ next_if_code=rcode; /* can be overwritten a number of times */
+ if (rmode == RES_WHILE)
+ flag_rep = !last_return_code;
+ if (rmode == RES_UNTIL)
+ flag_rep = last_return_code;
+ if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
+ (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
+ skip_more_in_this_rmode=rmode;
+#ifndef __U_BOOT__
+ checkjobs(NULL);
+#endif
+ }
+ return rcode;
+}
+
+/* broken, of course, but OK for testing */
+static char *indenter(int i)
+{
+ static char blanks[]=" ";
+ return &blanks[sizeof(blanks)-i-1];
+}
+
+/* return code is the exit status of the pipe */
+static int free_pipe(struct pipe *pi, int indent)
+{
+ char **p;
+ struct child_prog *child;
+#ifndef __U_BOOT__
+ struct redir_struct *r, *rnext;
+#endif
+ int a, i, ret_code=0;
+ char *ind = indenter(indent);
+
+#ifndef __U_BOOT__
+ if (pi->stopped_progs > 0)
+ return ret_code;
+ final_printf("%s run pipe: (pid %d)\n",ind,getpid());
+#endif
+ for (i=0; i<pi->num_progs; i++) {
+ child = &pi->progs[i];
+ final_printf("%s command %d:\n",ind,i);
+ if (child->argv) {
+ for (a=0,p=child->argv; *p; a++,p++) {
+ final_printf("%s argv[%d] = %s\n",ind,a,*p);
+ }
+#ifndef __U_BOOT__
+ globfree(&child->glob_result);
+#else
+ for (a = 0; a < child->argc; a++) {
+ free(child->argv[a]);
+ }
+ free(child->argv);
+ free(child->argv_nonnull);
+ child->argc = 0;
+#endif
+ child->argv=NULL;
+ } else if (child->group) {
+#ifndef __U_BOOT__
+ final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);
+#endif
+ ret_code = free_pipe_list(child->group,indent+3);
+ final_printf("%s end group\n",ind);
+ } else {
+ final_printf("%s (nil)\n",ind);
+ }
+#ifndef __U_BOOT__
+ for (r=child->redirects; r; r=rnext) {
+ final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip);
+ if (r->dup == -1) {
+ /* guard against the case >$FOO, where foo is unset or blank */
+ if (r->word.gl_pathv) {
+ final_printf(" %s\n", *r->word.gl_pathv);
+ globfree(&r->word);
+ }
+ } else {
+ final_printf("&%d\n", r->dup);
+ }
+ rnext=r->next;
+ free(r);
+ }
+ child->redirects=NULL;
+#endif
+ }
+ free(pi->progs); /* children are an array, they get freed all at once */
+ pi->progs=NULL;
+ return ret_code;
+}
+
+static int free_pipe_list(struct pipe *head, int indent)
+{
+ int rcode=0; /* if list has no members */
+ struct pipe *pi, *next;
+ char *ind = indenter(indent);
+ for (pi=head; pi; pi=next) {
+ final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
+ rcode = free_pipe(pi, indent);
+ final_printf("%s pipe followup code %d\n", ind, pi->followup);
+ next=pi->next;
+ pi->next=NULL;
+ free(pi);
+ }
+ return rcode;
+}
+
+/* Select which version we will use */
+static int run_list(struct pipe *pi)
+{
+ int rcode=0;
+#ifndef __U_BOOT__
+ if (fake_mode==0) {
+#endif
+ rcode = run_list_real(pi);
+#ifndef __U_BOOT__
+ }
+#endif
+ /* free_pipe_list has the side effect of clearing memory
+ * In the long run that function can be merged with run_list_real,
+ * but doing that now would hobble the debugging effort. */
+ free_pipe_list(pi,0);
+ return rcode;
+}
+
+/* The API for glob is arguably broken. This routine pushes a non-matching
+ * string into the output structure, removing non-backslashed backslashes.
+ * If someone can prove me wrong, by performing this function within the
+ * original glob(3) api, feel free to rewrite this routine into oblivion.
+ * Return code (0 vs. GLOB_NOSPACE) matches glob(3).
+ * XXX broken if the last character is '\\', check that before calling.
+ */
+#ifndef __U_BOOT__
+static int globhack(const char *src, int flags, glob_t *pglob)
+{
+ int cnt=0, pathc;
+ const char *s;
+ char *dest;
+ for (cnt=1, s=src; s && *s; s++) {
+ if (*s == '\\') s++;
+ cnt++;
+ }
+ dest = malloc(cnt);
+ if (!dest) return GLOB_NOSPACE;
+ if (!(flags & GLOB_APPEND)) {
+ pglob->gl_pathv=NULL;
+ pglob->gl_pathc=0;
+ pglob->gl_offs=0;
+ pglob->gl_offs=0;
+ }
+ pathc = ++pglob->gl_pathc;
+ pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
+ if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
+ pglob->gl_pathv[pathc-1]=dest;
+ pglob->gl_pathv[pathc]=NULL;
+ for (s=src; s && *s; s++, dest++) {
+ if (*s == '\\') s++;
+ *dest = *s;
+ }
+ *dest='\0';
+ return 0;
+}
+
+/* XXX broken if the last character is '\\', check that before calling */
+static int glob_needed(const char *s)
+{
+ for (; *s; s++) {
+ if (*s == '\\') s++;
+ if (strchr("*[?",*s)) return 1;
+ }
+ return 0;
+}
+
+#if 0
+static void globprint(glob_t *pglob)
+{
+ int i;
+ debug_printf("glob_t at %p:\n", pglob);
+ debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n",
+ pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);
+ for (i=0; i<pglob->gl_pathc; i++)
+ debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,
+ pglob->gl_pathv[i], pglob->gl_pathv[i]);
+}
+#endif
+
+static int xglob(o_string *dest, int flags, glob_t *pglob)
+{
+ int gr;
+
+ /* short-circuit for null word */
+ /* we can code this better when the debug_printf's are gone */
+ if (dest->length == 0) {
+ if (dest->nonnull) {
+ /* bash man page calls this an "explicit" null */
+ gr = globhack(dest->data, flags, pglob);
+ debug_printf("globhack returned %d\n",gr);
+ } else {
+ return 0;
+ }
+ } else if (glob_needed(dest->data)) {
+ gr = glob(dest->data, flags, NULL, pglob);
+ debug_printf("glob returned %d\n",gr);
+ if (gr == GLOB_NOMATCH) {
+ /* quote removal, or more accurately, backslash removal */
+ gr = globhack(dest->data, flags, pglob);
+ debug_printf("globhack returned %d\n",gr);
+ }
+ } else {
+ gr = globhack(dest->data, flags, pglob);
+ debug_printf("globhack returned %d\n",gr);
+ }
+ if (gr == GLOB_NOSPACE)
+ error_msg_and_die("out of memory during glob");
+ if (gr != 0) { /* GLOB_ABORTED ? */
+ error_msg("glob(3) error %d",gr);
+ }
+ /* globprint(glob_target); */
+ return gr;
+}
+#endif
+
+#ifdef __U_BOOT__
+static char *get_dollar_var(char ch);
+#endif
+
+/* This is used to get/check local shell variables */
+char *get_local_var(const char *s)
+{
+ struct variables *cur;
+
+ if (!s)
+ return NULL;
+
+#ifdef __U_BOOT__
+ if (*s == '$')
+ return get_dollar_var(s[1]);
+#endif
+
+ for (cur = top_vars; cur; cur=cur->next)
+ if(strcmp(cur->name, s)==0)
+ return cur->value;
+ return NULL;
+}
+
+/* This is used to set local shell variables
+ flg_export==0 if only local (not exporting) variable
+ flg_export==1 if "new" exporting environ
+ flg_export>1 if current startup environ (not call putenv()) */
+int set_local_var(const char *s, int flg_export)
+{
+ char *name, *value;
+ int result=0;
+ struct variables *cur;
+
+#ifdef __U_BOOT__
+ /* might be possible! */
+ if (!isalpha(*s))
+ return -1;
+#endif
+
+ name=strdup(s);
+
+ /* Assume when we enter this function that we are already in
+ * NAME=VALUE format. So the first order of business is to
+ * split 's' on the '=' into 'name' and 'value' */
+ value = strchr(name, '=');
+ if (value == NULL || *(value + 1) == 0) {
+ free(name);
+ return -1;
+ }
+ *value++ = 0;
+
+ for(cur = top_vars; cur; cur = cur->next) {
+ if(strcmp(cur->name, name)==0)
+ break;
+ }
+
+ if(cur) {
+ if(strcmp(cur->value, value)==0) {
+ if(flg_export>0 && cur->flg_export==0)
+ cur->flg_export=flg_export;
+ else
+ result++;
+ } else {
+ if(cur->flg_read_only) {
+ error_msg("%s: readonly variable", name);
+ result = -1;
+ } else {
+ if(flg_export>0 || cur->flg_export>1)
+ cur->flg_export=1;
+ free(cur->value);
+
+ cur->value = strdup(value);
+ }
+ }
+ } else {
+ cur = malloc(sizeof(struct variables));
+ if(!cur) {
+ result = -1;
+ } else {
+ cur->name = strdup(name);
+ if (cur->name == NULL) {
+ free(cur);
+ result = -1;
+ } else {
+ struct variables *bottom = top_vars;
+ cur->value = strdup(value);
+ cur->next = NULL;
+ cur->flg_export = flg_export;
+ cur->flg_read_only = 0;
+ while(bottom->next) bottom=bottom->next;
+ bottom->next = cur;
+ }
+ }
+ }
+
+#ifndef __U_BOOT__
+ if(result==0 && cur->flg_export==1) {
+ *(value-1) = '=';
+ result = putenv(name);
+ } else {
+#endif
+ free(name);
+#ifndef __U_BOOT__
+ if(result>0) /* equivalent to previous set */
+ result = 0;
+ }
+#endif
+ return result;
+}
+
+void unset_local_var(const char *name)
+{
+ struct variables *cur;
+
+ if (name) {
+ for (cur = top_vars; cur; cur=cur->next) {
+ if(strcmp(cur->name, name)==0)
+ break;
+ }
+ if (cur != NULL) {
+ struct variables *next = top_vars;
+ if(cur->flg_read_only) {
+ error_msg("%s: readonly variable", name);
+ return;
+ } else {
+#ifndef __U_BOOT__
+ if(cur->flg_export)
+ unenv_set(cur->name);
+#endif
+ free(cur->name);
+ free(cur->value);
+ while (next->next != cur)
+ next = next->next;
+ next->next = cur->next;
+ }
+ free(cur);
+ }
+ }
+}
+
+static int is_assignment(const char *s)
+{
+ if (s == NULL)
+ return 0;
+
+ if (!isalpha(*s)) return 0;
+ ++s;
+ while(isalnum(*s) || *s=='_') ++s;
+ return *s=='=';
+}
+
+#ifndef __U_BOOT__
+/* the src parameter allows us to peek forward to a possible &n syntax
+ * for file descriptor duplication, e.g., "2>&1".
+ * Return code is 0 normally, 1 if a syntax error is detected in src.
+ * Resource errors (in xmalloc) cause the process to exit */
+static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
+ struct in_str *input)
+{
+ struct child_prog *child=ctx->child;
+ struct redir_struct *redir = child->redirects;
+ struct redir_struct *last_redir=NULL;
+
+ /* Create a new redir_struct and drop it onto the end of the linked list */
+ while(redir) {
+ last_redir=redir;
+ redir=redir->next;
+ }
+ redir = xmalloc(sizeof(struct redir_struct));
+ redir->next=NULL;
+ redir->word.gl_pathv=NULL;
+ if (last_redir) {
+ last_redir->next=redir;
+ } else {
+ child->redirects=redir;
+ }
+
+ redir->type=style;
+ redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
+
+ debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
+
+ /* Check for a '2>&1' type redirect */
+ redir->dup = redirect_dup_num(input);
+ if (redir->dup == -2) return 1; /* syntax error */
+ if (redir->dup != -1) {
+ /* Erik had a check here that the file descriptor in question
+ * is legit; I postpone that to "run time"
+ * A "-" representation of "close me" shows up as a -3 here */
+ debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
+ } else {
+ /* We do _not_ try to open the file that src points to,
+ * since we need to return and let src be expanded first.
+ * Set ctx->pending_redirect, so we know what to do at the
+ * end of the next parsed word.
+ */
+ ctx->pending_redirect = redir;
+ }
+ return 0;
+}
+#endif
+
+static struct pipe *new_pipe(void)
+{
+ struct pipe *pi;
+ pi = xmalloc(sizeof(struct pipe));
+ pi->num_progs = 0;
+ pi->progs = NULL;
+ pi->next = NULL;
+ pi->followup = 0; /* invalid */
+ pi->r_mode = RES_NONE;
+ return pi;
+}
+
+static void initialize_context(struct p_context *ctx)
+{
+ ctx->pipe=NULL;
+#ifndef __U_BOOT__
+ ctx->pending_redirect=NULL;
+#endif
+ ctx->child=NULL;
+ ctx->list_head=new_pipe();
+ ctx->pipe=ctx->list_head;
+ ctx->w=RES_NONE;
+ ctx->stack=NULL;
+#ifdef __U_BOOT__
+ ctx->old_flag=0;
+#endif
+ done_command(ctx); /* creates the memory for working child */
+}
+
+/* normal return is 0
+ * if a reserved word is found, and processed, return 1
+ * should handle if, then, elif, else, fi, for, while, until, do, done.
+ * case, function, and select are obnoxious, save those for later.
+ */
+struct reserved_combo {
+ char *literal;
+ int code;
+ long flag;
+};
+/* Mostly a list of accepted follow-up reserved words.
+ * FLAG_END means we are done with the sequence, and are ready
+ * to turn the compound list into a command.
+ * FLAG_START means the word must start a new compound list.
+ */
+static struct reserved_combo reserved_list[] = {
+ { "if", RES_IF, FLAG_THEN | FLAG_START },
+ { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI },
+ { "elif", RES_ELIF, FLAG_THEN },
+ { "else", RES_ELSE, FLAG_FI },
+ { "fi", RES_FI, FLAG_END },
+ { "for", RES_FOR, FLAG_IN | FLAG_START },
+ { "while", RES_WHILE, FLAG_DO | FLAG_START },
+ { "until", RES_UNTIL, FLAG_DO | FLAG_START },
+ { "in", RES_IN, FLAG_DO },
+ { "do", RES_DO, FLAG_DONE },
+ { "done", RES_DONE, FLAG_END }
+};
+#define NRES (sizeof(reserved_list)/sizeof(struct reserved_combo))
+
+static int reserved_word(o_string *dest, struct p_context *ctx)
+{
+ struct reserved_combo *r;
+ for (r=reserved_list;
+ r<reserved_list+NRES; r++) {
+ if (strcmp(dest->data, r->literal) == 0) {
+ debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
+ if (r->flag & FLAG_START) {
+ struct p_context *new = xmalloc(sizeof(struct p_context));
+ debug_printf("push stack\n");
+ if (ctx->w == RES_IN || ctx->w == RES_FOR) {
+ syntax();
+ free(new);
+ ctx->w = RES_SNTX;
+ b_reset(dest);
+ return 1;
+ }
+ *new = *ctx; /* physical copy */
+ initialize_context(ctx);
+ ctx->stack=new;
+ } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
+ syntax();
+ ctx->w = RES_SNTX;
+ b_reset(dest);
+ return 1;
+ }
+ ctx->w=r->code;
+ ctx->old_flag = r->flag;
+ if (ctx->old_flag & FLAG_END) {
+ struct p_context *old;
+ debug_printf("pop stack\n");
+ done_pipe(ctx,PIPE_SEQ);
+ old = ctx->stack;
+ old->child->group = ctx->list_head;
+#ifndef __U_BOOT__
+ old->child->subshell = 0;
+#endif
+ *ctx = *old; /* physical copy */
+ free(old);
+ }
+ b_reset (dest);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* normal return is 0.
+ * Syntax or xglob errors return 1. */
+static int done_word(o_string *dest, struct p_context *ctx)
+{
+ struct child_prog *child=ctx->child;
+#ifndef __U_BOOT__
+ glob_t *glob_target;
+ int gr, flags = 0;
+#else
+ char *str, *s;
+ int argc, cnt;
+#endif
+
+ debug_printf("done_word: %s %p\n", dest->data, child);
+ if (dest->length == 0 && !dest->nonnull) {
+ debug_printf(" true null, ignored\n");
+ return 0;
+ }
+#ifndef __U_BOOT__
+ if (ctx->pending_redirect) {
+ glob_target = &ctx->pending_redirect->word;
+ } else {
+#endif
+ if (child->group) {
+ syntax();
+ return 1; /* syntax error, groups and arglists don't mix */
+ }
+ if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) {
+ debug_printf("checking %s for reserved-ness\n",dest->data);
+ if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
+ }
+#ifndef __U_BOOT__
+ glob_target = &child->glob_result;
+ if (child->argv) flags |= GLOB_APPEND;
+#else
+ for (cnt = 1, s = dest->data; s && *s; s++) {
+ if (*s == '\\') s++;
+ cnt++;
+ }
+ str = malloc(cnt);
+ if (!str) return 1;
+ if ( child->argv == NULL) {
+ child->argc=0;
+ }
+ argc = ++child->argc;
+ child->argv = realloc(child->argv, (argc+1)*sizeof(*child->argv));
+ if (child->argv == NULL) {
+ free(str);
+ return 1;
+ }
+ child->argv_nonnull = realloc(child->argv_nonnull,
+ (argc+1)*sizeof(*child->argv_nonnull));
+ if (child->argv_nonnull == NULL) {
+ free(str);
+ return 1;
+ }
+ child->argv[argc-1]=str;
+ child->argv_nonnull[argc-1] = dest->nonnull;
+ child->argv[argc]=NULL;
+ child->argv_nonnull[argc] = 0;
+ for (s = dest->data; s && *s; s++,str++) {
+ if (*s == '\\') s++;
+ *str = *s;
+ }
+ *str = '\0';
+#endif
+#ifndef __U_BOOT__
+ }
+ gr = xglob(dest, flags, glob_target);
+ if (gr != 0) return 1;
+#endif
+
+ b_reset(dest);
+#ifndef __U_BOOT__
+ if (ctx->pending_redirect) {
+ ctx->pending_redirect=NULL;
+ if (glob_target->gl_pathc != 1) {
+ error_msg("ambiguous redirect");
+ return 1;
+ }
+ } else {
+ child->argv = glob_target->gl_pathv;
+ }
+#endif
+ if (ctx->w == RES_FOR) {
+ done_word(dest,ctx);
+ done_pipe(ctx,PIPE_SEQ);
+ }
+ return 0;
+}
+
+/* The only possible error here is out of memory, in which case
+ * xmalloc exits. */
+static int done_command(struct p_context *ctx)
+{
+ /* The child is really already in the pipe structure, so
+ * advance the pipe counter and make a new, null child.
+ * Only real trickiness here is that the uncommitted
+ * child structure, to which ctx->child points, is not
+ * counted in pi->num_progs. */
+ struct pipe *pi=ctx->pipe;
+ struct child_prog *prog=ctx->child;
+
+ if (prog && prog->group == NULL
+ && prog->argv == NULL
+#ifndef __U_BOOT__
+ && prog->redirects == NULL) {
+#else
+ ) {
+#endif
+ debug_printf("done_command: skipping null command\n");
+ return 0;
+ } else if (prog) {
+ pi->num_progs++;
+ debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
+ } else {
+ debug_printf("done_command: initializing\n");
+ }
+ pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
+
+ prog = pi->progs + pi->num_progs;
+#ifndef __U_BOOT__
+ prog->redirects = NULL;
+#endif
+ prog->argv = NULL;
+ prog->argv_nonnull = NULL;
+#ifndef __U_BOOT__
+ prog->is_stopped = 0;
+#endif
+ prog->group = NULL;
+#ifndef __U_BOOT__
+ prog->glob_result.gl_pathv = NULL;
+ prog->family = pi;
+#endif
+ prog->sp = 0;
+ ctx->child = prog;
+ prog->type = ctx->type;
+
+ /* but ctx->pipe and ctx->list_head remain unchanged */
+ return 0;
+}
+
+static int done_pipe(struct p_context *ctx, pipe_style type)
+{
+ struct pipe *new_p;
+ done_command(ctx); /* implicit closure of previous command */
+ debug_printf("done_pipe, type %d\n", type);
+ ctx->pipe->followup = type;
+ ctx->pipe->r_mode = ctx->w;
+ new_p=new_pipe();
+ ctx->pipe->next = new_p;
+ ctx->pipe = new_p;
+ ctx->child = NULL;
+ done_command(ctx); /* set up new pipe to accept commands */
+ return 0;
+}
+
+#ifndef __U_BOOT__
+/* peek ahead in the in_str to find out if we have a "&n" construct,
+ * as in "2>&1", that represents duplicating a file descriptor.
+ * returns either -2 (syntax error), -1 (no &), or the number found.
+ */
+static int redirect_dup_num(struct in_str *input)
+{
+ int ch, d=0, ok=0;
+ ch = b_peek(input);
+ if (ch != '&') return -1;
+
+ b_getch(input); /* get the & */
+ ch=b_peek(input);
+ if (ch == '-') {
+ b_getch(input);
+ return -3; /* "-" represents "close me" */
+ }
+ while (isdigit(ch)) {
+ d = d*10+(ch-'0');
+ ok=1;
+ b_getch(input);
+ ch = b_peek(input);
+ }
+ if (ok) return d;
+
+ error_msg("ambiguous redirect");
+ return -2;
+}
+
+/* If a redirect is immediately preceded by a number, that number is
+ * supposed to tell which file descriptor to redirect. This routine
+ * looks for such preceding numbers. In an ideal world this routine
+ * needs to handle all the following classes of redirects...
+ * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo
+ * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo
+ * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo
+ * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo
+ * A -1 output from this program means no valid number was found, so the
+ * caller should use the appropriate default for this redirection.
+ */
+static int redirect_opt_num(o_string *o)
+{
+ int num;
+
+ if (o->length==0) return -1;
+ for(num=0; num<o->length; num++) {
+ if (!isdigit(*(o->data+num))) {
+ return -1;
+ }
+ }
+ /* reuse num (and save an int) */
+ num=atoi(o->data);
+ b_reset(o);
+ return num;
+}
+
+FILE *generate_stream_from_list(struct pipe *head)
+{
+ FILE *pf;
+#if 1
+ int pid, channel[2];
+ if (pipe(channel)<0) perror_msg_and_die("pipe");
+ pid=fork();
+ if (pid<0) {
+ perror_msg_and_die("fork");
+ } else if (pid==0) {
+ close(channel[0]);
+ if (channel[1] != 1) {
+ dup2(channel[1],1);
+ close(channel[1]);
+ }
+#if 0
+#define SURROGATE "surrogate response"
+ write(1,SURROGATE,sizeof(SURROGATE));
+ _exit(run_list(head));
+#else
+ _exit(run_list_real(head)); /* leaks memory */
+#endif
+ }
+ debug_printf("forked child %d\n",pid);
+ close(channel[1]);
+ pf = fdopen(channel[0],"r");
+ debug_printf("pipe on FILE *%p\n",pf);
+#else
+ free_pipe_list(head,0);
+ pf=popen("echo surrogate response","r");
+ debug_printf("started fake pipe on FILE *%p\n",pf);
+#endif
+ return pf;
+}
+
+/* this version hacked for testing purposes */
+/* return code is exit status of the process that is run. */
+static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end)
+{
+ int retcode;
+ o_string result=NULL_O_STRING;
+ struct p_context inner;
+ FILE *p;
+ struct in_str pipe_str;
+ initialize_context(&inner);
+
+ /* recursion to generate command */
+ retcode = parse_stream(&result, &inner, input, subst_end);
+ if (retcode != 0) return retcode; /* syntax error or EOF */
+ done_word(&result, &inner);
+ done_pipe(&inner, PIPE_SEQ);
+ b_free(&result);
+
+ p=generate_stream_from_list(inner.list_head);
+ if (p==NULL) return 1;
+ mark_open(fileno(p));
+ setup_file_in_str(&pipe_str, p);
+
+ /* now send results of command back into original context */
+ retcode = parse_stream(dest, ctx, &pipe_str, '\0');
+ /* XXX In case of a syntax error, should we try to kill the child?
+ * That would be tough to do right, so just read until EOF. */
+ if (retcode == 1) {
+ while (b_getch(&pipe_str)!=EOF) { /* discard */ };
+ }
+
+ debug_printf("done reading from pipe, pclose()ing\n");
+ /* This is the step that wait()s for the child. Should be pretty
+ * safe, since we just read an EOF from its stdout. We could try
+ * to better, by using wait(), and keeping track of background jobs
+ * at the same time. That would be a lot of work, and contrary
+ * to the KISS philosophy of this program. */
+ mark_closed(fileno(p));
+ retcode=pclose(p);
+ free_pipe_list(inner.list_head,0);
+ debug_printf("pclosed, retcode=%d\n",retcode);
+ /* XXX this process fails to trim a single trailing newline */
+ return retcode;
+}
+
+static int parse_group(o_string *dest, struct p_context *ctx,
+ struct in_str *input, int ch)
+{
+ int rcode, endch=0;
+ struct p_context sub;
+ struct child_prog *child = ctx->child;
+ if (child->argv) {
+ syntax();
+ return 1; /* syntax error, groups and arglists don't mix */
+ }
+ initialize_context(&sub);
+ switch(ch) {
+ case '(': endch=')'; child->subshell=1; break;
+ case '{': endch='}'; break;
+ default: syntax(); /* really logic error */
+ }
+ rcode=parse_stream(dest,&sub,input,endch);
+ done_word(dest,&sub); /* finish off the final word in the subcontext */
+ done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */
+ child->group = sub.list_head;
+ return rcode;
+ /* child remains "open", available for possible redirects */
+}
+#endif
+
+/* basically useful version until someone wants to get fancier,
+ * see the bash man page under "Parameter Expansion" */
+static char *lookup_param(char *src)
+{
+ char *p;
+ char *sep;
+ char *default_val = NULL;
+ int assign = 0;
+ int expand_empty = 0;
+
+ if (!src)
+ return NULL;
+
+ sep = strchr(src, ':');
+
+ if (sep) {
+ *sep = '\0';
+ if (*(sep + 1) == '-')
+ default_val = sep+2;
+ if (*(sep + 1) == '=') {
+ default_val = sep+2;
+ assign = 1;
+ }
+ if (*(sep + 1) == '+') {
+ default_val = sep+2;
+ expand_empty = 1;
+ }
+ }
+
+ p = env_get(src);
+ if (!p)
+ p = get_local_var(src);
+
+ if (!p || strlen(p) == 0) {
+ p = default_val;
+ if (assign) {
+ char *var = malloc(strlen(src)+strlen(default_val)+2);
+ if (var) {
+ sprintf(var, "%s=%s", src, default_val);
+ set_local_var(var, 0);
+ }
+ free(var);
+ }
+ } else if (expand_empty) {
+ p += strlen(p);
+ }
+
+ if (sep)
+ *sep = ':';
+
+ return p;
+}
+
+#ifdef __U_BOOT__
+static char *get_dollar_var(char ch)
+{
+ static char buf[40];
+
+ buf[0] = '\0';
+ switch (ch) {
+ case '?':
+ sprintf(buf, "%u", (unsigned int)last_return_code);
+ break;
+ default:
+ return NULL;
+ }
+ return buf;
+}
+#endif
+
+/* return code: 0 for OK, 1 for syntax error */
+static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
+{
+#ifndef __U_BOOT__
+ int i, advance=0;
+#else
+ int advance=0;
+#endif
+#ifndef __U_BOOT__
+ char sep[]=" ";
+#endif
+ int ch = input->peek(input); /* first character after the $ */
+ debug_printf("handle_dollar: ch=%c\n",ch);
+ if (isalpha(ch)) {
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+ ctx->child->sp++;
+ while(ch=b_peek(input),isalnum(ch) || ch=='_') {
+ b_getch(input);
+ b_addchr(dest,ch);
+ }
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+#ifndef __U_BOOT__
+ } else if (isdigit(ch)) {
+ i = ch-'0'; /* XXX is $0 special? */
+ if (i<global_argc) {
+ parse_string(dest, ctx, global_argv[i]); /* recursion */
+ }
+ advance = 1;
+#endif
+ } else switch (ch) {
+#ifndef __U_BOOT__
+ case '$':
+ b_adduint(dest,getpid());
+ advance = 1;
+ break;
+ case '!':
+ if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
+ advance = 1;
+ break;
+#endif
+ case '?':
+#ifndef __U_BOOT__
+ b_adduint(dest,last_return_code);
+#else
+ ctx->child->sp++;
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+ b_addchr(dest, '$');
+ b_addchr(dest, '?');
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+#endif
+ advance = 1;
+ break;
+#ifndef __U_BOOT__
+ case '#':
+ b_adduint(dest,global_argc ? global_argc-1 : 0);
+ advance = 1;
+ break;
+#endif
+ case '{':
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+ ctx->child->sp++;
+ b_getch(input);
+ /* XXX maybe someone will try to escape the '}' */
+ while(ch=b_getch(input),ch!=EOF && ch!='}') {
+ b_addchr(dest,ch);
+ }
+ if (ch != '}') {
+ syntax();
+ return 1;
+ }
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+ break;
+#ifndef __U_BOOT__
+ case '(':
+ b_getch(input);
+ process_command_subs(dest, ctx, input, ')');
+ break;
+ case '*':
+ sep[0]=ifs[0];
+ for (i=1; i<global_argc; i++) {
+ parse_string(dest, ctx, global_argv[i]);
+ if (i+1 < global_argc) parse_string(dest, ctx, sep);
+ }
+ break;
+ case '@':
+ case '-':
+ case '_':
+ /* still unhandled, but should be eventually */
+ error_msg("unhandled syntax: $%c",ch);
+ return 1;
+ break;
+#endif
+ default:
+ b_addqchr(dest,'$',dest->quote);
+ }
+ /* Eat the character if the flag was set. If the compiler
+ * is smart enough, we could substitute "b_getch(input);"
+ * for all the "advance = 1;" above, and also end up with
+ * a nice size-optimized program. Hah! That'll be the day.
+ */
+ if (advance) b_getch(input);
+ return 0;
+}
+
+#ifndef __U_BOOT__
+int parse_string(o_string *dest, struct p_context *ctx, const char *src)
+{
+ struct in_str foo;
+ setup_string_in_str(&foo, src);
+ return parse_stream(dest, ctx, &foo, '\0');
+}
+#endif
+
+/* return code is 0 for normal exit, 1 for syntax error */
+static int parse_stream(o_string *dest, struct p_context *ctx,
+ struct in_str *input, int end_trigger)
+{
+ unsigned int ch, m;
+#ifndef __U_BOOT__
+ int redir_fd;
+ redir_type redir_style;
+#endif
+ int next;
+
+ /* Only double-quote state is handled in the state variable dest->quote.
+ * A single-quote triggers a bypass of the main loop until its mate is
+ * found. When recursing, quote state is passed in via dest->quote. */
+
+ debug_printf("parse_stream, end_trigger=%d\n",end_trigger);
+ while ((ch=b_getch(input))!=EOF) {
+ m = map[ch];
+#ifdef __U_BOOT__
+ if (input->__promptme == 0) return 1;
+#endif
+ next = (ch == '\n') ? 0 : b_peek(input);
+
+ debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d - %c\n",
+ ch >= ' ' ? ch : '.', ch, m,
+ dest->quote, ctx->stack == NULL ? '*' : '.');
+
+ if (m==0 || ((m==1 || m==2) && dest->quote)) {
+ b_addqchr(dest, ch, dest->quote);
+ } else {
+ if (m==2) { /* unquoted IFS */
+ if (done_word(dest, ctx)) {
+ return 1;
+ }
+ /* If we aren't performing a substitution, treat a newline as a
+ * command separator. */
+ if (end_trigger != '\0' && ch=='\n')
+ done_pipe(ctx,PIPE_SEQ);
+ }
+ if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
+ debug_printf("leaving parse_stream (triggered)\n");
+ return 0;
+ }
+#if 0
+ if (ch=='\n') {
+ /* Yahoo! Time to run with it! */
+ done_pipe(ctx,PIPE_SEQ);
+ run_list(ctx->list_head);
+ initialize_context(ctx);
+ }
+#endif
+ if (m!=2) switch (ch) {
+ case '#':
+ if (dest->length == 0 && !dest->quote) {
+ while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); }
+ } else {
+ b_addqchr(dest, ch, dest->quote);
+ }
+ break;
+ case '\\':
+ if (next == EOF) {
+ syntax();
+ return 1;
+ }
+ b_addqchr(dest, '\\', dest->quote);
+ b_addqchr(dest, b_getch(input), dest->quote);
+ break;
+ case '$':
+ if (handle_dollar(dest, ctx, input)!=0) return 1;
+ break;
+ case '\'':
+ dest->nonnull = 1;
+ while(ch=b_getch(input),ch!=EOF && ch!='\'') {
+#ifdef __U_BOOT__
+ if(input->__promptme == 0) return 1;
+#endif
+ b_addchr(dest,ch);
+ }
+ if (ch==EOF) {
+ syntax();
+ return 1;
+ }
+ break;
+ case '"':
+ dest->nonnull = 1;
+ dest->quote = !dest->quote;
+ break;
+#ifndef __U_BOOT__
+ case '`':
+ process_command_subs(dest, ctx, input, '`');
+ break;
+ case '>':
+ redir_fd = redirect_opt_num(dest);
+ done_word(dest, ctx);
+ redir_style=REDIRECT_OVERWRITE;
+ if (next == '>') {
+ redir_style=REDIRECT_APPEND;
+ b_getch(input);
+ } else if (next == '(') {
+ syntax(); /* until we support >(list) Process Substitution */
+ return 1;
+ }
+ setup_redirect(ctx, redir_fd, redir_style, input);
+ break;
+ case '<':
+ redir_fd = redirect_opt_num(dest);
+ done_word(dest, ctx);
+ redir_style=REDIRECT_INPUT;
+ if (next == '<') {
+ redir_style=REDIRECT_HEREIS;
+ b_getch(input);
+ } else if (next == '>') {
+ redir_style=REDIRECT_IO;
+ b_getch(input);
+ } else if (next == '(') {
+ syntax(); /* until we support <(list) Process Substitution */
+ return 1;
+ }
+ setup_redirect(ctx, redir_fd, redir_style, input);
+ break;
+#endif
+ case ';':
+ done_word(dest, ctx);
+ done_pipe(ctx,PIPE_SEQ);
+ break;
+ case '&':
+ done_word(dest, ctx);
+ if (next=='&') {
+ b_getch(input);
+ done_pipe(ctx,PIPE_AND);
+ } else {
+#ifndef __U_BOOT__
+ done_pipe(ctx,PIPE_BG);
+#else
+ syntax_err();
+ return 1;
+#endif
+ }
+ break;
+ case '|':
+ done_word(dest, ctx);
+ if (next=='|') {
+ b_getch(input);
+ done_pipe(ctx,PIPE_OR);
+ } else {
+ /* we could pick up a file descriptor choice here
+ * with redirect_opt_num(), but bash doesn't do it.
+ * "echo foo 2| cat" yields "foo 2". */
+#ifndef __U_BOOT__
+ done_command(ctx);
+#else
+ syntax_err();
+ return 1;
+#endif
+ }
+ break;
+#ifndef __U_BOOT__
+ case '(':
+ case '{':
+ if (parse_group(dest, ctx, input, ch)!=0) return 1;
+ break;
+ case ')':
+ case '}':
+ syntax(); /* Proper use of this character caught by end_trigger */
+ return 1;
+ break;
+#endif
+ case SUBSTED_VAR_SYMBOL:
+ dest->nonnull = 1;
+ while (ch = b_getch(input), ch != EOF &&
+ ch != SUBSTED_VAR_SYMBOL) {
+ debug_printf("subst, pass=%d\n", ch);
+ if (input->__promptme == 0)
+ return 1;
+ b_addchr(dest, ch);
+ }
+ debug_printf("subst, term=%d\n", ch);
+ if (ch == EOF) {
+ syntax();
+ return 1;
+ }
+ break;
+ default:
+ syntax(); /* this is really an internal logic error */
+ return 1;
+ }
+ }
+ }
+ /* complain if quote? No, maybe we just finished a command substitution
+ * that was quoted. Example:
+ * $ echo "`cat foo` plus more"
+ * and we just got the EOF generated by the subshell that ran "cat foo"
+ * The only real complaint is if we got an EOF when end_trigger != '\0',
+ * that is, we were really supposed to get end_trigger, and never got
+ * one before the EOF. Can't use the standard "syntax error" return code,
+ * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
+ debug_printf("leaving parse_stream (EOF)\n");
+ if (end_trigger != '\0') return -1;
+ return 0;
+}
+
+static void mapset(const unsigned char *set, int code)
+{
+ const unsigned char *s;
+ for (s=set; *s; s++) map[*s] = code;
+}
+
+static void update_ifs_map(void)
+{
+ /* char *ifs and char map[256] are both globals. */
+ ifs = (uchar *)env_get("IFS");
+ if (ifs == NULL) ifs=(uchar *)" \t\n";
+ /* Precompute a list of 'flow through' behavior so it can be treated
+ * quickly up front. Computation is necessary because of IFS.
+ * Special case handling of IFS == " \t\n" is not implemented.
+ * The map[] array only really needs two bits each, and on most machines
+ * that would be faster because of the reduced L1 cache footprint.
+ */
+ memset(map,0,sizeof(map)); /* most characters flow through always */
+#ifndef __U_BOOT__
+ mapset((uchar *)"\\$'\"`", 3); /* never flow through */
+ mapset((uchar *)"<>;&|(){}#", 1); /* flow through if quoted */
+#else
+ {
+ uchar subst[2] = {SUBSTED_VAR_SYMBOL, 0};
+ mapset(subst, 3); /* never flow through */
+ }
+ mapset((uchar *)"\\$'\"", 3); /* never flow through */
+ mapset((uchar *)";&|#", 1); /* flow through if quoted */
+#endif
+ mapset(ifs, 2); /* also flow through if quoted */
+}
+
+/* most recursion does not come through here, the exeception is
+ * from builtin_source() */
+static int parse_stream_outer(struct in_str *inp, int flag)
+{
+
+ struct p_context ctx;
+ o_string temp=NULL_O_STRING;
+ int rcode;
+#ifdef __U_BOOT__
+ int code = 1;
+#endif
+ do {
+ ctx.type = flag;
+ initialize_context(&ctx);
+ update_ifs_map();
+ if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset((uchar *)";$&|", 0);
+ inp->promptmode=1;
+ rcode = parse_stream(&temp, &ctx, inp,
+ flag & FLAG_CONT_ON_NEWLINE ? -1 : '\n');
+#ifdef __U_BOOT__
+ if (rcode == 1) flag_repeat = 0;
+#endif
+ if (rcode != 1 && ctx.old_flag != 0) {
+ syntax();
+#ifdef __U_BOOT__
+ flag_repeat = 0;
+#endif
+ }
+ if (rcode != 1 && ctx.old_flag == 0) {
+ done_word(&temp, &ctx);
+ done_pipe(&ctx,PIPE_SEQ);
+#ifndef __U_BOOT__
+ run_list(ctx.list_head);
+#else
+ code = run_list(ctx.list_head);
+ if (code == -2) { /* exit */
+ b_free(&temp);
+ code = 0;
+ /* XXX hackish way to not allow exit from main loop */
+ if (inp->peek == file_peek) {
+ printf("exit not allowed from main input shell.\n");
+ continue;
+ }
+ break;
+ }
+ if (code == -1)
+ flag_repeat = 0;
+#endif
+ } else {
+ if (ctx.old_flag != 0) {
+ free(ctx.stack);
+ b_reset(&temp);
+ }
+#ifdef __U_BOOT__
+ if (inp->__promptme == 0) printf("<INTERRUPT>\n");
+ inp->__promptme = 1;
+#endif
+ temp.nonnull = 0;
+ temp.quote = 0;
+ inp->p = NULL;
+ free_pipe_list(ctx.list_head,0);
+ }
+ b_free(&temp);
+ /* loop on syntax errors, return on EOF */
+ } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP) &&
+ (inp->peek != static_peek || b_peek(inp)));
+#ifndef __U_BOOT__
+ return 0;
+#else
+ return (code != 0) ? 1 : 0;
+#endif /* __U_BOOT__ */
+}
+
+#ifndef __U_BOOT__
+static int parse_string_outer(const char *s, int flag)
+#else
+int parse_string_outer(const char *s, int flag)
+#endif /* __U_BOOT__ */
+{
+ struct in_str input;
+#ifdef __U_BOOT__
+ char *p = NULL;
+ int rcode;
+ if (!s)
+ return 1;
+ if (!*s)
+ return 0;
+ if (!(p = strchr(s, '\n')) || *++p) {
+ p = xmalloc(strlen(s) + 2);
+ strcpy(p, s);
+ strcat(p, "\n");
+ setup_string_in_str(&input, p);
+ rcode = parse_stream_outer(&input, flag);
+ free(p);
+ return rcode;
+ } else {
+#endif
+ setup_string_in_str(&input, s);
+ return parse_stream_outer(&input, flag);
+#ifdef __U_BOOT__
+ }
+#endif
+}
+
+#ifndef __U_BOOT__
+static int parse_file_outer(FILE *f)
+#else
+int parse_file_outer(void)
+#endif
+{
+ int rcode;
+ struct in_str input;
+#ifndef __U_BOOT__
+ setup_file_in_str(&input, f);
+#else
+ setup_file_in_str(&input);
+#endif
+ rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
+ return rcode;
+}
+
+#ifdef __U_BOOT__
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+static void u_boot_hush_reloc(void)
+{
+ unsigned long addr;
+ struct reserved_combo *r;
+
+ for (r=reserved_list; r<reserved_list+NRES; r++) {
+ addr = (ulong) (r->literal) + gd->reloc_off;
+ r->literal = (char *)addr;
+ }
+}
+#endif
+
+int u_boot_hush_start(void)
+{
+ if (top_vars == NULL) {
+ top_vars = malloc(sizeof(struct variables));
+ top_vars->name = "HUSH_VERSION";
+ top_vars->value = "0.01";
+ top_vars->next = NULL;
+ top_vars->flg_export = 0;
+ top_vars->flg_read_only = 1;
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ u_boot_hush_reloc();
+#endif
+ }
+ return 0;
+}
+
+static void *xmalloc(size_t size)
+{
+ void *p = NULL;
+
+ if (!(p = malloc(size))) {
+ printf("ERROR : xmalloc failed\n");
+ for(;;);
+ }
+ return p;
+}
+
+static void *xrealloc(void *ptr, size_t size)
+{
+ void *p = NULL;
+
+ if (!(p = realloc(ptr, size))) {
+ printf("ERROR : xrealloc failed\n");
+ for(;;);
+ }
+ return p;
+}
+#endif /* __U_BOOT__ */
+
+#ifndef __U_BOOT__
+/* Make sure we have a controlling tty. If we get started under a job
+ * aware app (like bash for example), make sure we are now in charge so
+ * we don't fight over who gets the foreground */
+static void setup_job_control(void)
+{
+ static pid_t shell_pgrp;
+ /* Loop until we are in the foreground. */
+ while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
+ kill (- shell_pgrp, SIGTTIN);
+
+ /* Ignore interactive and job-control signals. */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
+
+ /* Put ourselves in our own process group. */
+ setsid();
+ shell_pgrp = getpid ();
+ setpgid (shell_pgrp, shell_pgrp);
+
+ /* Grab control of the terminal. */
+ tcsetpgrp(shell_terminal, shell_pgrp);
+}
+
+int hush_main(int argc, char * const *argv)
+{
+ int opt;
+ FILE *input;
+ char **e = environ;
+
+ /* XXX what should these be while sourcing /etc/profile? */
+ global_argc = argc;
+ global_argv = argv;
+
+ /* (re?) initialize globals. Sometimes hush_main() ends up calling
+ * hush_main(), therefore we cannot rely on the BSS to zero out this
+ * stuff. Reset these to 0 every time. */
+ ifs = NULL;
+ /* map[] is taken care of with call to update_ifs_map() */
+ fake_mode = 0;
+ interactive = 0;
+ close_me_head = NULL;
+ last_bg_pid = 0;
+ job_list = NULL;
+ last_jobid = 0;
+
+ /* Initialize some more globals to non-zero values */
+ set_cwd();
+#ifdef CONFIG_FEATURE_COMMAND_EDITING
+ cmdedit_set_initial_prompt();
+#else
+ PS1 = NULL;
+#endif
+ PS2 = "> ";
+
+ /* initialize our shell local variables with the values
+ * currently living in the environment */
+ if (e) {
+ for (; *e; e++)
+ set_local_var(*e, 2); /* without call putenv() */
+ }
+
+ last_return_code=EXIT_SUCCESS;
+
+
+ if (argv[0] && argv[0][0] == '-') {
+ debug_printf("\nsourcing /etc/profile\n");
+ if ((input = fopen("/etc/profile", "r")) != NULL) {
+ mark_open(fileno(input));
+ parse_file_outer(input);
+ mark_closed(fileno(input));
+ fclose(input);
+ }
+ }
+ input=stdin;
+
+ while ((opt = getopt(argc, argv, "c:xif")) > 0) {
+ switch (opt) {
+ case 'c':
+ {
+ global_argv = argv+optind;
+ global_argc = argc-optind;
+ opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
+ goto final_return;
+ }
+ break;
+ case 'i':
+ interactive++;
+ break;
+ case 'f':
+ fake_mode++;
+ break;
+ default:
+#ifndef BB_VER
+ fprintf(stderr, "Usage: sh [FILE]...\n"
+ " or: sh -c command [args]...\n\n");
+ exit(EXIT_FAILURE);
+#else
+ show_usage();
+#endif
+ }
+ }
+ /* A shell is interactive if the `-i' flag was given, or if all of
+ * the following conditions are met:
+ * no -c command
+ * no arguments remaining or the -s flag given
+ * standard input is a terminal
+ * standard output is a terminal
+ * Refer to Posix.2, the description of the `sh' utility. */
+ if (argv[optind]==NULL && input==stdin &&
+ isatty(fileno(stdin)) && isatty(fileno(stdout))) {
+ interactive++;
+ }
+
+ debug_printf("\ninteractive=%d\n", interactive);
+ if (interactive) {
+ /* Looks like they want an interactive shell */
+#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
+ printf( "\n\n" BB_BANNER " hush - the humble shell v0.01 (testing)\n");
+ printf( "Enter 'help' for a list of built-in commands.\n\n");
+#endif
+ setup_job_control();
+ }
+
+ if (argv[optind]==NULL) {
+ opt=parse_file_outer(stdin);
+ goto final_return;
+ }
+
+ debug_printf("\nrunning script '%s'\n", argv[optind]);
+ global_argv = argv+optind;
+ global_argc = argc-optind;
+ input = xfopen(argv[optind], "r");
+ opt = parse_file_outer(input);
+
+#ifdef CONFIG_FEATURE_CLEAN_UP
+ fclose(input);
+ if (cwd && cwd != unknown)
+ free((char*)cwd);
+ {
+ struct variables *cur, *tmp;
+ for(cur = top_vars; cur; cur = tmp) {
+ tmp = cur->next;
+ if (!cur->flg_read_only) {
+ free(cur->name);
+ free(cur->value);
+ free(cur);
+ }
+ }
+ }
+#endif
+
+final_return:
+ return(opt?opt:last_return_code);
+}
+#endif
+
+static char *insert_var_value(char *inp)
+{
+ return insert_var_value_sub(inp, 0);
+}
+
+static char *insert_var_value_sub(char *inp, int tag_subst)
+{
+ int res_str_len = 0;
+ int len;
+ int done = 0;
+ char *p, *p1, *res_str = NULL;
+
+ while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
+ /* check the beginning of the string for normal characters */
+ if (p != inp) {
+ /* copy any characters to the result string */
+ len = p - inp;
+ res_str = xrealloc(res_str, (res_str_len + len));
+ strncpy((res_str + res_str_len), inp, len);
+ res_str_len += len;
+ }
+ inp = ++p;
+ /* find the ending marker */
+ p = strchr(inp, SPECIAL_VAR_SYMBOL);
+ *p = '\0';
+ /* look up the value to substitute */
+ if ((p1 = lookup_param(inp))) {
+ if (tag_subst)
+ len = res_str_len + strlen(p1) + 2;
+ else
+ len = res_str_len + strlen(p1);
+ res_str = xrealloc(res_str, (1 + len));
+ if (tag_subst) {
+ /*
+ * copy the variable value to the result
+ * string
+ */
+ strcpy((res_str + res_str_len + 1), p1);
+
+ /*
+ * mark the replaced text to be accepted as
+ * is
+ */
+ res_str[res_str_len] = SUBSTED_VAR_SYMBOL;
+ res_str[res_str_len + 1 + strlen(p1)] =
+ SUBSTED_VAR_SYMBOL;
+ } else
+ /*
+ * copy the variable value to the result
+ * string
+ */
+ strcpy((res_str + res_str_len), p1);
+
+ res_str_len = len;
+ }
+ *p = SPECIAL_VAR_SYMBOL;
+ inp = ++p;
+ done = 1;
+ }
+ if (done) {
+ res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
+ strcpy((res_str + res_str_len), inp);
+ while ((p = strchr(res_str, '\n'))) {
+ *p = ' ';
+ }
+ }
+ return (res_str == NULL) ? inp : res_str;
+}
+
+static char **make_list_in(char **inp, char *name)
+{
+ int len, i;
+ int name_len = strlen(name);
+ int n = 0;
+ char **list;
+ char *p1, *p2, *p3;
+
+ /* create list of variable values */
+ list = xmalloc(sizeof(*list));
+ for (i = 0; inp[i]; i++) {
+ p3 = insert_var_value(inp[i]);
+ p1 = p3;
+ while (*p1) {
+ if (*p1 == ' ') {
+ p1++;
+ continue;
+ }
+ if ((p2 = strchr(p1, ' '))) {
+ len = p2 - p1;
+ } else {
+ len = strlen(p1);
+ p2 = p1 + len;
+ }
+ /* we use n + 2 in realloc for list,because we add
+ * new element and then we will add NULL element */
+ list = xrealloc(list, sizeof(*list) * (n + 2));
+ list[n] = xmalloc(2 + name_len + len);
+ strcpy(list[n], name);
+ strcat(list[n], "=");
+ strncat(list[n], p1, len);
+ list[n++][name_len + len + 1] = '\0';
+ p1 = p2;
+ }
+ if (p3 != inp[i]) free(p3);
+ }
+ list[n] = NULL;
+ return list;
+}
+
+/*
+ * Make new string for parser
+ * inp - array of argument strings to flatten
+ * nonnull - indicates argument was quoted when originally parsed
+ */
+static char *make_string(char **inp, int *nonnull)
+{
+ char *p;
+ char *str = NULL;
+ int n;
+ int len = 2;
+ char *noeval_str;
+ int noeval = 0;
+
+ noeval_str = get_local_var("HUSH_NO_EVAL");
+ if (noeval_str != NULL && *noeval_str != '0' && *noeval_str != '\0')
+ noeval = 1;
+ for (n = 0; inp[n]; n++) {
+ p = insert_var_value_sub(inp[n], noeval);
+ str = xrealloc(str, (len + strlen(p) + (2 * nonnull[n])));
+ if (n) {
+ strcat(str, " ");
+ } else {
+ *str = '\0';
+ }
+ if (nonnull[n])
+ strcat(str, "'");
+ strcat(str, p);
+ if (nonnull[n])
+ strcat(str, "'");
+ len = strlen(str) + 3;
+ if (p != inp[n]) free(p);
+ }
+ len = strlen(str);
+ *(str + len) = '\n';
+ *(str + len + 1) = '\0';
+ return str;
+}
+
+#ifdef __U_BOOT__
+static int do_showvar(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int i, k;
+ int rcode = 0;
+ struct variables *cur;
+
+ if (argc == 1) { /* Print all env variables */
+ for (cur = top_vars; cur; cur = cur->next) {
+ printf ("%s=%s\n", cur->name, cur->value);
+ if (ctrlc ()) {
+ puts ("\n ** Abort\n");
+ return 1;
+ }
+ }
+ return 0;
+ }
+ for (i = 1; i < argc; ++i) { /* print single env variables */
+ char *name = argv[i];
+
+ k = -1;
+ for (cur = top_vars; cur; cur = cur->next) {
+ if(strcmp (cur->name, name) == 0) {
+ k = 0;
+ printf ("%s=%s\n", cur->name, cur->value);
+ }
+ if (ctrlc ()) {
+ puts ("\n ** Abort\n");
+ return 1;
+ }
+ }
+ if (k < 0) {
+ printf ("## Error: \"%s\" not defined\n", name);
+ rcode ++;
+ }
+ }
+ return rcode;
+}
+
+U_BOOT_CMD(
+ showvar, CONFIG_SYS_MAXARGS, 1, do_showvar,
+ "print local hushshell variables",
+ "\n - print values of all hushshell variables\n"
+ "showvar name ...\n"
+ " - print value of hushshell variable 'name'"
+);
+
+#endif
+/****************************************************************************/
diff --git a/roms/u-boot/common/cli_readline.c b/roms/u-boot/common/cli_readline.c
new file mode 100644
index 000000000..c7614a4c9
--- /dev/null
+++ b/roms/u-boot/common/cli_readline.c
@@ -0,0 +1,659 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Add to readline cmdline-editing by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
+ */
+
+#include <common.h>
+#include <bootretry.h>
+#include <cli.h>
+#include <command.h>
+#include <time.h>
+#include <watchdog.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char erase_seq[] = "\b \b"; /* erase sequence */
+static const char tab_seq[] = " "; /* used to expand TABs */
+
+char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
+
+static char *delete_char (char *buffer, char *p, int *colp, int *np, int plen)
+{
+ char *s;
+
+ if (*np == 0)
+ return p;
+
+ if (*(--p) == '\t') { /* will retype the whole line */
+ while (*colp > plen) {
+ puts(erase_seq);
+ (*colp)--;
+ }
+ for (s = buffer; s < p; ++s) {
+ if (*s == '\t') {
+ puts(tab_seq + ((*colp) & 07));
+ *colp += 8 - ((*colp) & 07);
+ } else {
+ ++(*colp);
+ putc(*s);
+ }
+ }
+ } else {
+ puts(erase_seq);
+ (*colp)--;
+ }
+ (*np)--;
+
+ return p;
+}
+
+#ifdef CONFIG_CMDLINE_EDITING
+
+/*
+ * cmdline-editing related codes from vivi.
+ * Author: Janghoon Lyu <nandy@mizi.com>
+ */
+
+#define putnstr(str, n) printf("%.*s", (int)n, str)
+
+#define CTL_CH(c) ((c) - 'a' + 1)
+#define CTL_BACKSPACE ('\b')
+#define DEL ((char)255)
+#define DEL7 ((char)127)
+#define CREAD_HIST_CHAR ('!')
+
+#define getcmd_putch(ch) putc(ch)
+#define getcmd_getch() getchar()
+#define getcmd_cbeep() getcmd_putch('\a')
+
+#define HIST_MAX 20
+#define HIST_SIZE CONFIG_SYS_CBSIZE
+
+static int hist_max;
+static int hist_add_idx;
+static int hist_cur = -1;
+static unsigned hist_num;
+
+static char *hist_list[HIST_MAX];
+static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
+
+#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
+
+static void hist_init(void)
+{
+ int i;
+
+ hist_max = 0;
+ hist_add_idx = 0;
+ hist_cur = -1;
+ hist_num = 0;
+
+ for (i = 0; i < HIST_MAX; i++) {
+ hist_list[i] = hist_lines[i];
+ hist_list[i][0] = '\0';
+ }
+}
+
+static void cread_add_to_hist(char *line)
+{
+ strcpy(hist_list[hist_add_idx], line);
+
+ if (++hist_add_idx >= HIST_MAX)
+ hist_add_idx = 0;
+
+ if (hist_add_idx > hist_max)
+ hist_max = hist_add_idx;
+
+ hist_num++;
+}
+
+static char *hist_prev(void)
+{
+ char *ret;
+ int old_cur;
+
+ if (hist_cur < 0)
+ return NULL;
+
+ old_cur = hist_cur;
+ if (--hist_cur < 0)
+ hist_cur = hist_max;
+
+ if (hist_cur == hist_add_idx) {
+ hist_cur = old_cur;
+ ret = NULL;
+ } else {
+ ret = hist_list[hist_cur];
+ }
+
+ return ret;
+}
+
+static char *hist_next(void)
+{
+ char *ret;
+
+ if (hist_cur < 0)
+ return NULL;
+
+ if (hist_cur == hist_add_idx)
+ return NULL;
+
+ if (++hist_cur > hist_max)
+ hist_cur = 0;
+
+ if (hist_cur == hist_add_idx)
+ ret = "";
+ else
+ ret = hist_list[hist_cur];
+
+ return ret;
+}
+
+#ifndef CONFIG_CMDLINE_EDITING
+static void cread_print_hist_list(void)
+{
+ int i;
+ unsigned long n;
+
+ n = hist_num - hist_max;
+
+ i = hist_add_idx + 1;
+ while (1) {
+ if (i > hist_max)
+ i = 0;
+ if (i == hist_add_idx)
+ break;
+ printf("%s\n", hist_list[i]);
+ n++;
+ i++;
+ }
+}
+#endif /* CONFIG_CMDLINE_EDITING */
+
+#define BEGINNING_OF_LINE() { \
+ while (num) { \
+ getcmd_putch(CTL_BACKSPACE); \
+ num--; \
+ } \
+}
+
+#define ERASE_TO_EOL() { \
+ if (num < eol_num) { \
+ printf("%*s", (int)(eol_num - num), ""); \
+ do { \
+ getcmd_putch(CTL_BACKSPACE); \
+ } while (--eol_num > num); \
+ } \
+}
+
+#define REFRESH_TO_EOL() { \
+ if (num < eol_num) { \
+ wlen = eol_num - num; \
+ putnstr(buf + num, wlen); \
+ num = eol_num; \
+ } \
+}
+
+static void cread_add_char(char ichar, int insert, unsigned long *num,
+ unsigned long *eol_num, char *buf, unsigned long len)
+{
+ unsigned long wlen;
+
+ /* room ??? */
+ if (insert || *num == *eol_num) {
+ if (*eol_num > len - 1) {
+ getcmd_cbeep();
+ return;
+ }
+ (*eol_num)++;
+ }
+
+ if (insert) {
+ wlen = *eol_num - *num;
+ if (wlen > 1)
+ memmove(&buf[*num+1], &buf[*num], wlen-1);
+
+ buf[*num] = ichar;
+ putnstr(buf + *num, wlen);
+ (*num)++;
+ while (--wlen)
+ getcmd_putch(CTL_BACKSPACE);
+ } else {
+ /* echo the character */
+ wlen = 1;
+ buf[*num] = ichar;
+ putnstr(buf + *num, wlen);
+ (*num)++;
+ }
+}
+
+static void cread_add_str(char *str, int strsize, int insert,
+ unsigned long *num, unsigned long *eol_num,
+ char *buf, unsigned long len)
+{
+ while (strsize--) {
+ cread_add_char(*str, insert, num, eol_num, buf, len);
+ str++;
+ }
+}
+
+static int cread_line(const char *const prompt, char *buf, unsigned int *len,
+ int timeout)
+{
+ unsigned long num = 0;
+ unsigned long eol_num = 0;
+ unsigned long wlen;
+ char ichar;
+ int insert = 1;
+ int esc_len = 0;
+ char esc_save[8];
+ int init_len = strlen(buf);
+ int first = 1;
+
+ if (init_len)
+ cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
+
+ while (1) {
+ if (bootretry_tstc_timeout())
+ return -2; /* timed out */
+ if (first && timeout) {
+ uint64_t etime = endtick(timeout);
+
+ while (!tstc()) { /* while no incoming data */
+ if (get_ticks() >= etime)
+ return -2; /* timed out */
+ WATCHDOG_RESET();
+ }
+ first = 0;
+ }
+
+ ichar = getcmd_getch();
+
+ /* ichar=0x0 when error occurs in U-Boot getc */
+ if (!ichar)
+ continue;
+
+ if ((ichar == '\n') || (ichar == '\r')) {
+ putc('\n');
+ break;
+ }
+
+ /*
+ * handle standard linux xterm esc sequences for arrow key, etc.
+ */
+ if (esc_len != 0) {
+ enum { ESC_REJECT, ESC_SAVE, ESC_CONVERTED } act = ESC_REJECT;
+
+ if (esc_len == 1) {
+ if (ichar == '[' || ichar == 'O')
+ act = ESC_SAVE;
+ } else if (esc_len == 2) {
+ switch (ichar) {
+ case 'D': /* <- key */
+ ichar = CTL_CH('b');
+ act = ESC_CONVERTED;
+ break; /* pass off to ^B handler */
+ case 'C': /* -> key */
+ ichar = CTL_CH('f');
+ act = ESC_CONVERTED;
+ break; /* pass off to ^F handler */
+ case 'H': /* Home key */
+ ichar = CTL_CH('a');
+ act = ESC_CONVERTED;
+ break; /* pass off to ^A handler */
+ case 'F': /* End key */
+ ichar = CTL_CH('e');
+ act = ESC_CONVERTED;
+ break; /* pass off to ^E handler */
+ case 'A': /* up arrow */
+ ichar = CTL_CH('p');
+ act = ESC_CONVERTED;
+ break; /* pass off to ^P handler */
+ case 'B': /* down arrow */
+ ichar = CTL_CH('n');
+ act = ESC_CONVERTED;
+ break; /* pass off to ^N handler */
+ case '1':
+ case '3':
+ case '4':
+ case '7':
+ case '8':
+ if (esc_save[1] == '[') {
+ /* see if next character is ~ */
+ act = ESC_SAVE;
+ }
+ break;
+ }
+ } else if (esc_len == 3) {
+ if (ichar == '~') {
+ switch (esc_save[2]) {
+ case '3': /* Delete key */
+ ichar = CTL_CH('d');
+ act = ESC_CONVERTED;
+ break; /* pass to ^D handler */
+ case '1': /* Home key */
+ case '7':
+ ichar = CTL_CH('a');
+ act = ESC_CONVERTED;
+ break; /* pass to ^A handler */
+ case '4': /* End key */
+ case '8':
+ ichar = CTL_CH('e');
+ act = ESC_CONVERTED;
+ break; /* pass to ^E handler */
+ }
+ }
+ }
+
+ switch (act) {
+ case ESC_SAVE:
+ esc_save[esc_len++] = ichar;
+ continue;
+ case ESC_REJECT:
+ esc_save[esc_len++] = ichar;
+ cread_add_str(esc_save, esc_len, insert,
+ &num, &eol_num, buf, *len);
+ esc_len = 0;
+ continue;
+ case ESC_CONVERTED:
+ esc_len = 0;
+ break;
+ }
+ }
+
+ switch (ichar) {
+ case 0x1b:
+ if (esc_len == 0) {
+ esc_save[esc_len] = ichar;
+ esc_len = 1;
+ } else {
+ puts("impossible condition #876\n");
+ esc_len = 0;
+ }
+ break;
+
+ case CTL_CH('a'):
+ BEGINNING_OF_LINE();
+ break;
+ case CTL_CH('c'): /* ^C - break */
+ *buf = '\0'; /* discard input */
+ return -1;
+ case CTL_CH('f'):
+ if (num < eol_num) {
+ getcmd_putch(buf[num]);
+ num++;
+ }
+ break;
+ case CTL_CH('b'):
+ if (num) {
+ getcmd_putch(CTL_BACKSPACE);
+ num--;
+ }
+ break;
+ case CTL_CH('d'):
+ if (num < eol_num) {
+ wlen = eol_num - num - 1;
+ if (wlen) {
+ memmove(&buf[num], &buf[num+1], wlen);
+ putnstr(buf + num, wlen);
+ }
+
+ getcmd_putch(' ');
+ do {
+ getcmd_putch(CTL_BACKSPACE);
+ } while (wlen--);
+ eol_num--;
+ }
+ break;
+ case CTL_CH('k'):
+ ERASE_TO_EOL();
+ break;
+ case CTL_CH('e'):
+ REFRESH_TO_EOL();
+ break;
+ case CTL_CH('o'):
+ insert = !insert;
+ break;
+ case CTL_CH('x'):
+ case CTL_CH('u'):
+ BEGINNING_OF_LINE();
+ ERASE_TO_EOL();
+ break;
+ case DEL:
+ case DEL7:
+ case 8:
+ if (num) {
+ wlen = eol_num - num;
+ num--;
+ memmove(&buf[num], &buf[num+1], wlen);
+ getcmd_putch(CTL_BACKSPACE);
+ putnstr(buf + num, wlen);
+ getcmd_putch(' ');
+ do {
+ getcmd_putch(CTL_BACKSPACE);
+ } while (wlen--);
+ eol_num--;
+ }
+ break;
+ case CTL_CH('p'):
+ case CTL_CH('n'):
+ {
+ char *hline;
+
+ esc_len = 0;
+
+ if (ichar == CTL_CH('p'))
+ hline = hist_prev();
+ else
+ hline = hist_next();
+
+ if (!hline) {
+ getcmd_cbeep();
+ continue;
+ }
+
+ /* nuke the current line */
+ /* first, go home */
+ BEGINNING_OF_LINE();
+
+ /* erase to end of line */
+ ERASE_TO_EOL();
+
+ /* copy new line into place and display */
+ strcpy(buf, hline);
+ eol_num = strlen(buf);
+ REFRESH_TO_EOL();
+ continue;
+ }
+#ifdef CONFIG_AUTO_COMPLETE
+ case '\t': {
+ int num2, col;
+
+ /* do not autocomplete when in the middle */
+ if (num < eol_num) {
+ getcmd_cbeep();
+ break;
+ }
+
+ buf[num] = '\0';
+ col = strlen(prompt) + eol_num;
+ num2 = num;
+ if (cmd_auto_complete(prompt, buf, &num2, &col)) {
+ col = num2 - num;
+ num += col;
+ eol_num += col;
+ }
+ break;
+ }
+#endif
+ default:
+ if (ichar >= ' ' && ichar <= '~') {
+ cread_add_char(ichar, insert, &num, &eol_num,
+ buf, *len);
+ }
+ break;
+ }
+ }
+ *len = eol_num;
+ buf[eol_num] = '\0'; /* lose the newline */
+
+ if (buf[0] && buf[0] != CREAD_HIST_CHAR)
+ cread_add_to_hist(buf);
+ hist_cur = hist_add_idx;
+
+ return 0;
+}
+
+#endif /* CONFIG_CMDLINE_EDITING */
+
+/****************************************************************************/
+
+int cli_readline(const char *const prompt)
+{
+ /*
+ * If console_buffer isn't 0-length the user will be prompted to modify
+ * it instead of entering it from scratch as desired.
+ */
+ console_buffer[0] = '\0';
+
+ return cli_readline_into_buffer(prompt, console_buffer, 0);
+}
+
+
+int cli_readline_into_buffer(const char *const prompt, char *buffer,
+ int timeout)
+{
+ char *p = buffer;
+#ifdef CONFIG_CMDLINE_EDITING
+ unsigned int len = CONFIG_SYS_CBSIZE;
+ int rc;
+ static int initted;
+
+ /*
+ * History uses a global array which is not
+ * writable until after relocation to RAM.
+ * Revert to non-history version if still
+ * running from flash.
+ */
+ if (gd->flags & GD_FLG_RELOC) {
+ if (!initted) {
+ hist_init();
+ initted = 1;
+ }
+
+ if (prompt)
+ puts(prompt);
+
+ rc = cread_line(prompt, p, &len, timeout);
+ return rc < 0 ? rc : len;
+
+ } else {
+#endif /* CONFIG_CMDLINE_EDITING */
+ char *p_buf = p;
+ int n = 0; /* buffer index */
+ int plen = 0; /* prompt length */
+ int col; /* output column cnt */
+ char c;
+
+ /* print prompt */
+ if (prompt) {
+ plen = strlen(prompt);
+ puts(prompt);
+ }
+ col = plen;
+
+ for (;;) {
+ if (bootretry_tstc_timeout())
+ return -2; /* timed out */
+ WATCHDOG_RESET(); /* Trigger watchdog, if needed */
+
+ c = getchar();
+
+ /*
+ * Special character handling
+ */
+ switch (c) {
+ case '\r': /* Enter */
+ case '\n':
+ *p = '\0';
+ puts("\r\n");
+ return p - p_buf;
+
+ case '\0': /* nul */
+ continue;
+
+ case 0x03: /* ^C - break */
+ p_buf[0] = '\0'; /* discard input */
+ return -1;
+
+ case 0x15: /* ^U - erase line */
+ while (col > plen) {
+ puts(erase_seq);
+ --col;
+ }
+ p = p_buf;
+ n = 0;
+ continue;
+
+ case 0x17: /* ^W - erase word */
+ p = delete_char(p_buf, p, &col, &n, plen);
+ while ((n > 0) && (*p != ' '))
+ p = delete_char(p_buf, p, &col, &n, plen);
+ continue;
+
+ case 0x08: /* ^H - backspace */
+ case 0x7F: /* DEL - backspace */
+ p = delete_char(p_buf, p, &col, &n, plen);
+ continue;
+
+ default:
+ /*
+ * Must be a normal character then
+ */
+ if (n < CONFIG_SYS_CBSIZE-2) {
+ if (c == '\t') { /* expand TABs */
+#ifdef CONFIG_AUTO_COMPLETE
+ /*
+ * if auto completion triggered just
+ * continue
+ */
+ *p = '\0';
+ if (cmd_auto_complete(prompt,
+ console_buffer,
+ &n, &col)) {
+ p = p_buf + n; /* reset */
+ continue;
+ }
+#endif
+ puts(tab_seq + (col & 07));
+ col += 8 - (col & 07);
+ } else {
+ char __maybe_unused buf[2];
+
+ /*
+ * Echo input using puts() to force an
+ * LCD flush if we are using an LCD
+ */
+ ++col;
+ buf[0] = c;
+ buf[1] = '\0';
+ puts(buf);
+ }
+ *p++ = c;
+ ++n;
+ } else { /* Buffer full */
+ putc('\a');
+ }
+ }
+ }
+#ifdef CONFIG_CMDLINE_EDITING
+ }
+#endif
+}
diff --git a/roms/u-boot/common/cli_simple.c b/roms/u-boot/common/cli_simple.c
new file mode 100644
index 000000000..e80ba488a
--- /dev/null
+++ b/roms/u-boot/common/cli_simple.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Add to readline cmdline-editing by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
+ */
+
+#include <common.h>
+#include <bootretry.h>
+#include <cli.h>
+#include <command.h>
+#include <console.h>
+#include <env.h>
+#include <log.h>
+#include <linux/ctype.h>
+
+#define DEBUG_PARSER 0 /* set to 1 to debug */
+
+#define debug_parser(fmt, args...) \
+ debug_cond(DEBUG_PARSER, fmt, ##args)
+
+
+int cli_simple_parse_line(char *line, char *argv[])
+{
+ int nargs = 0;
+
+ debug_parser("%s: \"%s\"\n", __func__, line);
+ while (nargs < CONFIG_SYS_MAXARGS) {
+ /* skip any white space */
+ while (isblank(*line))
+ ++line;
+
+ if (*line == '\0') { /* end of line, no more args */
+ argv[nargs] = NULL;
+ debug_parser("%s: nargs=%d\n", __func__, nargs);
+ return nargs;
+ }
+
+ argv[nargs++] = line; /* begin of argument string */
+
+ /* find end of string */
+ while (*line && !isblank(*line))
+ ++line;
+
+ if (*line == '\0') { /* end of line, no more args */
+ argv[nargs] = NULL;
+ debug_parser("parse_line: nargs=%d\n", nargs);
+ return nargs;
+ }
+
+ *line++ = '\0'; /* terminate current arg */
+ }
+
+ printf("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);
+
+ debug_parser("%s: nargs=%d\n", __func__, nargs);
+ return nargs;
+}
+
+int cli_simple_process_macros(const char *input, char *output, int max_size)
+{
+ char c, prev;
+ const char *varname_start = NULL;
+ int inputcnt = strlen(input);
+ int outputcnt = max_size;
+ int state = 0; /* 0 = waiting for '$' */
+ int ret;
+
+ /* 1 = waiting for '(' or '{' */
+ /* 2 = waiting for ')' or '}' */
+ /* 3 = waiting for ''' */
+ char __maybe_unused *output_start = output;
+
+ debug_parser("[PROCESS_MACROS] INPUT len %zd: \"%s\"\n", strlen(input),
+ input);
+
+ prev = '\0'; /* previous character */
+
+ while (inputcnt && outputcnt) {
+ c = *input++;
+ inputcnt--;
+
+ if (state != 3) {
+ /* remove one level of escape characters */
+ if ((c == '\\') && (prev != '\\')) {
+ if (inputcnt-- == 0)
+ break;
+ prev = c;
+ c = *input++;
+ }
+ }
+
+ switch (state) {
+ case 0: /* Waiting for (unescaped) $ */
+ if ((c == '\'') && (prev != '\\')) {
+ state = 3;
+ break;
+ }
+ if ((c == '$') && (prev != '\\')) {
+ state++;
+ } else {
+ *(output++) = c;
+ outputcnt--;
+ }
+ break;
+ case 1: /* Waiting for ( */
+ if (c == '(' || c == '{') {
+ state++;
+ varname_start = input;
+ } else {
+ state = 0;
+ *(output++) = '$';
+ outputcnt--;
+
+ if (outputcnt) {
+ *(output++) = c;
+ outputcnt--;
+ }
+ }
+ break;
+ case 2: /* Waiting for ) */
+ if (c == ')' || c == '}') {
+ int i;
+ char envname[CONFIG_SYS_CBSIZE], *envval;
+ /* Varname # of chars */
+ int envcnt = input - varname_start - 1;
+
+ /* Get the varname */
+ for (i = 0; i < envcnt; i++)
+ envname[i] = varname_start[i];
+ envname[i] = 0;
+
+ /* Get its value */
+ envval = env_get(envname);
+
+ /* Copy into the line if it exists */
+ if (envval != NULL)
+ while ((*envval) && outputcnt) {
+ *(output++) = *(envval++);
+ outputcnt--;
+ }
+ /* Look for another '$' */
+ state = 0;
+ }
+ break;
+ case 3: /* Waiting for ' */
+ if ((c == '\'') && (prev != '\\')) {
+ state = 0;
+ } else {
+ *(output++) = c;
+ outputcnt--;
+ }
+ break;
+ }
+ prev = c;
+ }
+
+ ret = inputcnt ? -ENOSPC : 0;
+ if (outputcnt) {
+ *output = 0;
+ } else {
+ *(output - 1) = 0;
+ ret = -ENOSPC;
+ }
+
+ debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n",
+ strlen(output_start), output_start);
+
+ return ret;
+}
+
+ /*
+ * WARNING:
+ *
+ * We must create a temporary copy of the command since the command we get
+ * may be the result from env_get(), which returns a pointer directly to
+ * the environment data, which may change magicly when the command we run
+ * creates or modifies environment variables (like "bootp" does).
+ */
+int cli_simple_run_command(const char *cmd, int flag)
+{
+ char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
+ char *token; /* start of token in cmdbuf */
+ char *sep; /* end of token (separator) in cmdbuf */
+ char finaltoken[CONFIG_SYS_CBSIZE];
+ char *str = cmdbuf;
+ char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
+ int argc, inquotes;
+ int repeatable = 1;
+ int rc = 0;
+
+ debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd);
+ if (DEBUG_PARSER) {
+ /* use puts - string may be loooong */
+ puts(cmd ? cmd : "NULL");
+ puts("\"\n");
+ }
+ clear_ctrlc(); /* forget any previous Control C */
+
+ if (!cmd || !*cmd)
+ return -1; /* empty command */
+
+ if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
+ puts("## Command too long!\n");
+ return -1;
+ }
+
+ strcpy(cmdbuf, cmd);
+
+ /* Process separators and check for invalid
+ * repeatable commands
+ */
+
+ debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);
+ while (*str) {
+ /*
+ * Find separator, or string end
+ * Allow simple escape of ';' by writing "\;"
+ */
+ for (inquotes = 0, sep = str; *sep; sep++) {
+ if ((*sep == '\'') &&
+ (*(sep - 1) != '\\'))
+ inquotes = !inquotes;
+
+ if (!inquotes &&
+ (*sep == ';') && /* separator */
+ (sep != str) && /* past string start */
+ (*(sep - 1) != '\\')) /* and NOT escaped */
+ break;
+ }
+
+ /*
+ * Limit the token to data between separators
+ */
+ token = str;
+ if (*sep) {
+ str = sep + 1; /* start of command for next pass */
+ *sep = '\0';
+ } else {
+ str = sep; /* no more commands for next pass */
+ }
+ debug_parser("token: \"%s\"\n", token);
+
+ /* find macros in this token and replace them */
+ cli_simple_process_macros(token, finaltoken,
+ sizeof(finaltoken));
+
+ /* Extract arguments */
+ argc = cli_simple_parse_line(finaltoken, argv);
+ if (argc == 0) {
+ rc = -1; /* no command at all */
+ continue;
+ }
+
+ if (cmd_process(flag, argc, argv, &repeatable, NULL))
+ rc = -1;
+
+ /* Did the user stop this? */
+ if (had_ctrlc())
+ return -1; /* if stopped then not repeatable */
+ }
+
+ return rc ? rc : repeatable;
+}
+
+void cli_simple_loop(void)
+{
+ static char lastcommand[CONFIG_SYS_CBSIZE + 1] = { 0, };
+
+ int len;
+ int flag;
+ int rc = 1;
+
+ for (;;) {
+ if (rc >= 0) {
+ /* Saw enough of a valid command to
+ * restart the timeout.
+ */
+ bootretry_reset_cmd_timeout();
+ }
+ len = cli_readline(CONFIG_SYS_PROMPT);
+
+ flag = 0; /* assume no special flags for now */
+ if (len > 0)
+ strlcpy(lastcommand, console_buffer,
+ CONFIG_SYS_CBSIZE + 1);
+ else if (len == 0)
+ flag |= CMD_FLAG_REPEAT;
+#ifdef CONFIG_BOOT_RETRY_TIME
+ else if (len == -2) {
+ /* -2 means timed out, retry autoboot
+ */
+ puts("\nTimed out waiting for command\n");
+# ifdef CONFIG_RESET_TO_RETRY
+ /* Reinit board to run initialization code again */
+ do_reset(NULL, 0, 0, NULL);
+# else
+ return; /* retry autoboot */
+# endif
+ }
+#endif
+
+ if (len == -1)
+ puts("<INTERRUPT>\n");
+ else
+ rc = run_command_repeatable(lastcommand, flag);
+
+ if (rc <= 0) {
+ /* invalid command or not repeatable, forget it */
+ lastcommand[0] = 0;
+ }
+ }
+}
+
+int cli_simple_run_command_list(char *cmd, int flag)
+{
+ char *line, *next;
+ int rcode = 0;
+
+ /*
+ * Break into individual lines, and execute each line; terminate on
+ * error.
+ */
+ next = cmd;
+ line = cmd;
+ while (*next) {
+ if (*next == '\n') {
+ *next = '\0';
+ /* run only non-empty commands */
+ if (*line) {
+ debug("** exec: \"%s\"\n", line);
+ if (cli_simple_run_command(line, 0) < 0) {
+ rcode = 1;
+ break;
+ }
+ }
+ line = next + 1;
+ }
+ ++next;
+ }
+ if (rcode == 0 && *line)
+ rcode = (cli_simple_run_command(line, 0) < 0);
+
+ return rcode;
+}
diff --git a/roms/u-boot/common/command.c b/roms/u-boot/common/command.c
new file mode 100644
index 000000000..95af73f17
--- /dev/null
+++ b/roms/u-boot/common/command.c
@@ -0,0 +1,656 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+/*
+ * Command Processor Table
+ */
+
+#include <common.h>
+#include <compiler.h>
+#include <command.h>
+#include <console.h>
+#include <env.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/ctype.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Use puts() instead of printf() to avoid printf buffer overflow
+ * for long help messages
+ */
+
+int _do_help(struct cmd_tbl *cmd_start, int cmd_items, struct cmd_tbl *cmdtp,
+ int flag, int argc, char *const argv[])
+{
+ int i;
+ int rcode = 0;
+
+ if (argc == 1) { /* show list of commands */
+ struct cmd_tbl *cmd_array[cmd_items];
+ int i, j, swaps;
+
+ /* Make array of commands from .uboot_cmd section */
+ cmdtp = cmd_start;
+ for (i = 0; i < cmd_items; i++) {
+ cmd_array[i] = cmdtp++;
+ }
+
+ /* Sort command list (trivial bubble sort) */
+ for (i = cmd_items - 1; i > 0; --i) {
+ swaps = 0;
+ for (j = 0; j < i; ++j) {
+ if (strcmp(cmd_array[j]->name,
+ cmd_array[j + 1]->name) > 0) {
+ struct cmd_tbl *tmp;
+ tmp = cmd_array[j];
+ cmd_array[j] = cmd_array[j + 1];
+ cmd_array[j + 1] = tmp;
+ ++swaps;
+ }
+ }
+ if (!swaps)
+ break;
+ }
+
+ /* print short help (usage) */
+ for (i = 0; i < cmd_items; i++) {
+ const char *usage = cmd_array[i]->usage;
+
+ /* allow user abort */
+ if (ctrlc())
+ return 1;
+ if (usage == NULL)
+ continue;
+ printf("%-*s- %s\n", CONFIG_SYS_HELP_CMD_WIDTH,
+ cmd_array[i]->name, usage);
+ }
+ return 0;
+ }
+ /*
+ * command help (long version)
+ */
+ for (i = 1; i < argc; ++i) {
+ cmdtp = find_cmd_tbl(argv[i], cmd_start, cmd_items);
+ if (cmdtp != NULL) {
+ rcode |= cmd_usage(cmdtp);
+ } else {
+ printf("Unknown command '%s' - try 'help' without arguments for list of all known commands\n\n",
+ argv[i]);
+ rcode = 1;
+ }
+ }
+ return rcode;
+}
+
+/* find command table entry for a command */
+struct cmd_tbl *find_cmd_tbl(const char *cmd, struct cmd_tbl *table,
+ int table_len)
+{
+#ifdef CONFIG_CMDLINE
+ struct cmd_tbl *cmdtp;
+ struct cmd_tbl *cmdtp_temp = table; /* Init value */
+ const char *p;
+ int len;
+ int n_found = 0;
+
+ if (!cmd)
+ return NULL;
+ /*
+ * Some commands allow length modifiers (like "cp.b");
+ * compare command name only until first dot.
+ */
+ len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
+
+ for (cmdtp = table; cmdtp != table + table_len; cmdtp++) {
+ if (strncmp(cmd, cmdtp->name, len) == 0) {
+ if (len == strlen(cmdtp->name))
+ return cmdtp; /* full match */
+
+ cmdtp_temp = cmdtp; /* abbreviated command ? */
+ n_found++;
+ }
+ }
+ if (n_found == 1) { /* exactly one match */
+ return cmdtp_temp;
+ }
+#endif /* CONFIG_CMDLINE */
+
+ return NULL; /* not found or ambiguous command */
+}
+
+struct cmd_tbl *find_cmd(const char *cmd)
+{
+ struct cmd_tbl *start = ll_entry_start(struct cmd_tbl, cmd);
+ const int len = ll_entry_count(struct cmd_tbl, cmd);
+ return find_cmd_tbl(cmd, start, len);
+}
+
+int cmd_usage(const struct cmd_tbl *cmdtp)
+{
+ printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);
+
+#ifdef CONFIG_SYS_LONGHELP
+ printf("Usage:\n%s ", cmdtp->name);
+
+ if (!cmdtp->help) {
+ puts ("- No additional help available.\n");
+ return 1;
+ }
+
+ puts(cmdtp->help);
+ putc('\n');
+#endif /* CONFIG_SYS_LONGHELP */
+ return 1;
+}
+
+#ifdef CONFIG_AUTO_COMPLETE
+static char env_complete_buf[512];
+
+int var_complete(int argc, char *const argv[], char last_char, int maxv,
+ char *cmdv[])
+{
+ int space;
+
+ space = last_char == '\0' || isblank(last_char);
+
+ if (space && argc == 1)
+ return env_complete("", maxv, cmdv, sizeof(env_complete_buf),
+ env_complete_buf, false);
+
+ if (!space && argc == 2)
+ return env_complete(argv[1], maxv, cmdv,
+ sizeof(env_complete_buf),
+ env_complete_buf, false);
+
+ return 0;
+}
+
+static int dollar_complete(int argc, char *const argv[], char last_char,
+ int maxv, char *cmdv[])
+{
+ /* Make sure the last argument starts with a $. */
+ if (argc < 1 || argv[argc - 1][0] != '$' ||
+ last_char == '\0' || isblank(last_char))
+ return 0;
+
+ return env_complete(argv[argc - 1], maxv, cmdv, sizeof(env_complete_buf),
+ env_complete_buf, true);
+}
+
+/*************************************************************************************/
+
+int complete_subcmdv(struct cmd_tbl *cmdtp, int count, int argc,
+ char *const argv[], char last_char,
+ int maxv, char *cmdv[])
+{
+#ifdef CONFIG_CMDLINE
+ const struct cmd_tbl *cmdend = cmdtp + count;
+ const char *p;
+ int len, clen;
+ int n_found = 0;
+ const char *cmd;
+
+ /* sanity? */
+ if (maxv < 2)
+ return -2;
+
+ cmdv[0] = NULL;
+
+ if (argc == 0) {
+ /* output full list of commands */
+ for (; cmdtp != cmdend; cmdtp++) {
+ if (n_found >= maxv - 2) {
+ cmdv[n_found++] = "...";
+ break;
+ }
+ cmdv[n_found++] = cmdtp->name;
+ }
+ cmdv[n_found] = NULL;
+ return n_found;
+ }
+
+ /* more than one arg or one but the start of the next */
+ if (argc > 1 || last_char == '\0' || isblank(last_char)) {
+ cmdtp = find_cmd_tbl(argv[0], cmdtp, count);
+ if (cmdtp == NULL || cmdtp->complete == NULL) {
+ cmdv[0] = NULL;
+ return 0;
+ }
+ return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
+ }
+
+ cmd = argv[0];
+ /*
+ * Some commands allow length modifiers (like "cp.b");
+ * compare command name only until first dot.
+ */
+ p = strchr(cmd, '.');
+ if (p == NULL)
+ len = strlen(cmd);
+ else
+ len = p - cmd;
+
+ /* return the partial matches */
+ for (; cmdtp != cmdend; cmdtp++) {
+
+ clen = strlen(cmdtp->name);
+ if (clen < len)
+ continue;
+
+ if (memcmp(cmd, cmdtp->name, len) != 0)
+ continue;
+
+ /* too many! */
+ if (n_found >= maxv - 2) {
+ cmdv[n_found++] = "...";
+ break;
+ }
+
+ cmdv[n_found++] = cmdtp->name;
+ }
+
+ cmdv[n_found] = NULL;
+ return n_found;
+#else
+ return 0;
+#endif
+}
+
+static int complete_cmdv(int argc, char *const argv[], char last_char,
+ int maxv, char *cmdv[])
+{
+#ifdef CONFIG_CMDLINE
+ return complete_subcmdv(ll_entry_start(struct cmd_tbl, cmd),
+ ll_entry_count(struct cmd_tbl, cmd), argc, argv,
+ last_char, maxv, cmdv);
+#else
+ return 0;
+#endif
+}
+
+static int make_argv(char *s, int argvsz, char *argv[])
+{
+ int argc = 0;
+
+ /* split into argv */
+ while (argc < argvsz - 1) {
+
+ /* skip any white space */
+ while (isblank(*s))
+ ++s;
+
+ if (*s == '\0') /* end of s, no more args */
+ break;
+
+ argv[argc++] = s; /* begin of argument string */
+
+ /* find end of string */
+ while (*s && !isblank(*s))
+ ++s;
+
+ if (*s == '\0') /* end of s, no more args */
+ break;
+
+ *s++ = '\0'; /* terminate current arg */
+ }
+ argv[argc] = NULL;
+
+ return argc;
+}
+
+static void print_argv(const char *banner, const char *leader, const char *sep,
+ int linemax, char *const argv[])
+{
+ int ll = leader != NULL ? strlen(leader) : 0;
+ int sl = sep != NULL ? strlen(sep) : 0;
+ int len, i;
+
+ if (banner) {
+ puts("\n");
+ puts(banner);
+ }
+
+ i = linemax; /* force leader and newline */
+ while (*argv != NULL) {
+ len = strlen(*argv) + sl;
+ if (i + len >= linemax) {
+ puts("\n");
+ if (leader)
+ puts(leader);
+ i = ll - sl;
+ } else if (sep)
+ puts(sep);
+ puts(*argv++);
+ i += len;
+ }
+ printf("\n");
+}
+
+static int find_common_prefix(char *const argv[])
+{
+ int i, len;
+ char *anchor, *s, *t;
+
+ if (*argv == NULL)
+ return 0;
+
+ /* begin with max */
+ anchor = *argv++;
+ len = strlen(anchor);
+ while ((t = *argv++) != NULL) {
+ s = anchor;
+ for (i = 0; i < len; i++, t++, s++) {
+ if (*t != *s)
+ break;
+ }
+ len = s - anchor;
+ }
+ return len;
+}
+
+static char tmp_buf[CONFIG_SYS_CBSIZE + 1]; /* copy of console I/O buffer */
+
+int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp)
+{
+ int n = *np, col = *colp;
+ char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
+ char *cmdv[20];
+ char *s, *t;
+ const char *sep;
+ int i, j, k, len, seplen, argc;
+ int cnt;
+ char last_char;
+#ifdef CONFIG_CMDLINE_PS_SUPPORT
+ const char *ps_prompt = env_get("PS1");
+#else
+ const char *ps_prompt = CONFIG_SYS_PROMPT;
+#endif
+
+ if (strcmp(prompt, ps_prompt) != 0)
+ return 0; /* not in normal console */
+
+ cnt = strlen(buf);
+ if (cnt >= 1)
+ last_char = buf[cnt - 1];
+ else
+ last_char = '\0';
+
+ /* copy to secondary buffer which will be affected */
+ strcpy(tmp_buf, buf);
+
+ /* separate into argv */
+ argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
+
+ /* first try a $ completion */
+ i = dollar_complete(argc, argv, last_char,
+ sizeof(cmdv) / sizeof(cmdv[0]), cmdv);
+ if (!i) {
+ /* do the completion and return the possible completions */
+ i = complete_cmdv(argc, argv, last_char,
+ sizeof(cmdv) / sizeof(cmdv[0]), cmdv);
+ }
+
+ /* no match; bell and out */
+ if (i == 0) {
+ if (argc > 1) /* allow tab for non command */
+ return 0;
+ putc('\a');
+ return 1;
+ }
+
+ s = NULL;
+ len = 0;
+ sep = NULL;
+ seplen = 0;
+ if (i == 1) { /* one match; perfect */
+ if (last_char != '\0' && !isblank(last_char))
+ k = strlen(argv[argc - 1]);
+ else
+ k = 0;
+
+ s = cmdv[0] + k;
+ len = strlen(s);
+ sep = " ";
+ seplen = 1;
+ } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
+ if (last_char != '\0' && !isblank(last_char))
+ k = strlen(argv[argc - 1]);
+ else
+ k = 0;
+
+ j -= k;
+ if (j > 0) {
+ s = cmdv[0] + k;
+ len = j;
+ }
+ }
+
+ if (s != NULL) {
+ k = len + seplen;
+ /* make sure it fits */
+ if (n + k >= CONFIG_SYS_CBSIZE - 2) {
+ putc('\a');
+ return 1;
+ }
+
+ t = buf + cnt;
+ for (i = 0; i < len; i++)
+ *t++ = *s++;
+ if (sep != NULL)
+ for (i = 0; i < seplen; i++)
+ *t++ = sep[i];
+ *t = '\0';
+ n += k;
+ col += k;
+ puts(t - k);
+ if (sep == NULL)
+ putc('\a');
+ *np = n;
+ *colp = col;
+ } else {
+ print_argv(NULL, " ", " ", 78, cmdv);
+
+ puts(prompt);
+ puts(buf);
+ }
+ return 1;
+}
+
+#endif
+
+#ifdef CMD_DATA_SIZE
+int cmd_get_data_size(char* arg, int default_size)
+{
+ /* Check for a size specification .b, .w or .l.
+ */
+ int len = strlen(arg);
+ if (len > 2 && arg[len-2] == '.') {
+ switch (arg[len-1]) {
+ case 'b':
+ return 1;
+ case 'w':
+ return 2;
+ case 'l':
+ return 4;
+ case 's':
+ return CMD_DATA_SIZE_STR;
+ case 'q':
+ if (MEM_SUPPORT_64BIT_DATA)
+ return 8;
+ /* no break */
+ default:
+ return CMD_DATA_SIZE_ERR;
+ }
+ }
+ return default_size;
+}
+#endif
+
+void fixup_cmdtable(struct cmd_tbl *cmdtp, int size)
+{
+ int i;
+
+ if (gd->reloc_off == 0)
+ return;
+
+ for (i = 0; i < size; i++) {
+ ulong addr;
+
+ addr = (ulong)(cmdtp->cmd_rep) + gd->reloc_off;
+ cmdtp->cmd_rep =
+ (int (*)(struct cmd_tbl *, int, int,
+ char * const [], int *))addr;
+
+ addr = (ulong)(cmdtp->cmd) + gd->reloc_off;
+#ifdef DEBUG_COMMANDS
+ printf("Command \"%s\": 0x%08lx => 0x%08lx\n",
+ cmdtp->name, (ulong)(cmdtp->cmd), addr);
+#endif
+ cmdtp->cmd = (int (*)(struct cmd_tbl *, int, int,
+ char *const []))addr;
+ addr = (ulong)(cmdtp->name) + gd->reloc_off;
+ cmdtp->name = (char *)addr;
+ if (cmdtp->usage) {
+ addr = (ulong)(cmdtp->usage) + gd->reloc_off;
+ cmdtp->usage = (char *)addr;
+ }
+#ifdef CONFIG_SYS_LONGHELP
+ if (cmdtp->help) {
+ addr = (ulong)(cmdtp->help) + gd->reloc_off;
+ cmdtp->help = (char *)addr;
+ }
+#endif
+#ifdef CONFIG_AUTO_COMPLETE
+ if (cmdtp->complete) {
+ addr = (ulong)(cmdtp->complete) + gd->reloc_off;
+ cmdtp->complete =
+ (int (*)(int, char * const [], char, int, char * []))addr;
+ }
+#endif
+ cmdtp++;
+ }
+}
+
+int cmd_always_repeatable(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], int *repeatable)
+{
+ *repeatable = 1;
+
+ return cmdtp->cmd(cmdtp, flag, argc, argv);
+}
+
+int cmd_never_repeatable(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], int *repeatable)
+{
+ *repeatable = 0;
+
+ return cmdtp->cmd(cmdtp, flag, argc, argv);
+}
+
+int cmd_discard_repeatable(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int repeatable;
+
+ return cmdtp->cmd_rep(cmdtp, flag, argc, argv, &repeatable);
+}
+
+/**
+ * Call a command function. This should be the only route in U-Boot to call
+ * a command, so that we can track whether we are waiting for input or
+ * executing a command.
+ *
+ * @param cmdtp Pointer to the command to execute
+ * @param flag Some flags normally 0 (see CMD_FLAG_.. above)
+ * @param argc Number of arguments (arg 0 must be the command text)
+ * @param argv Arguments
+ * @param repeatable Can the command be repeated
+ * @return 0 if command succeeded, else non-zero (CMD_RET_...)
+ */
+static int cmd_call(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], int *repeatable)
+{
+ int result;
+
+ result = cmdtp->cmd_rep(cmdtp, flag, argc, argv, repeatable);
+ if (result)
+ debug("Command failed, result=%d\n", result);
+ return result;
+}
+
+enum command_ret_t cmd_process(int flag, int argc, char *const argv[],
+ int *repeatable, ulong *ticks)
+{
+ enum command_ret_t rc = CMD_RET_SUCCESS;
+ struct cmd_tbl *cmdtp;
+
+#if defined(CONFIG_SYS_XTRACE)
+ char *xtrace;
+
+ xtrace = env_get("xtrace");
+ if (xtrace) {
+ puts("+");
+ for (int i = 0; i < argc; i++) {
+ puts(" ");
+ puts(argv[i]);
+ }
+ puts("\n");
+ }
+#endif
+
+ /* Look up command in command table */
+ cmdtp = find_cmd(argv[0]);
+ if (cmdtp == NULL) {
+ printf("Unknown command '%s' - try 'help'\n", argv[0]);
+ return 1;
+ }
+
+ /* found - check max args */
+ if (argc > cmdtp->maxargs)
+ rc = CMD_RET_USAGE;
+
+#if defined(CONFIG_CMD_BOOTD)
+ /* avoid "bootd" recursion */
+ else if (cmdtp->cmd == do_bootd) {
+ if (flag & CMD_FLAG_BOOTD) {
+ puts("'bootd' recursion detected\n");
+ rc = CMD_RET_FAILURE;
+ } else {
+ flag |= CMD_FLAG_BOOTD;
+ }
+ }
+#endif
+
+ /* If OK so far, then do the command */
+ if (!rc) {
+ int newrep;
+
+ if (ticks)
+ *ticks = get_timer(0);
+ rc = cmd_call(cmdtp, flag, argc, argv, &newrep);
+ if (ticks)
+ *ticks = get_timer(*ticks);
+ *repeatable &= newrep;
+ }
+ if (rc == CMD_RET_USAGE)
+ rc = cmd_usage(cmdtp);
+ return rc;
+}
+
+int cmd_process_error(struct cmd_tbl *cmdtp, int err)
+{
+ if (err == CMD_RET_USAGE)
+ return CMD_RET_USAGE;
+
+ if (err) {
+ printf("Command '%s' failed: Error %d\n", cmdtp->name, err);
+ return CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
diff --git a/roms/u-boot/common/common_fit.c b/roms/u-boot/common/common_fit.c
new file mode 100644
index 000000000..cde2dc45e
--- /dev/null
+++ b/roms/u-boot/common/common_fit.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <image.h>
+#include <log.h>
+#include <linux/libfdt.h>
+
+ulong fdt_getprop_u32(const void *fdt, int node, const char *prop)
+{
+ const u32 *cell;
+ int len;
+
+ cell = fdt_getprop(fdt, node, prop, &len);
+ if (!cell || len != sizeof(*cell))
+ return FDT_ERROR;
+
+ return fdt32_to_cpu(*cell);
+}
+
+__weak int board_fit_config_name_match(const char *name)
+{
+ return -EINVAL;
+}
+
+/*
+ * Iterate over all /configurations subnodes and call a platform specific
+ * function to find the matching configuration.
+ * Returns the node offset or a negative error number.
+ */
+int fit_find_config_node(const void *fdt)
+{
+ const char *name;
+ int conf, node, len;
+ const char *dflt_conf_name;
+ const char *dflt_conf_desc = NULL;
+ int dflt_conf_node = -ENOENT;
+
+ conf = fdt_path_offset(fdt, FIT_CONFS_PATH);
+ if (conf < 0) {
+ debug("%s: Cannot find /configurations node: %d\n", __func__,
+ conf);
+ return -EINVAL;
+ }
+
+ dflt_conf_name = fdt_getprop(fdt, conf, "default", &len);
+
+ for (node = fdt_first_subnode(fdt, conf);
+ node >= 0;
+ node = fdt_next_subnode(fdt, node)) {
+ name = fdt_getprop(fdt, node, "description", &len);
+ if (!name) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("%s: Missing FDT description in DTB\n",
+ __func__);
+#endif
+ return -EINVAL;
+ }
+
+ if (dflt_conf_name) {
+ const char *node_name = fdt_get_name(fdt, node, NULL);
+ if (strcmp(dflt_conf_name, node_name) == 0) {
+ dflt_conf_node = node;
+ dflt_conf_desc = name;
+ }
+ }
+
+ if (board_fit_config_name_match(name))
+ continue;
+
+ debug("Selecting config '%s'\n", name);
+
+ return node;
+ }
+
+ if (dflt_conf_node != -ENOENT) {
+ debug("Selecting default config '%s'\n", dflt_conf_desc);
+ return dflt_conf_node;
+ }
+
+ return -ENOENT;
+}
diff --git a/roms/u-boot/common/console.c b/roms/u-boot/common/console.c
new file mode 100644
index 000000000..561cdf36a
--- /dev/null
+++ b/roms/u-boot/common/console.c
@@ -0,0 +1,1097 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ */
+
+#include <common.h>
+#include <console.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <env.h>
+#include <stdarg.h>
+#include <iomux.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <os.h>
+#include <serial.h>
+#include <stdio_dev.h>
+#include <exports.h>
+#include <env_internal.h>
+#include <watchdog.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int on_console(const char *name, const char *value, enum env_op op,
+ int flags)
+{
+ int console = -1;
+
+ /* Check for console redirection */
+ if (strcmp(name, "stdin") == 0)
+ console = stdin;
+ else if (strcmp(name, "stdout") == 0)
+ console = stdout;
+ else if (strcmp(name, "stderr") == 0)
+ console = stderr;
+
+ /* if not actually setting a console variable, we don't care */
+ if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0)
+ return 0;
+
+ switch (op) {
+ case env_op_create:
+ case env_op_overwrite:
+
+ if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
+ if (iomux_doenv(console, value))
+ return 1;
+ } else {
+ /* Try assigning specified device */
+ if (console_assign(console, value) < 0)
+ return 1;
+ }
+
+ return 0;
+
+ case env_op_delete:
+ if ((flags & H_FORCE) == 0)
+ printf("Can't delete \"%s\"\n", name);
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+U_BOOT_ENV_CALLBACK(console, on_console);
+
+#ifdef CONFIG_SILENT_CONSOLE
+static int on_silent(const char *name, const char *value, enum env_op op,
+ int flags)
+{
+ if (!CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_SET))
+ if (flags & H_INTERACTIVE)
+ return 0;
+
+ if (!CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_RELOC))
+ if ((flags & H_INTERACTIVE) == 0)
+ return 0;
+
+ if (value != NULL)
+ gd->flags |= GD_FLG_SILENT;
+ else
+ gd->flags &= ~GD_FLG_SILENT;
+
+ return 0;
+}
+U_BOOT_ENV_CALLBACK(silent, on_silent);
+#endif
+
+#ifdef CONFIG_CONSOLE_RECORD
+/* helper function: access to gd->console_out and gd->console_in */
+static void console_record_putc(const char c)
+{
+ if (!(gd->flags & GD_FLG_RECORD))
+ return;
+ if (gd->console_out.start)
+ membuff_putbyte((struct membuff *)&gd->console_out, c);
+}
+
+static void console_record_puts(const char *s)
+{
+ if (!(gd->flags & GD_FLG_RECORD))
+ return;
+ if (gd->console_out.start)
+ membuff_put((struct membuff *)&gd->console_out, s, strlen(s));
+}
+
+static int console_record_getc(void)
+{
+ if (!(gd->flags & GD_FLG_RECORD))
+ return -1;
+ if (!gd->console_in.start)
+ return -1;
+
+ return membuff_getbyte((struct membuff *)&gd->console_in);
+}
+
+static int console_record_tstc(void)
+{
+ if (!(gd->flags & GD_FLG_RECORD))
+ return 0;
+ if (gd->console_in.start) {
+ if (membuff_peekbyte((struct membuff *)&gd->console_in) != -1)
+ return 1;
+ }
+ return 0;
+}
+#else
+static void console_record_putc(char c)
+{
+}
+
+static void console_record_puts(const char *s)
+{
+}
+
+static int console_record_getc(void)
+{
+ return -1;
+}
+
+static int console_record_tstc(void)
+{
+ return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
+/*
+ * if overwrite_console returns 1, the stdin, stderr and stdout
+ * are switched to the serial port, else the settings in the
+ * environment are used
+ */
+#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
+extern int overwrite_console(void);
+#define OVERWRITE_CONSOLE overwrite_console()
+#else
+#define OVERWRITE_CONSOLE 0
+#endif /* CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE */
+
+#endif /* CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */
+
+static int console_setfile(int file, struct stdio_dev * dev)
+{
+ int error = 0;
+
+ if (dev == NULL)
+ return -1;
+
+ switch (file) {
+ case stdin:
+ case stdout:
+ case stderr:
+ error = console_start(file, dev);
+ if (error)
+ break;
+
+ /* Assign the new device (leaving the existing one started) */
+ stdio_devices[file] = dev;
+
+ /*
+ * Update monitor functions
+ * (to use the console stuff by other applications)
+ */
+ switch (file) {
+ case stdin:
+ gd->jt->getc = getchar;
+ gd->jt->tstc = tstc;
+ break;
+ case stdout:
+ gd->jt->putc = putc;
+ gd->jt->puts = puts;
+ gd->jt->printf = printf;
+ break;
+ }
+ break;
+
+ default: /* Invalid file ID */
+ error = -1;
+ }
+ return error;
+}
+
+/**
+ * console_dev_is_serial() - Check if a stdio device is a serial device
+ *
+ * @sdev: Device to check
+ * @return true if this device is in the serial uclass (or for pre-driver-model,
+ * whether it is called "serial".
+ */
+static bool console_dev_is_serial(struct stdio_dev *sdev)
+{
+ bool is_serial;
+
+ if (IS_ENABLED(CONFIG_DM_SERIAL) && (sdev->flags & DEV_FLAGS_DM)) {
+ struct udevice *dev = sdev->priv;
+
+ is_serial = device_get_uclass_id(dev) == UCLASS_SERIAL;
+ } else {
+ is_serial = !strcmp(sdev->name, "serial");
+ }
+
+ return is_serial;
+}
+
+#if CONFIG_IS_ENABLED(CONSOLE_MUX)
+/** Console I/O multiplexing *******************************************/
+
+/* tstcdev: save the last stdio device with pending characters, with tstc != 0 */
+static struct stdio_dev *tstcdev;
+struct stdio_dev **console_devices[MAX_FILES];
+int cd_count[MAX_FILES];
+
+static void console_devices_set(int file, struct stdio_dev *dev)
+{
+ console_devices[file][0] = dev;
+ cd_count[file] = 1;
+}
+
+/**
+ * console_needs_start_stop() - check if we need to start or stop the STDIO device
+ * @file: STDIO file
+ * @sdev: STDIO device in question
+ *
+ * This function checks if we need to start or stop the stdio device used for
+ * a console. For IOMUX case it simply enforces one time start and one time
+ * stop of the device independently of how many STDIO files are using it. In
+ * other words, we start console once before first STDIO device wants it and
+ * stop after the last is gone.
+ */
+static bool console_needs_start_stop(int file, struct stdio_dev *sdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cd_count); i++) {
+ if (i == file)
+ continue;
+
+ if (iomux_match_device(console_devices[i], cd_count[i], sdev) >= 0)
+ return false;
+ }
+ return true;
+}
+
+/*
+ * This depends on tstc() always being called before getchar().
+ * This is guaranteed to be true because this routine is called
+ * only from fgetc() which assures it.
+ * No attempt is made to demultiplex multiple input sources.
+ */
+static int console_getc(int file)
+{
+ unsigned char ret;
+
+ /* This is never called with testcdev == NULL */
+ ret = tstcdev->getc(tstcdev);
+ tstcdev = NULL;
+ return ret;
+}
+
+/* Upper layer may have already called tstc(): check the saved result */
+static bool console_has_tstc(void)
+{
+ return !!tstcdev;
+}
+
+static int console_tstc(int file)
+{
+ int i, ret;
+ struct stdio_dev *dev;
+ int prev;
+
+ prev = disable_ctrlc(1);
+ for_each_console_dev(i, file, dev) {
+ if (dev->tstc != NULL) {
+ ret = dev->tstc(dev);
+ if (ret > 0) {
+ tstcdev = dev;
+ disable_ctrlc(prev);
+ return ret;
+ }
+ }
+ }
+ disable_ctrlc(prev);
+
+ return 0;
+}
+
+static void console_putc(int file, const char c)
+{
+ int i;
+ struct stdio_dev *dev;
+
+ for_each_console_dev(i, file, dev) {
+ if (dev->putc != NULL)
+ dev->putc(dev, c);
+ }
+}
+
+/**
+ * console_puts_select() - Output a string to all console devices
+ *
+ * @file: File number to output to (e,g, stdout, see stdio.h)
+ * @serial_only: true to output only to serial, false to output to everything
+ * else
+ * @s: String to output
+ */
+static void console_puts_select(int file, bool serial_only, const char *s)
+{
+ int i;
+ struct stdio_dev *dev;
+
+ for_each_console_dev(i, file, dev) {
+ bool is_serial = console_dev_is_serial(dev);
+
+ if (dev->puts && serial_only == is_serial)
+ dev->puts(dev, s);
+ }
+}
+
+void console_puts_select_stderr(bool serial_only, const char *s)
+{
+ console_puts_select(stderr, serial_only, s);
+}
+
+static void console_puts(int file, const char *s)
+{
+ int i;
+ struct stdio_dev *dev;
+
+ for_each_console_dev(i, file, dev) {
+ if (dev->puts != NULL)
+ dev->puts(dev, s);
+ }
+}
+
+#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
+static inline void console_doenv(int file, struct stdio_dev *dev)
+{
+ iomux_doenv(file, dev->name);
+}
+#endif
+#else
+
+static void console_devices_set(int file, struct stdio_dev *dev)
+{
+}
+
+static inline bool console_needs_start_stop(int file, struct stdio_dev *sdev)
+{
+ return true;
+}
+
+static inline int console_getc(int file)
+{
+ return stdio_devices[file]->getc(stdio_devices[file]);
+}
+
+static bool console_has_tstc(void)
+{
+ return false;
+}
+
+static inline int console_tstc(int file)
+{
+ return stdio_devices[file]->tstc(stdio_devices[file]);
+}
+
+static inline void console_putc(int file, const char c)
+{
+ stdio_devices[file]->putc(stdio_devices[file], c);
+}
+
+void console_puts_select(int file, bool serial_only, const char *s)
+{
+ if (serial_only == console_dev_is_serial(stdio_devices[file]))
+ stdio_devices[file]->puts(stdio_devices[file], s);
+}
+
+static inline void console_puts(int file, const char *s)
+{
+ stdio_devices[file]->puts(stdio_devices[file], s);
+}
+
+#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
+static inline void console_doenv(int file, struct stdio_dev *dev)
+{
+ console_setfile(file, dev);
+}
+#endif
+#endif /* CONIFIG_IS_ENABLED(CONSOLE_MUX) */
+
+static void __maybe_unused console_setfile_and_devices(int file, struct stdio_dev *dev)
+{
+ console_setfile(file, dev);
+ console_devices_set(file, dev);
+}
+
+int console_start(int file, struct stdio_dev *sdev)
+{
+ int error;
+
+ if (!console_needs_start_stop(file, sdev))
+ return 0;
+
+ /* Start new device */
+ if (sdev->start) {
+ error = sdev->start(sdev);
+ /* If it's not started don't use it */
+ if (error < 0)
+ return error;
+ }
+ return 0;
+}
+
+void console_stop(int file, struct stdio_dev *sdev)
+{
+ if (!console_needs_start_stop(file, sdev))
+ return;
+
+ if (sdev->stop)
+ sdev->stop(sdev);
+}
+
+/** U-Boot INITIAL CONSOLE-NOT COMPATIBLE FUNCTIONS *************************/
+
+int serial_printf(const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[CONFIG_SYS_PBSIZE];
+
+ va_start(args, fmt);
+
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
+ va_end(args);
+
+ serial_puts(printbuffer);
+ return i;
+}
+
+int fgetc(int file)
+{
+ if (file < MAX_FILES) {
+ /*
+ * Effectively poll for input wherever it may be available.
+ */
+ for (;;) {
+ WATCHDOG_RESET();
+ if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
+ /*
+ * Upper layer may have already called tstc() so
+ * check for that first.
+ */
+ if (console_has_tstc())
+ return console_getc(file);
+ console_tstc(file);
+ } else {
+ if (console_tstc(file))
+ return console_getc(file);
+ }
+
+ /*
+ * If the watchdog must be rate-limited then it should
+ * already be handled in board-specific code.
+ */
+ if (IS_ENABLED(CONFIG_WATCHDOG))
+ udelay(1);
+ }
+ }
+
+ return -1;
+}
+
+int ftstc(int file)
+{
+ if (file < MAX_FILES)
+ return console_tstc(file);
+
+ return -1;
+}
+
+void fputc(int file, const char c)
+{
+ if (file < MAX_FILES)
+ console_putc(file, c);
+}
+
+void fputs(int file, const char *s)
+{
+ if (file < MAX_FILES)
+ console_puts(file, s);
+}
+
+int fprintf(int file, const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[CONFIG_SYS_PBSIZE];
+
+ va_start(args, fmt);
+
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
+ va_end(args);
+
+ /* Send to desired file */
+ fputs(file, printbuffer);
+ return i;
+}
+
+/** U-Boot INITIAL CONSOLE-COMPATIBLE FUNCTION *****************************/
+
+int getchar(void)
+{
+ int ch;
+
+ if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
+ return 0;
+
+ if (!gd->have_console)
+ return 0;
+
+ ch = console_record_getc();
+ if (ch != -1)
+ return ch;
+
+ if (gd->flags & GD_FLG_DEVINIT) {
+ /* Get from the standard input */
+ return fgetc(stdin);
+ }
+
+ /* Send directly to the handler */
+ return serial_getc();
+}
+
+int tstc(void)
+{
+ if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
+ return 0;
+
+ if (!gd->have_console)
+ return 0;
+
+ if (console_record_tstc())
+ return 1;
+
+ if (gd->flags & GD_FLG_DEVINIT) {
+ /* Test the standard input */
+ return ftstc(stdin);
+ }
+
+ /* Send directly to the handler */
+ return serial_tstc();
+}
+
+#define PRE_CONSOLE_FLUSHPOINT1_SERIAL 0
+#define PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL 1
+
+#if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
+#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_PRE_CON_BUF_SZ)
+
+static void pre_console_putc(const char c)
+{
+ char *buffer;
+
+ buffer = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ);
+
+ buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c;
+
+ unmap_sysmem(buffer);
+}
+
+static void pre_console_puts(const char *s)
+{
+ while (*s)
+ pre_console_putc(*s++);
+}
+
+static void print_pre_console_buffer(int flushpoint)
+{
+ unsigned long in = 0, out = 0;
+ char buf_out[CONFIG_PRE_CON_BUF_SZ + 1];
+ char *buf_in;
+
+ if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
+ return;
+
+ buf_in = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ);
+ if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ)
+ in = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ;
+
+ while (in < gd->precon_buf_idx)
+ buf_out[out++] = buf_in[CIRC_BUF_IDX(in++)];
+ unmap_sysmem(buf_in);
+
+ buf_out[out] = 0;
+
+ switch (flushpoint) {
+ case PRE_CONSOLE_FLUSHPOINT1_SERIAL:
+ puts(buf_out);
+ break;
+ case PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL:
+ console_puts_select(stdout, false, buf_out);
+ break;
+ }
+}
+#else
+static inline void pre_console_putc(const char c) {}
+static inline void pre_console_puts(const char *s) {}
+static inline void print_pre_console_buffer(int flushpoint) {}
+#endif
+
+void putc(const char c)
+{
+ if (!gd)
+ return;
+
+ console_record_putc(c);
+
+ /* sandbox can send characters to stdout before it has a console */
+ if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
+ os_putc(c);
+ return;
+ }
+
+ /* if we don't have a console yet, use the debug UART */
+ if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) {
+ printch(c);
+ return;
+ }
+
+ if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) {
+ if (!(gd->flags & GD_FLG_DEVINIT))
+ pre_console_putc(c);
+ return;
+ }
+
+ if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
+ return;
+
+ if (!gd->have_console)
+ return pre_console_putc(c);
+
+ if (gd->flags & GD_FLG_DEVINIT) {
+ /* Send to the standard output */
+ fputc(stdout, c);
+ } else {
+ /* Send directly to the handler */
+ pre_console_putc(c);
+ serial_putc(c);
+ }
+}
+
+void puts(const char *s)
+{
+ if (!gd)
+ return;
+
+ console_record_puts(s);
+
+ /* sandbox can send characters to stdout before it has a console */
+ if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
+ os_puts(s);
+ return;
+ }
+
+ if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) {
+ while (*s) {
+ int ch = *s++;
+
+ printch(ch);
+ }
+ return;
+ }
+
+ if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) {
+ if (!(gd->flags & GD_FLG_DEVINIT))
+ pre_console_puts(s);
+ return;
+ }
+
+ if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
+ return;
+
+ if (!gd->have_console)
+ return pre_console_puts(s);
+
+ if (gd->flags & GD_FLG_DEVINIT) {
+ /* Send to the standard output */
+ fputs(stdout, s);
+ } else {
+ /* Send directly to the handler */
+ pre_console_puts(s);
+ serial_puts(s);
+ }
+}
+
+#ifdef CONFIG_CONSOLE_RECORD
+int console_record_init(void)
+{
+ int ret;
+
+ ret = membuff_new((struct membuff *)&gd->console_out,
+ CONFIG_CONSOLE_RECORD_OUT_SIZE);
+ if (ret)
+ return ret;
+ ret = membuff_new((struct membuff *)&gd->console_in,
+ CONFIG_CONSOLE_RECORD_IN_SIZE);
+
+ return ret;
+}
+
+void console_record_reset(void)
+{
+ membuff_purge((struct membuff *)&gd->console_out);
+ membuff_purge((struct membuff *)&gd->console_in);
+}
+
+int console_record_reset_enable(void)
+{
+ console_record_reset();
+ gd->flags |= GD_FLG_RECORD;
+
+ return 0;
+}
+
+int console_record_readline(char *str, int maxlen)
+{
+ return membuff_readline((struct membuff *)&gd->console_out, str,
+ maxlen, ' ');
+}
+
+int console_record_avail(void)
+{
+ return membuff_avail((struct membuff *)&gd->console_out);
+}
+
+#endif
+
+/* test if ctrl-c was pressed */
+static int ctrlc_disabled = 0; /* see disable_ctrl() */
+static int ctrlc_was_pressed = 0;
+int ctrlc(void)
+{
+ if (!ctrlc_disabled && gd->have_console) {
+ if (tstc()) {
+ switch (getchar()) {
+ case 0x03: /* ^C - Control C */
+ ctrlc_was_pressed = 1;
+ return 1;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+/* Reads user's confirmation.
+ Returns 1 if user's input is "y", "Y", "yes" or "YES"
+*/
+int confirm_yesno(void)
+{
+ int i;
+ char str_input[5];
+
+ /* Flush input */
+ while (tstc())
+ getchar();
+ i = 0;
+ while (i < sizeof(str_input)) {
+ str_input[i] = getchar();
+ putc(str_input[i]);
+ if (str_input[i] == '\r')
+ break;
+ i++;
+ }
+ putc('\n');
+ if (strncmp(str_input, "y\r", 2) == 0 ||
+ strncmp(str_input, "Y\r", 2) == 0 ||
+ strncmp(str_input, "yes\r", 4) == 0 ||
+ strncmp(str_input, "YES\r", 4) == 0)
+ return 1;
+ return 0;
+}
+/* pass 1 to disable ctrlc() checking, 0 to enable.
+ * returns previous state
+ */
+int disable_ctrlc(int disable)
+{
+ int prev = ctrlc_disabled; /* save previous state */
+
+ ctrlc_disabled = disable;
+ return prev;
+}
+
+int had_ctrlc (void)
+{
+ return ctrlc_was_pressed;
+}
+
+void clear_ctrlc(void)
+{
+ ctrlc_was_pressed = 0;
+}
+
+/** U-Boot INIT FUNCTIONS *************************************************/
+
+struct stdio_dev *console_search_dev(int flags, const char *name)
+{
+ struct stdio_dev *dev;
+
+ dev = stdio_get_by_name(name);
+#ifdef CONFIG_VIDCONSOLE_AS_LCD
+ if (!dev && !strcmp(name, CONFIG_VIDCONSOLE_AS_NAME))
+ dev = stdio_get_by_name("vidconsole");
+#endif
+
+ if (dev && (dev->flags & flags))
+ return dev;
+
+ return NULL;
+}
+
+int console_assign(int file, const char *devname)
+{
+ int flag;
+ struct stdio_dev *dev;
+
+ /* Check for valid file */
+ flag = stdio_file_to_flags(file);
+ if (flag < 0)
+ return flag;
+
+ /* Check for valid device name */
+
+ dev = console_search_dev(flag, devname);
+
+ if (dev)
+ return console_setfile(file, dev);
+
+ return -1;
+}
+
+/* return true if the 'silent' flag is removed */
+static bool console_update_silent(void)
+{
+ unsigned long flags = gd->flags;
+
+ if (!IS_ENABLED(CONFIG_SILENT_CONSOLE))
+ return false;
+
+ if (env_get("silent")) {
+ gd->flags |= GD_FLG_SILENT;
+ return false;
+ }
+
+ gd->flags &= ~GD_FLG_SILENT;
+
+ return !!(flags & GD_FLG_SILENT);
+}
+
+int console_announce_r(void)
+{
+#if !CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
+ char buf[DISPLAY_OPTIONS_BANNER_LENGTH];
+
+ display_options_get_banner(false, buf, sizeof(buf));
+
+ console_puts_select(stdout, false, buf);
+#endif
+
+ return 0;
+}
+
+/* Called before relocation - use serial functions */
+int console_init_f(void)
+{
+ gd->have_console = 1;
+
+ console_update_silent();
+
+ print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);
+
+ return 0;
+}
+
+void stdio_print_current_devices(void)
+{
+ /* Print information */
+ puts("In: ");
+ if (stdio_devices[stdin] == NULL) {
+ puts("No input devices available!\n");
+ } else {
+ printf ("%s\n", stdio_devices[stdin]->name);
+ }
+
+ puts("Out: ");
+ if (stdio_devices[stdout] == NULL) {
+ puts("No output devices available!\n");
+ } else {
+ printf ("%s\n", stdio_devices[stdout]->name);
+ }
+
+ puts("Err: ");
+ if (stdio_devices[stderr] == NULL) {
+ puts("No error devices available!\n");
+ } else {
+ printf ("%s\n", stdio_devices[stderr]->name);
+ }
+}
+
+#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
+/* Called after the relocation - use desired console functions */
+int console_init_r(void)
+{
+ char *stdinname, *stdoutname, *stderrname;
+ struct stdio_dev *inputdev = NULL, *outputdev = NULL, *errdev = NULL;
+ int i;
+ int iomux_err = 0;
+ int flushpoint;
+
+ /* update silent for env loaded from flash (initr_env) */
+ if (console_update_silent())
+ flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL;
+ else
+ flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL;
+
+ /* set default handlers at first */
+ gd->jt->getc = serial_getc;
+ gd->jt->tstc = serial_tstc;
+ gd->jt->putc = serial_putc;
+ gd->jt->puts = serial_puts;
+ gd->jt->printf = serial_printf;
+
+ /* stdin stdout and stderr are in environment */
+ /* scan for it */
+ stdinname = env_get("stdin");
+ stdoutname = env_get("stdout");
+ stderrname = env_get("stderr");
+
+ if (OVERWRITE_CONSOLE == 0) { /* if not overwritten by config switch */
+ inputdev = console_search_dev(DEV_FLAGS_INPUT, stdinname);
+ outputdev = console_search_dev(DEV_FLAGS_OUTPUT, stdoutname);
+ errdev = console_search_dev(DEV_FLAGS_OUTPUT, stderrname);
+ if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
+ iomux_err = iomux_doenv(stdin, stdinname);
+ iomux_err += iomux_doenv(stdout, stdoutname);
+ iomux_err += iomux_doenv(stderr, stderrname);
+ if (!iomux_err)
+ /* Successful, so skip all the code below. */
+ goto done;
+ }
+ }
+ /* if the devices are overwritten or not found, use default device */
+ if (inputdev == NULL) {
+ inputdev = console_search_dev(DEV_FLAGS_INPUT, "serial");
+ }
+ if (outputdev == NULL) {
+ outputdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
+ }
+ if (errdev == NULL) {
+ errdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
+ }
+ /* Initializes output console first */
+ if (outputdev != NULL) {
+ /* need to set a console if not done above. */
+ console_doenv(stdout, outputdev);
+ }
+ if (errdev != NULL) {
+ /* need to set a console if not done above. */
+ console_doenv(stderr, errdev);
+ }
+ if (inputdev != NULL) {
+ /* need to set a console if not done above. */
+ console_doenv(stdin, inputdev);
+ }
+
+done:
+
+ if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET))
+ stdio_print_current_devices();
+
+#ifdef CONFIG_VIDCONSOLE_AS_LCD
+ if (strstr(stdoutname, CONFIG_VIDCONSOLE_AS_NAME))
+ printf("Warning: Please change '%s' to 'vidconsole' in stdout/stderr environment vars\n",
+ CONFIG_VIDCONSOLE_AS_NAME);
+#endif
+
+ if (IS_ENABLED(CONFIG_SYS_CONSOLE_ENV_OVERWRITE)) {
+ /* set the environment variables (will overwrite previous env settings) */
+ for (i = 0; i < MAX_FILES; i++)
+ env_set(stdio_names[i], stdio_devices[i]->name);
+ }
+
+ gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
+
+ print_pre_console_buffer(flushpoint);
+ return 0;
+}
+
+#else /* !CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */
+
+/* Called after the relocation - use desired console functions */
+int console_init_r(void)
+{
+ struct stdio_dev *inputdev = NULL, *outputdev = NULL;
+ int i;
+ struct list_head *list = stdio_get_list();
+ struct list_head *pos;
+ struct stdio_dev *dev;
+ int flushpoint;
+
+ /* update silent for env loaded from flash (initr_env) */
+ if (console_update_silent())
+ flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL;
+ else
+ flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL;
+
+ /*
+ * suppress all output if splash screen is enabled and we have
+ * a bmp to display. We redirect the output from frame buffer
+ * console to serial console in this case or suppress it if
+ * "silent" mode was requested.
+ */
+ if (IS_ENABLED(CONFIG_SPLASH_SCREEN) && env_get("splashimage")) {
+ if (!(gd->flags & GD_FLG_SILENT))
+ outputdev = console_search_dev (DEV_FLAGS_OUTPUT, "serial");
+ }
+
+ /* Scan devices looking for input and output devices */
+ list_for_each(pos, list) {
+ dev = list_entry(pos, struct stdio_dev, list);
+
+ if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {
+ inputdev = dev;
+ }
+ if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {
+ outputdev = dev;
+ }
+ if(inputdev && outputdev)
+ break;
+ }
+
+ /* Initializes output console first */
+ if (outputdev != NULL) {
+ console_setfile_and_devices(stdout, outputdev);
+ console_setfile_and_devices(stderr, outputdev);
+ }
+
+ /* Initializes input console */
+ if (inputdev != NULL)
+ console_setfile_and_devices(stdin, inputdev);
+
+ if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET))
+ stdio_print_current_devices();
+
+ /* Setting environment variables */
+ for (i = 0; i < MAX_FILES; i++) {
+ env_set(stdio_names[i], stdio_devices[i]->name);
+ }
+
+ gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
+
+ print_pre_console_buffer(flushpoint);
+ return 0;
+}
+
+#endif /* CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */
diff --git a/roms/u-boot/common/cros_ec.c b/roms/u-boot/common/cros_ec.c
new file mode 100644
index 000000000..249d1f194
--- /dev/null
+++ b/roms/u-boot/common/cros_ec.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ */
+
+#include <common.h>
+#include <cros_ec.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+
+struct udevice *board_get_cros_ec_dev(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
+ if (ret) {
+ debug("%s: Error %d\n", __func__, ret);
+ return NULL;
+ }
+ return dev;
+}
diff --git a/roms/u-boot/common/ddr_spd.c b/roms/u-boot/common/ddr_spd.c
new file mode 100644
index 000000000..58dc9b378
--- /dev/null
+++ b/roms/u-boot/common/ddr_spd.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2008-2014 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <ddr_spd.h>
+
+/* used for ddr1 and ddr2 spd */
+static int
+spd_check(const u8 *buf, u8 spd_rev, u8 spd_cksum)
+{
+ unsigned int cksum = 0;
+ unsigned int i;
+
+ /*
+ * Check SPD revision supported
+ * Rev 1.X or less supported by this code
+ */
+ if (spd_rev >= 0x20) {
+ printf("SPD revision %02X not supported by this code\n",
+ spd_rev);
+ return 1;
+ }
+ if (spd_rev > 0x13) {
+ printf("SPD revision %02X not verified by this code\n",
+ spd_rev);
+ }
+
+ /*
+ * Calculate checksum
+ */
+ for (i = 0; i < 63; i++) {
+ cksum += *buf++;
+ }
+ cksum &= 0xFF;
+
+ if (cksum != spd_cksum) {
+ printf("SPD checksum unexpected. "
+ "Checksum in SPD = %02X, computed SPD = %02X\n",
+ spd_cksum, cksum);
+ return 1;
+ }
+
+ return 0;
+}
+
+unsigned int
+ddr1_spd_check(const ddr1_spd_eeprom_t *spd)
+{
+ const u8 *p = (const u8 *)spd;
+
+ return spd_check(p, spd->spd_rev, spd->cksum);
+}
+
+unsigned int
+ddr2_spd_check(const ddr2_spd_eeprom_t *spd)
+{
+ const u8 *p = (const u8 *)spd;
+
+ return spd_check(p, spd->spd_rev, spd->cksum);
+}
+
+/*
+ * CRC16 compute for DDR3 SPD
+ * Copied from DDR3 SPD spec.
+ */
+static int
+crc16(char *ptr, int count)
+{
+ int crc, i;
+
+ crc = 0;
+ while (--count >= 0) {
+ crc = crc ^ (int)*ptr++ << 8;
+ for (i = 0; i < 8; ++i)
+ if (crc & 0x8000)
+ crc = crc << 1 ^ 0x1021;
+ else
+ crc = crc << 1;
+ }
+ return crc & 0xffff;
+}
+
+unsigned int
+ddr3_spd_check(const ddr3_spd_eeprom_t *spd)
+{
+ char *p = (char *)spd;
+ int csum16;
+ int len;
+ char crc_lsb; /* byte 126 */
+ char crc_msb; /* byte 127 */
+
+ /*
+ * SPD byte0[7] - CRC coverage
+ * 0 = CRC covers bytes 0~125
+ * 1 = CRC covers bytes 0~116
+ */
+
+ len = !(spd->info_size_crc & 0x80) ? 126 : 117;
+ csum16 = crc16(p, len);
+
+ crc_lsb = (char) (csum16 & 0xff);
+ crc_msb = (char) (csum16 >> 8);
+
+ if (spd->crc[0] == crc_lsb && spd->crc[1] == crc_msb) {
+ return 0;
+ } else {
+ printf("SPD checksum unexpected.\n"
+ "Checksum lsb in SPD = %02X, computed SPD = %02X\n"
+ "Checksum msb in SPD = %02X, computed SPD = %02X\n",
+ spd->crc[0], crc_lsb, spd->crc[1], crc_msb);
+ return 1;
+ }
+}
+
+unsigned int ddr4_spd_check(const struct ddr4_spd_eeprom_s *spd)
+{
+ char *p = (char *)spd;
+ int csum16;
+ int len;
+ char crc_lsb; /* byte 126 */
+ char crc_msb; /* byte 127 */
+
+ len = 126;
+ csum16 = crc16(p, len);
+
+ crc_lsb = (char) (csum16 & 0xff);
+ crc_msb = (char) (csum16 >> 8);
+
+ if (spd->crc[0] != crc_lsb || spd->crc[1] != crc_msb) {
+ printf("SPD checksum unexpected.\n"
+ "Checksum lsb in SPD = %02X, computed SPD = %02X\n"
+ "Checksum msb in SPD = %02X, computed SPD = %02X\n",
+ spd->crc[0], crc_lsb, spd->crc[1], crc_msb);
+ return 1;
+ }
+
+ p = (char *)((ulong)spd + 128);
+ len = 126;
+ csum16 = crc16(p, len);
+
+ crc_lsb = (char) (csum16 & 0xff);
+ crc_msb = (char) (csum16 >> 8);
+
+ if (spd->mod_section.uc[126] != crc_lsb ||
+ spd->mod_section.uc[127] != crc_msb) {
+ printf("SPD checksum unexpected.\n"
+ "Checksum lsb in SPD = %02X, computed SPD = %02X\n"
+ "Checksum msb in SPD = %02X, computed SPD = %02X\n",
+ spd->mod_section.uc[126],
+ crc_lsb, spd->mod_section.uc[127],
+ crc_msb);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/roms/u-boot/common/dfu.c b/roms/u-boot/common/dfu.c
new file mode 100644
index 000000000..16bd1ba58
--- /dev/null
+++ b/roms/u-boot/common/dfu.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * dfu.c -- dfu command
+ *
+ * Copyright (C) 2015
+ * Lukasz Majewski <l.majewski@majess.pl>
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ * Lukasz Majewski <l.majewski@samsung.com>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <log.h>
+#include <watchdog.h>
+#include <dfu.h>
+#include <console.h>
+#include <g_dnl.h>
+#include <usb.h>
+#include <net.h>
+
+int run_usb_dnl_gadget(int usbctrl_index, char *usb_dnl_gadget)
+{
+ bool dfu_reset = false;
+ int ret, i = 0;
+
+ ret = usb_gadget_initialize(usbctrl_index);
+ if (ret) {
+ pr_err("usb_gadget_initialize failed\n");
+ return CMD_RET_FAILURE;
+ }
+ g_dnl_clear_detach();
+ ret = g_dnl_register(usb_dnl_gadget);
+ if (ret) {
+ pr_err("g_dnl_register failed");
+ return CMD_RET_FAILURE;
+ }
+
+#ifdef CONFIG_DFU_TIMEOUT
+ unsigned long start_time = get_timer(0);
+#endif
+
+ while (1) {
+ if (g_dnl_detach()) {
+ /*
+ * Check if USB bus reset is performed after detach,
+ * which indicates that -R switch has been passed to
+ * dfu-util. In this case reboot the device
+ */
+ if (dfu_usb_get_reset()) {
+ dfu_reset = true;
+ goto exit;
+ }
+
+ /*
+ * This extra number of usb_gadget_handle_interrupts()
+ * calls is necessary to assure correct transmission
+ * completion with dfu-util
+ */
+ if (++i == 10000)
+ goto exit;
+ }
+
+ if (ctrlc())
+ goto exit;
+
+ if (dfu_get_defer_flush()) {
+ /*
+ * Call to usb_gadget_handle_interrupts() is necessary
+ * to act on ZLP OUT transaction from HOST PC after
+ * transmitting the whole file.
+ *
+ * If this ZLP OUT packet is NAK'ed, the HOST libusb
+ * function fails after timeout (by default it is set to
+ * 5 seconds). In such situation the dfu-util program
+ * exits with error message.
+ */
+ usb_gadget_handle_interrupts(usbctrl_index);
+ ret = dfu_flush(dfu_get_defer_flush(), NULL, 0, 0);
+ dfu_set_defer_flush(NULL);
+ if (ret) {
+ pr_err("Deferred dfu_flush() failed!");
+ goto exit;
+ }
+ }
+
+#ifdef CONFIG_DFU_TIMEOUT
+ unsigned long wait_time = dfu_get_timeout();
+
+ if (wait_time) {
+ unsigned long current_time = get_timer(start_time);
+
+ if (current_time > wait_time) {
+ debug("Inactivity timeout, abort DFU\n");
+ goto exit;
+ }
+ }
+#endif
+
+ if (dfu_reinit_needed)
+ goto exit;
+
+ WATCHDOG_RESET();
+ usb_gadget_handle_interrupts(usbctrl_index);
+ }
+exit:
+ g_dnl_unregister();
+ usb_gadget_release(usbctrl_index);
+
+ if (dfu_reset)
+ do_reset(NULL, 0, 0, NULL);
+
+ g_dnl_clear_detach();
+
+ return ret;
+}
diff --git a/roms/u-boot/common/dlmalloc.c b/roms/u-boot/common/dlmalloc.c
new file mode 100644
index 000000000..11729e8c8
--- /dev/null
+++ b/roms/u-boot/common/dlmalloc.c
@@ -0,0 +1,2549 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This code is based on a version (aka dlmalloc) of malloc/free/realloc written
+ * by Doug Lea and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/-
+ *
+ * The original code is available at http://gee.cs.oswego.edu/pub/misc/
+ * as file malloc-2.6.6.c.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/global_data.h>
+
+#if CONFIG_IS_ENABLED(UNIT_TEST)
+#define DEBUG
+#endif
+
+#include <malloc.h>
+#include <asm/io.h>
+
+#ifdef DEBUG
+#if __STD_C
+static void malloc_update_mallinfo (void);
+void malloc_stats (void);
+#else
+static void malloc_update_mallinfo ();
+void malloc_stats();
+#endif
+#endif /* DEBUG */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ Emulation of sbrk for WIN32
+ All code within the ifdef WIN32 is untested by me.
+
+ Thanks to Martin Fong and others for supplying this.
+*/
+
+
+#ifdef WIN32
+
+#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
+~(malloc_getpagesize-1))
+#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1))
+
+/* resrve 64MB to insure large contiguous space */
+#define RESERVED_SIZE (1024*1024*64)
+#define NEXT_SIZE (2048*1024)
+#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
+
+struct GmListElement;
+typedef struct GmListElement GmListElement;
+
+struct GmListElement
+{
+ GmListElement* next;
+ void* base;
+};
+
+static GmListElement* head = 0;
+static unsigned int gNextAddress = 0;
+static unsigned int gAddressBase = 0;
+static unsigned int gAllocatedSize = 0;
+
+static
+GmListElement* makeGmListElement (void* bas)
+{
+ GmListElement* this;
+ this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
+ assert (this);
+ if (this)
+ {
+ this->base = bas;
+ this->next = head;
+ head = this;
+ }
+ return this;
+}
+
+void gcleanup ()
+{
+ BOOL rval;
+ assert ( (head == NULL) || (head->base == (void*)gAddressBase));
+ if (gAddressBase && (gNextAddress - gAddressBase))
+ {
+ rval = VirtualFree ((void*)gAddressBase,
+ gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ assert (rval);
+ }
+ while (head)
+ {
+ GmListElement* next = head->next;
+ rval = VirtualFree (head->base, 0, MEM_RELEASE);
+ assert (rval);
+ LocalFree (head);
+ head = next;
+ }
+}
+
+static
+void* findRegion (void* start_address, unsigned long size)
+{
+ MEMORY_BASIC_INFORMATION info;
+ if (size >= TOP_MEMORY) return NULL;
+
+ while ((unsigned long)start_address + size < TOP_MEMORY)
+ {
+ VirtualQuery (start_address, &info, sizeof (info));
+ if ((info.State == MEM_FREE) && (info.RegionSize >= size))
+ return start_address;
+ else
+ {
+ /* Requested region is not available so see if the */
+ /* next region is available. Set 'start_address' */
+ /* to the next region and call 'VirtualQuery()' */
+ /* again. */
+
+ start_address = (char*)info.BaseAddress + info.RegionSize;
+
+ /* Make sure we start looking for the next region */
+ /* on the *next* 64K boundary. Otherwise, even if */
+ /* the new region is free according to */
+ /* 'VirtualQuery()', the subsequent call to */
+ /* 'VirtualAlloc()' (which follows the call to */
+ /* this routine in 'wsbrk()') will round *down* */
+ /* the requested address to a 64K boundary which */
+ /* we already know is an address in the */
+ /* unavailable region. Thus, the subsequent call */
+ /* to 'VirtualAlloc()' will fail and bring us back */
+ /* here, causing us to go into an infinite loop. */
+
+ start_address =
+ (void *) AlignPage64K((unsigned long) start_address);
+ }
+ }
+ return NULL;
+
+}
+
+
+void* wsbrk (long size)
+{
+ void* tmp;
+ if (size > 0)
+ {
+ if (gAddressBase == 0)
+ {
+ gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
+ gNextAddress = gAddressBase =
+ (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
+ MEM_RESERVE, PAGE_NOACCESS);
+ } else if (AlignPage (gNextAddress + size) > (gAddressBase +
+gAllocatedSize))
+ {
+ long new_size = max (NEXT_SIZE, AlignPage (size));
+ void* new_address = (void*)(gAddressBase+gAllocatedSize);
+ do
+ {
+ new_address = findRegion (new_address, new_size);
+
+ if (!new_address)
+ return (void*)-1;
+
+ gAddressBase = gNextAddress =
+ (unsigned int)VirtualAlloc (new_address, new_size,
+ MEM_RESERVE, PAGE_NOACCESS);
+ /* repeat in case of race condition */
+ /* The region that we found has been snagged */
+ /* by another thread */
+ }
+ while (gAddressBase == 0);
+
+ assert (new_address == (void*)gAddressBase);
+
+ gAllocatedSize = new_size;
+
+ if (!makeGmListElement ((void*)gAddressBase))
+ return (void*)-1;
+ }
+ if ((size + gNextAddress) > AlignPage (gNextAddress))
+ {
+ void* res;
+ res = VirtualAlloc ((void*)AlignPage (gNextAddress),
+ (size + gNextAddress -
+ AlignPage (gNextAddress)),
+ MEM_COMMIT, PAGE_READWRITE);
+ if (!res)
+ return (void*)-1;
+ }
+ tmp = (void*)gNextAddress;
+ gNextAddress = (unsigned int)tmp + size;
+ return tmp;
+ }
+ else if (size < 0)
+ {
+ unsigned int alignedGoal = AlignPage (gNextAddress + size);
+ /* Trim by releasing the virtual memory */
+ if (alignedGoal >= gAddressBase)
+ {
+ VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
+ MEM_DECOMMIT);
+ gNextAddress = gNextAddress + size;
+ return (void*)gNextAddress;
+ }
+ else
+ {
+ VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ gNextAddress = gAddressBase;
+ return (void*)-1;
+ }
+ }
+ else
+ {
+ return (void*)gNextAddress;
+ }
+}
+
+#endif
+
+
+
+/*
+ Type declarations
+*/
+
+
+struct malloc_chunk
+{
+ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+} __attribute__((__may_alias__)) ;
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+
+ malloc_chunk details:
+
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ described in e.g., Knuth or Standish. (See the paper by Paul
+ Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+ survey of such techniques.) Sizes of free chunks are stored both
+ in the front of each chunk and at the end. This makes
+ consolidating fragmented chunks into bigger chunks very fast. The
+ size fields also hold bits representing whether chunks are free or
+ in use.
+
+ An allocated chunk looks like this:
+
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk, if allocated | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | User data starts here... .
+ . .
+ . (malloc_usable_space() bytes) .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ Where "chunk" is the front of the chunk for the purpose of most of
+ the malloc code, but "mem" is the pointer that is returned to the
+ user. "Nextchunk" is the beginning of the next contiguous chunk.
+
+ Chunks always begin on even word boundries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus double-word aligned.
+
+ Free chunks are stored in circular doubly-linked lists, and look like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ (The very first chunk allocated always has this bit set,
+ preventing access to non-existent (or non-owned) memory.)
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_size of the NEXT chunk. (This makes it easier to
+ deal with alignments etc).
+
+ The two exceptions to all this are
+
+ 1. The special chunk `top', which doesn't bother using the
+ trailing size field since there is no
+ next contiguous chunk that would have to index off it. (After
+ initialization, `top' is forced to always exist. If it would
+ become less than MINSIZE bytes long, it is replenished via
+ malloc_extend_top.)
+
+ 2. Chunks allocated via mmap, which have the second-lowest-order
+ bit (IS_MMAPPED) set in their size fields. Because they are
+ never merged or traversed from any other chunk, they have no
+ foot size or inuse information.
+
+ Available chunks are kept in any of several places (all declared below):
+
+ * `av': An array of chunks serving as bin headers for consolidated
+ chunks. Each bin is doubly linked. The bins are approximately
+ proportionally (log) spaced. There are a lot of these bins
+ (128). This may look excessive, but works very well in
+ practice. All procedures maintain the invariant that no
+ consolidated chunk physically borders another one. Chunks in
+ bins are kept in size order, with ties going to the
+ approximately least recently used chunk.
+
+ The chunks in each bin are maintained in decreasing sorted order by
+ size. This is irrelevant for the small bins, which all contain
+ the same-sized chunks, but facilitates best-fit allocation for
+ larger chunks. (These lists are just sequential. Keeping them in
+ order almost never requires enough traversal to warrant using
+ fancier ordered data structures.) Chunks of the same size are
+ linked with the most recently freed at the front, and allocations
+ are taken from the back. This results in LRU or FIFO allocation
+ order, which tends to give each chunk an equal opportunity to be
+ consolidated with adjacent freed chunks, resulting in larger free
+ chunks and less fragmentation.
+
+ * `top': The top-most available chunk (i.e., the one bordering the
+ end of available memory) is treated specially. It is never
+ included in any bin, is used only if no other chunk is
+ available, and is released back to the system if it is very
+ large (see M_TRIM_THRESHOLD).
+
+ * `last_remainder': A bin holding only the remainder of the
+ most recently split (non-top) chunk. This bin is checked
+ before other non-fitting chunks, so as to provide better
+ locality for runs of sequentially allocated chunks.
+
+ * Implicitly, through the host system's memory mapping tables.
+ If supported, requests greater than a threshold are usually
+ serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+/* sizes, alignments */
+
+#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
+#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ)
+#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
+#define MINSIZE (sizeof(struct malloc_chunk))
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* pad request bytes into a usable size */
+
+#define request2size(req) \
+ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
+ (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
+ (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+
+
+/*
+ Physical chunk operations
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+ ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+
+
+
+/*
+ Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+
+
+/*
+ Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s) ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+
+
+
+/*
+ Bins
+
+ The bins, `av_' are an array of pairs of pointers serving as the
+ heads of (initially empty) doubly-linked lists of chunks, laid out
+ in a way so that each pair can be treated as if it were in a
+ malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+ and chunks are the same).
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically
+ spaced. (See the table below.) The `av_' array is never mentioned
+ directly in the code, but instead via bin access macros.
+
+ Bin layout:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ There is actually a little bit of slop in the numbers in bin_index
+ for the sake of speed. This makes no difference elsewhere.
+
+ The special chunks `top' and `last_remainder' get their own bins,
+ (this is implemented via yet more trickery with the av_ array),
+ although `top' is never properly linked to its bin since it is
+ always handled specially.
+
+*/
+
+#define NAV 128 /* number of bins */
+
+typedef struct malloc_chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+ The first 2 bins are never indexed. The corresponding av_ cells are instead
+ used for bookkeeping. This is not to save space, but to simplify
+ indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top (av_[2]) /* The topmost chunk */
+#define last_remainder (bin_at(1)) /* remainder from last split */
+
+
+/*
+ Because top initially points to its own bin with initial
+ zero size, thus forcing extension on the first malloc request,
+ we avoid having any special code in malloc to check whether
+ it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i) bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ NULL, NULL,
+ IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
+ IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
+ IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
+ IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
+ IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
+ IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
+ IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
+ IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
+ IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
+ IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
+ IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
+ IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
+ IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+static void malloc_bin_reloc(void)
+{
+ mbinptr *p = &av_[2];
+ size_t i;
+
+ for (i = 2; i < ARRAY_SIZE(av_); ++i, ++p)
+ *p = (mbinptr)((ulong)*p + gd->reloc_off);
+}
+#else
+static inline void malloc_bin_reloc(void) {}
+#endif
+
+#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT
+static void malloc_init(void);
+#endif
+
+ulong mem_malloc_start = 0;
+ulong mem_malloc_end = 0;
+ulong mem_malloc_brk = 0;
+
+void *sbrk(ptrdiff_t increment)
+{
+ ulong old = mem_malloc_brk;
+ ulong new = old + increment;
+
+ /*
+ * if we are giving memory back make sure we clear it out since
+ * we set MORECORE_CLEARS to 1
+ */
+ if (increment < 0)
+ memset((void *)new, 0, -increment);
+
+ if ((new < mem_malloc_start) || (new > mem_malloc_end))
+ return (void *)MORECORE_FAILURE;
+
+ mem_malloc_brk = new;
+
+ return (void *)old;
+}
+
+void mem_malloc_init(ulong start, ulong size)
+{
+ mem_malloc_start = start;
+ mem_malloc_end = start + size;
+ mem_malloc_brk = start;
+
+#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT
+ malloc_init();
+#endif
+
+ debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start,
+ mem_malloc_end);
+#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT
+ memset((void *)mem_malloc_start, 0x0, size);
+#endif
+ malloc_bin_reloc();
+}
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/*
+ Indexing into bins
+*/
+
+#define bin_index(sz) \
+(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \
+ ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \
+ ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \
+ ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+ 126)
+/*
+ bins for chunks < 512 are all spaced 8 bytes apart, and hold
+ identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN 63
+#define MAX_SMALLBIN_SIZE 512
+#define SMALLBIN_WIDTH 8
+
+#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
+
+/*
+ Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+
+
+/*
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binblocks' is a
+ one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+ have any (possibly) non-empty bins, so they can be skipped over
+ all at once during during traversals. The bits are NOT always
+ cleared as soon as all bins in a block are empty, but instead only
+ when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH 4 /* bins per block */
+
+#define binblocks_r ((INTERNAL_SIZE_T)av_[1]) /* bitvector of nonempty blocks */
+#define binblocks_w (av_[1])
+
+/* bin<->block macros */
+
+#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii) (binblocks_w = (mbinptr)(binblocks_r | idx2binblock(ii)))
+#define clear_binblock(ii) (binblocks_w = (mbinptr)(binblocks_r & ~(idx2binblock(ii))))
+
+
+
+
+
+/* Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad = DEFAULT_TOP_PAD;
+static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+#ifdef DEBUG
+static unsigned int n_mmaps = 0;
+#endif /* DEBUG */
+static unsigned long mmapped_mem = 0;
+#if HAVE_MMAP
+static unsigned int max_n_mmaps = 0;
+static unsigned long max_mmapped_mem = 0;
+#endif
+
+#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT
+static void malloc_init(void)
+{
+ int i, j;
+
+ debug("bins (av_ array) are at %p\n", (void *)av_);
+
+ av_[0] = NULL; av_[1] = NULL;
+ for (i = 2, j = 2; i < NAV * 2 + 2; i += 2, j++) {
+ av_[i] = bin_at(j - 2);
+ av_[i + 1] = bin_at(j - 2);
+
+ /* Just print the first few bins so that
+ * we can see there are alright.
+ */
+ if (i < 10)
+ debug("av_[%d]=%lx av_[%d]=%lx\n",
+ i, (ulong)av_[i],
+ i + 1, (ulong)av_[i + 1]);
+ }
+
+ /* Init the static bookkeeping as well */
+ sbrk_base = (char *)(-1);
+ max_sbrked_mem = 0;
+ max_total_mem = 0;
+#ifdef DEBUG
+ memset((void *)&current_mallinfo, 0, sizeof(struct mallinfo));
+#endif
+}
+#endif
+
+/*
+ Debugging support
+*/
+
+#ifdef DEBUG
+
+
+/*
+ These routines make a number of assertions about the states
+ of data structures that should be true at all times. If any
+ are not true, it's very likely that a user program has somehow
+ trashed memory. (It's also possible that there is a coding error
+ in malloc. In which case, please report it!)
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+
+ /* No checkable chunk is mmapped */
+ assert(!chunk_is_mmapped(p));
+
+ /* Check for legal address ... */
+ assert((char*)p >= sbrk_base);
+ if (p != top)
+ assert((char*)p + sz <= (char*)top);
+ else
+ assert((char*)p + sz <= sbrk_base + sbrked_mem);
+
+}
+
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ mchunkptr next = chunk_at_offset(p, sz);
+
+ do_check_chunk(p);
+
+ /* Check whether it claims to be free ... */
+ assert(!inuse(p));
+
+ /* Unless a special marker, must have OK fields */
+ if ((long)sz >= (long)MINSIZE)
+ {
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(aligned_OK(chunk2mem(p)));
+ /* ... matching footer field */
+ assert(next->prev_size == sz);
+ /* ... and is fully consolidated */
+ assert(prev_inuse(p));
+ assert (next == top || inuse(next));
+
+ /* ... and has minimally sane links */
+ assert(p->fd->bk == p);
+ assert(p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_SZ */
+ assert(sz == SIZE_SZ);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+ mchunkptr next = next_chunk(p);
+ do_check_chunk(p);
+
+ /* Check whether it claims to be in use ... */
+ assert(inuse(p));
+
+ /* ... and is surrounded by OK chunks.
+ Since more things can be checked with free chunks than inuse ones,
+ if an inuse chunk borders them and debug is on, it's worth doing them.
+ */
+ if (!prev_inuse(p))
+ {
+ mchunkptr prv = prev_chunk(p);
+ assert(next_chunk(prv) == p);
+ do_check_free_chunk(prv);
+ }
+ if (next == top)
+ {
+ assert(prev_inuse(next));
+ assert(chunksize(next) >= MINSIZE);
+ }
+ else if (!inuse(next))
+ do_check_free_chunk(next);
+
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ long room = sz - s;
+
+ do_check_inuse_chunk(p);
+
+ /* Legal size ... */
+ assert((long)sz >= (long)MINSIZE);
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(room >= 0);
+ assert(room < (long)MINSIZE);
+
+ /* ... and alignment */
+ assert(aligned_OK(chunk2mem(p)));
+
+
+ /* ... and was allocated at front of an available chunk */
+ assert(prev_inuse(p));
+
+}
+
+
+#define check_free_chunk(P) do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif
+
+
+
+/*
+ Macro-based internal utilities
+*/
+
+
+/*
+ Linking chunks in bin lists.
+ Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+ Place chunk p of size s in its bin, in size order,
+ putting it ahead of others of same size.
+*/
+
+
+#define frontlink(P, S, IDX, BK, FD) \
+{ \
+ if (S < MAX_SMALLBIN_SIZE) \
+ { \
+ IDX = smallbin_index(S); \
+ mark_binblock(IDX); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+ else \
+ { \
+ IDX = bin_index(S); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ if (FD == BK) mark_binblock(IDX); \
+ else \
+ { \
+ while (FD != BK && S < chunksize(FD)) FD = FD->fd; \
+ BK = FD->bk; \
+ } \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+}
+
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD) \
+{ \
+ BK = P->bk; \
+ FD = P->fd; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+} \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P) \
+{ \
+ last_remainder->fd = last_remainder->bk = P; \
+ P->fd = P->bk = last_remainder; \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+ (last_remainder->fd = last_remainder->bk = last_remainder)
+
+
+
+
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+ static int fd = -1;
+#endif
+
+ if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+ /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
+ * there is no following chunk whose prev_size field could be used.
+ */
+ size = (size + SIZE_SZ + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+ if (fd < 0)
+ {
+ fd = open("/dev/zero", O_RDWR);
+ if(fd < 0) return 0;
+ }
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+ if(p == (mchunkptr)-1) return 0;
+
+ n_mmaps++;
+ if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+ /* We demand that eight bytes into a page must be 8-byte aligned. */
+ assert(aligned_OK(chunk2mem(p)));
+
+ /* The offset to the start of the mmapped region is stored
+ * in the prev_size field of the chunk; normally it is zero,
+ * but that can be changed in memalign().
+ */
+ p->prev_size = 0;
+ set_head(p, size|IS_MMAPPED);
+
+ mmapped_mem += size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T size = chunksize(p);
+ int ret;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+ n_mmaps--;
+ mmapped_mem -= (size + p->prev_size);
+
+ ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ INTERNAL_SIZE_T offset = p->prev_size;
+ INTERNAL_SIZE_T size = chunksize(p);
+ char *cp;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+ /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+ new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
+
+ cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+ if (cp == (char *)-1) return 0;
+
+ p = (mchunkptr)(cp + offset);
+
+ assert(aligned_OK(chunk2mem(p)));
+
+ assert((p->prev_size == offset));
+ set_head(p, (new_size - offset)|IS_MMAPPED);
+
+ mmapped_mem -= size + offset;
+ mmapped_mem += new_size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+/*
+ Extend the top-most chunk by obtaining memory from system.
+ Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+ char* brk; /* return value from sbrk */
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+ INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */
+ char* new_brk; /* return of 2nd sbrk call */
+ INTERNAL_SIZE_T top_size; /* new size of top chunk */
+
+ mchunkptr old_top = top; /* Record state of old top */
+ INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+ char* old_end = (char*)(chunk_at_offset(old_top, old_top_size));
+
+ /* Pad request with top_pad plus minimal overhead */
+
+ INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE;
+ unsigned long pagesz = malloc_getpagesize;
+
+ /* If not the first time through, round to preserve page boundary */
+ /* Otherwise, we need to correct to a page size below anyway. */
+ /* (We also correct below if an intervening foreign sbrk call.) */
+
+ if (sbrk_base != (char*)(-1))
+ sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+ brk = (char*)(MORECORE (sbrk_size));
+
+ /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+ if (brk == (char*)(MORECORE_FAILURE) ||
+ (brk < old_end && old_top != initial_top))
+ return;
+
+ sbrked_mem += sbrk_size;
+
+ if (brk == old_end) /* can just add bytes to current top */
+ {
+ top_size = sbrk_size + old_top_size;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ else
+ {
+ if (sbrk_base == (char*)(-1)) /* First time through. Record base */
+ sbrk_base = brk;
+ else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */
+ sbrked_mem += brk - (char*)old_end;
+
+ /* Guarantee alignment of first new chunk made from this space */
+ front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0)
+ {
+ correction = (MALLOC_ALIGNMENT) - front_misalign;
+ brk += correction;
+ }
+ else
+ correction = 0;
+
+ /* Guarantee the next brk will be at a page boundary */
+
+ correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) &
+ ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size));
+
+ /* Allocate correction */
+ new_brk = (char*)(MORECORE (correction));
+ if (new_brk == (char*)(MORECORE_FAILURE)) return;
+
+ sbrked_mem += correction;
+
+ top = (mchunkptr)brk;
+ top_size = new_brk - brk + correction;
+ set_head(top, top_size | PREV_INUSE);
+
+ if (old_top != initial_top)
+ {
+
+ /* There must have been an intervening foreign sbrk call. */
+ /* A double fencepost is necessary to prevent consolidation */
+
+ /* If not enough space to do this, then user did something very wrong */
+ if (old_top_size < MINSIZE)
+ {
+ set_head(top, PREV_INUSE); /* will force null return from malloc */
+ return;
+ }
+
+ /* Also keep size a multiple of MALLOC_ALIGNMENT */
+ old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+ set_head_size(old_top, old_top_size);
+ chunk_at_offset(old_top, old_top_size )->size =
+ SIZE_SZ|PREV_INUSE;
+ chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+ SIZE_SZ|PREV_INUSE;
+ /* If possible, release the rest. */
+ if (old_top_size >= MINSIZE)
+ fREe(chunk2mem(old_top));
+ }
+ }
+
+ if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+ max_sbrked_mem = sbrked_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+
+ /* We always land on a page boundary */
+ assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+
+
+
+/* Main public routines */
+
+
+/*
+ Malloc Algorthim:
+
+ The requested size is first converted into a usable form, `nb'.
+ This currently means to add 4 bytes overhead plus possibly more to
+ obtain 8-byte alignment and/or to obtain a size of at least
+ MINSIZE (currently 16 bytes), the smallest allocatable size.
+ (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+ From there, the first successful of the following steps is taken:
+
+ 1. The bin corresponding to the request size is scanned, and if
+ a chunk of exactly the right size is found, it is taken.
+
+ 2. The most recently remaindered chunk is used if it is big
+ enough. This is a form of (roving) first fit, used only in
+ the absence of exact fits. Runs of consecutive requests use
+ the remainder of the chunk used for the previous such request
+ whenever possible. This limited use of a first-fit style
+ allocation strategy tends to give contiguous chunks
+ coextensive lifetimes, which improves locality and can reduce
+ fragmentation in the long run.
+
+ 3. Other bins are scanned in increasing size order, using a
+ chunk big enough to fulfill the request, and splitting off
+ any remainder. This search is strictly by best-fit; i.e.,
+ the smallest (with ties going to approximately the least
+ recently used) chunk that fits is selected.
+
+ 4. If large enough, the chunk bordering the end of memory
+ (`top') is split off. (This use of `top' is in accord with
+ the best-fit search rule. In effect, `top' is treated as
+ larger (and thus less well fitting) than any other available
+ chunk since it can be extended to be as large as necessary
+ (up to system limitations).
+
+ 5. If the request size meets the mmap threshold and the
+ system supports mmap, and there are few enough currently
+ allocated mmapped regions, and a call to mmap succeeds,
+ the request is allocated via direct memory mapping.
+
+ 6. Otherwise, the top of memory is extended by
+ obtaining more space from the system (normally using sbrk,
+ but definable to anything else via the MORECORE macro).
+ Memory is gathered from the system (in system page-sized
+ units) in a way that allows chunks obtained across different
+ sbrk calls to be consolidated, but does not require
+ contiguous memory. Thus, it should be safe to intersperse
+ mallocs with other sbrk calls.
+
+
+ All allocations are made from the the `lowest' part of any found
+ chunk. (The implementation invariant is that prev_inuse is
+ always true of any allocated chunk; i.e., that each allocated
+ chunk borders either a previously allocated and still in-use chunk,
+ or the base of its memory arena.)
+
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mchunkptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T victim_size; /* its size */
+ int idx; /* index for bin traversal */
+ mbinptr bin; /* associated bin */
+ mchunkptr remainder; /* remainder from a split */
+ long remainder_size; /* its size */
+ int remainder_index; /* its bin index */
+ unsigned long block; /* block traverser bit */
+ int startidx; /* first bin of a traversed block */
+ mchunkptr fwd; /* misc temp for linking */
+ mchunkptr bck; /* misc temp for linking */
+ mbinptr q; /* misc temp */
+
+ INTERNAL_SIZE_T nb;
+
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT))
+ return malloc_simple(bytes);
+#endif
+
+ /* check if mem_malloc_init() was run */
+ if ((mem_malloc_start == 0) && (mem_malloc_end == 0)) {
+ /* not initialized yet */
+ return NULL;
+ }
+
+ if ((long)bytes < 0) return NULL;
+
+ nb = request2size(bytes); /* padded request size; */
+
+ /* Check for exact match in a bin */
+
+ if (is_small_request(nb)) /* Faster version for small requests */
+ {
+ idx = smallbin_index(nb);
+
+ /* No traversal or size check necessary for small bins. */
+
+ q = bin_at(idx);
+ victim = last(q);
+
+ /* Also scan the next one, since it would have a remainder < MINSIZE */
+ if (victim == q)
+ {
+ q = next_bin(q);
+ victim = last(q);
+ }
+ if (victim != q)
+ {
+ victim_size = chunksize(victim);
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+ }
+ else
+ {
+ idx = bin_index(nb);
+ bin = bin_at(idx);
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* too big */
+ {
+ --idx; /* adjust to rescan below after checking last remainder */
+ break;
+ }
+
+ else if (remainder_size >= 0) /* exact fit */
+ {
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+
+ ++idx;
+
+ }
+
+ /* Try to use the last split-off remainder */
+
+ if ( (victim = last_remainder->fd) != last_remainder)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* re-split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ clear_last_remainder;
+
+ if (remainder_size >= 0) /* exhaust */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* Else place in bin */
+
+ frontlink(victim, victim_size, remainder_index, bck, fwd);
+ }
+
+ /*
+ If there are any possibly nonempty big-enough blocks,
+ search for best fitting chunk by scanning bins in blockwidth units.
+ */
+
+ if ( (block = idx2binblock(idx)) <= binblocks_r)
+ {
+
+ /* Get to the first marked block */
+
+ if ( (block & binblocks_r) == 0)
+ {
+ /* force to an even block boundary */
+ idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+ block <<= 1;
+ while ((block & binblocks_r) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+
+ /* For each possibly nonempty block ... */
+ for (;;)
+ {
+ startidx = idx; /* (track incomplete blocks) */
+ q = bin = bin_at(idx);
+
+ /* For each bin in this block ... */
+ do
+ {
+ /* Find and use first big enough chunk ... */
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ unlink(victim, bck, fwd);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ else if (remainder_size >= 0) /* take */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ unlink(victim, bck, fwd);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ }
+
+ bin = next_bin(bin);
+
+ } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+ /* Clear out the block bit. */
+
+ do /* Possibly backtrack to try to clear a partial block */
+ {
+ if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+ {
+ av_[1] = (mbinptr)(binblocks_r & ~block);
+ break;
+ }
+ --startidx;
+ q = prev_bin(q);
+ } while (first(q) == q);
+
+ /* Get to the next possibly nonempty block */
+
+ if ( (block <<= 1) <= binblocks_r && (block != 0) )
+ {
+ while ((block & binblocks_r) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+
+ /* Try to use top chunk */
+
+ /* Require that there be a remainder, ensuring top always exists */
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ {
+
+#if HAVE_MMAP
+ /* If big and would otherwise need to extend, try to use mmap instead */
+ if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+ (victim = mmap_chunk(nb)))
+ return chunk2mem(victim);
+#endif
+
+ /* Try to extend */
+ malloc_extend_top(nb);
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ return NULL; /* propagate failure */
+ }
+
+ victim = top;
+ set_head(victim, nb | PREV_INUSE);
+ top = chunk_at_offset(victim, nb);
+ set_head(top, remainder_size | PREV_INUSE);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+
+}
+
+
+
+
+/*
+
+ free() algorithm :
+
+ cases:
+
+ 1. free(0) has no effect.
+
+ 2. If the chunk was allocated via mmap, it is release via munmap().
+
+ 3. If a returned chunk borders the current high end of memory,
+ it is consolidated into the top, and if the total unused
+ topmost memory exceeds the trim threshold, malloc_trim is
+ called.
+
+ 4. Other chunks are consolidated as they arrive, and
+ placed in corresponding bins. (This includes the case of
+ consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T hd; /* its head field */
+ INTERNAL_SIZE_T sz; /* its size */
+ int idx; /* its bin index */
+ mchunkptr next; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsz; /* its size */
+ INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+ int islr; /* track whether merging with last_remainder */
+
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ /* free() is a no-op - all the memory will be freed on relocation */
+ if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT))
+ return;
+#endif
+
+ if (mem == NULL) /* free(0) has no effect */
+ return;
+
+ p = mem2chunk(mem);
+ hd = p->size;
+
+#if HAVE_MMAP
+ if (hd & IS_MMAPPED) /* release mmapped memory. */
+ {
+ munmap_chunk(p);
+ return;
+ }
+#endif
+
+ check_inuse_chunk(p);
+
+ sz = hd & ~PREV_INUSE;
+ next = chunk_at_offset(p, sz);
+ nextsz = chunksize(next);
+
+ if (next == top) /* merge with top */
+ {
+ sz += nextsz;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -((long) prevsz));
+ sz += prevsz;
+ unlink(p, bck, fwd);
+ }
+
+ set_head(p, sz | PREV_INUSE);
+ top = p;
+ if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
+ malloc_trim(top_pad);
+ return;
+ }
+
+ set_head(next, nextsz); /* clear inuse bit */
+
+ islr = 0;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -((long) prevsz));
+ sz += prevsz;
+
+ if (p->fd == last_remainder) /* keep as last_remainder */
+ islr = 1;
+ else
+ unlink(p, bck, fwd);
+ }
+
+ if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
+ {
+ sz += nextsz;
+
+ if (!islr && next->fd == last_remainder) /* re-insert last_remainder */
+ {
+ islr = 1;
+ link_last_remainder(p);
+ }
+ else
+ unlink(next, bck, fwd);
+ }
+
+
+ set_head(p, sz | PREV_INUSE);
+ set_foot(p, sz);
+ if (!islr)
+ frontlink(p, sz, idx, bck, fwd);
+}
+
+
+
+
+
+/*
+
+ Realloc algorithm:
+
+ Chunks that were obtained via mmap cannot be extended or shrunk
+ unless HAVE_MREMAP is defined, in which case mremap is used.
+ Otherwise, if their reallocation is for additional space, they are
+ copied. If for less, they are just left alone.
+
+ Otherwise, if the reallocation is for additional space, and the
+ chunk can be extended, it is, else a malloc-copy-free sequence is
+ taken. There are several different ways that a chunk could be
+ extended. All are tried:
+
+ * Extending forward into following adjacent free chunk.
+ * Shifting backwards, joining preceding adjacent space
+ * Both shifting backwards and extending forward.
+ * Extending into newly sbrked space
+
+ Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+
+ If the reallocation is for less space, and the new request is for
+ a `small' (<512 bytes) size, then the newly unused space is lopped
+ off and freed.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is no longer supported.
+ I don't know of any programs still relying on this feature,
+ and allowing it would also allow too many other incorrect
+ usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ mchunkptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ mchunkptr next; /* next contiguous chunk after oldp */
+ INTERNAL_SIZE_T nextsize; /* its size */
+
+ mchunkptr prev; /* previous contiguous chunk before oldp */
+ INTERNAL_SIZE_T prevsize; /* its size */
+
+ mchunkptr remainder; /* holds split off extra space from newp */
+ INTERNAL_SIZE_T remainder_size; /* its size */
+
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (!bytes) {
+ fREe(oldmem);
+ return NULL;
+ }
+#endif
+
+ if ((long)bytes < 0) return NULL;
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == NULL) return mALLOc(bytes);
+
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) {
+ /* This is harder to support and should not be needed */
+ panic("pre-reloc realloc() is not supported");
+ }
+#endif
+
+ newp = oldp = mem2chunk(oldmem);
+ newsize = oldsize = chunksize(oldp);
+
+
+ nb = request2size(bytes);
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(oldp))
+ {
+#if HAVE_MREMAP
+ newp = mremap_chunk(oldp, nb);
+ if(newp) return chunk2mem(newp);
+#endif
+ /* Note the extra SIZE_SZ overhead. */
+ if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(bytes);
+ if (!newmem)
+ return NULL; /* propagate failure */
+ MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+ munmap_chunk(oldp);
+ return newmem;
+ }
+#endif
+
+ check_inuse_chunk(oldp);
+
+ if ((long)(oldsize) < (long)(nb))
+ {
+
+ /* Try expanding forward */
+
+ next = chunk_at_offset(oldp, oldsize);
+ if (next == top || !inuse(next))
+ {
+ nextsize = chunksize(next);
+
+ /* Forward into top only if a remainder */
+ if (next == top)
+ {
+ if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ newsize += nextsize;
+ top = chunk_at_offset(oldp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(oldp, nb);
+ return chunk2mem(oldp);
+ }
+ }
+
+ /* Forward into next chunk */
+ else if (((long)(nextsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ newsize += nextsize;
+ goto split;
+ }
+ }
+ else
+ {
+ next = NULL;
+ nextsize = 0;
+ }
+
+ /* Try shifting backwards. */
+
+ if (!prev_inuse(oldp))
+ {
+ prev = prev_chunk(oldp);
+ prevsize = chunksize(prev);
+
+ /* try forward + backward first to save a later consolidation */
+
+ if (next != NULL)
+ {
+ /* into top */
+ if (next == top)
+ {
+ if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize + nextsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ top = chunk_at_offset(newp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(newp, nb);
+ return newmem;
+ }
+ }
+
+ /* into next chunk */
+ else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += nextsize + prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* backward only */
+ if (prev != NULL && (long)(prevsize + newsize) >= (long)nb)
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* Must allocate */
+
+ newmem = mALLOc (bytes);
+
+ if (newmem == NULL) /* propagate failure */
+ return NULL;
+
+ /* Avoid copy if newp is next chunk after oldp. */
+ /* (This can only happen when new chunk is sbrk'ed.) */
+
+ if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+ {
+ newsize += chunksize(newp);
+ newp = oldp;
+ goto split;
+ }
+
+ /* Otherwise copy, free, and exit */
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ fREe(oldmem);
+ return newmem;
+ }
+
+
+ split: /* split off extra room in old or expanded chunk */
+
+ if (newsize - nb >= MINSIZE) /* split off remainder */
+ {
+ remainder = chunk_at_offset(newp, nb);
+ remainder_size = newsize - nb;
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_inuse_bit_at_offset(remainder, remainder_size);
+ fREe(chunk2mem(remainder)); /* let free() deal with it */
+ }
+ else
+ {
+ set_head_size(newp, newsize);
+ set_inuse_bit_at_offset(newp, newsize);
+ }
+
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+}
+
+
+
+
+/*
+
+ memalign algorithm:
+
+ memalign requests more than enough space from malloc, finds a spot
+ within that chunk that meets the alignment request, and then
+ possibly frees the leading and trailing space.
+
+ The alignment argument must be a power of two. This property is not
+ checked by memalign, so misuse may result in random runtime errors.
+
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ mchunkptr p; /* corresponding chunk */
+ char* brk; /* alignment point within p */
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */
+ mchunkptr remainder; /* spare room at end to split off */
+ long remainder_size; /* its size */
+
+ if ((long)bytes < 0) return NULL;
+
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) {
+ return memalign_simple(alignment, bytes);
+ }
+#endif
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ nb = request2size(bytes);
+ m = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+ /*
+ * The attempt to over-allocate (with a size large enough to guarantee the
+ * ability to find an aligned region within allocated memory) failed.
+ *
+ * Try again, this time only allocating exactly the size the user wants. If
+ * the allocation now succeeds and just happens to be aligned, we can still
+ * fulfill the user's request.
+ */
+ if (m == NULL) {
+ size_t extra, extra2;
+ /*
+ * Use bytes not nb, since mALLOc internally calls request2size too, and
+ * each call increases the size to allocate, to account for the header.
+ */
+ m = (char*)(mALLOc(bytes));
+ /* Aligned -> return it */
+ if ((((unsigned long)(m)) % alignment) == 0)
+ return m;
+ /*
+ * Otherwise, try again, requesting enough extra space to be able to
+ * acquire alignment.
+ */
+ fREe(m);
+ /* Add in extra bytes to match misalignment of unexpanded allocation */
+ extra = alignment - (((unsigned long)(m)) % alignment);
+ m = (char*)(mALLOc(bytes + extra));
+ /*
+ * m might not be the same as before. Validate that the previous value of
+ * extra still works for the current value of m.
+ * If (!m), extra2=alignment so
+ */
+ if (m) {
+ extra2 = alignment - (((unsigned long)(m)) % alignment);
+ if (extra2 > extra) {
+ fREe(m);
+ m = NULL;
+ }
+ }
+ /* Fall through to original NULL check and chunk splitting logic */
+ }
+
+ if (m == NULL) return NULL; /* propagate failure */
+
+ p = mem2chunk(m);
+
+ if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+ {
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ return chunk2mem(p); /* nothing more to do */
+#endif
+ }
+ else /* misaligned */
+ {
+ /*
+ Find an aligned spot inside chunk.
+ Since we need to give back leading space in a chunk of at
+ least MINSIZE, if the first calculation places us at
+ a spot with less than MINSIZE leader, we can move to the
+ next aligned spot -- we've allocated enough total room so that
+ this is always possible.
+ */
+
+ brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment));
+ if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
+
+ newp = (mchunkptr)brk;
+ leadsize = brk - (char*)(p);
+ newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ {
+ newp->prev_size = p->prev_size + leadsize;
+ set_head(newp, newsize|IS_MMAPPED);
+ return chunk2mem(newp);
+ }
+#endif
+
+ /* give back leader, use the rest */
+
+ set_head(newp, newsize | PREV_INUSE);
+ set_inuse_bit_at_offset(newp, newsize);
+ set_head_size(p, leadsize);
+ fREe(chunk2mem(p));
+ p = newp;
+
+ assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+
+ remainder_size = chunksize(p) - nb;
+
+ if (remainder_size >= (long)MINSIZE)
+ {
+ remainder = chunk_at_offset(p, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_head_size(p, nb);
+ fREe(chunk2mem(remainder));
+ }
+
+ check_inuse_chunk(p);
+ return chunk2mem(p);
+
+}
+
+
+
+
+/*
+ valloc just invokes memalign with alignment argument equal
+ to the page size of the system (or as near to this as can
+ be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+ pvalloc just invokes valloc for the nearest pagesize
+ that will accommodate request
+*/
+
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+ size_t pagesize = malloc_getpagesize;
+ return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+
+ calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+ mchunkptr p;
+ INTERNAL_SIZE_T csz;
+
+ INTERNAL_SIZE_T sz = n * elem_size;
+
+
+ /* check if expand_top called, in which case don't need to clear */
+#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT
+#if MORECORE_CLEARS
+ mchunkptr oldtop = top;
+ INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+#endif
+ Void_t* mem = mALLOc (sz);
+
+ if ((long)n < 0) return NULL;
+
+ if (mem == NULL)
+ return NULL;
+ else
+ {
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) {
+ memset(mem, 0, sz);
+ return mem;
+ }
+#endif
+ p = mem2chunk(mem);
+
+ /* Two optional cases in which clearing not necessary */
+
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(p)) return mem;
+#endif
+
+ csz = chunksize(p);
+
+#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT
+#if MORECORE_CLEARS
+ if (p == oldtop && csz > oldtopsize)
+ {
+ /* clear only the bytes from non-freshly-sbrked memory */
+ csz = oldtopsize;
+ }
+#endif
+#endif
+
+ MALLOC_ZERO(mem, csz - SIZE_SZ);
+ return mem;
+ }
+}
+
+/*
+
+ cfree just calls free. It is needed/defined on some systems
+ that pair it with calloc, presumably for odd historical reasons.
+
+*/
+
+#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
+#if __STD_C
+void cfree(Void_t *mem)
+#else
+void cfree(mem) Void_t *mem;
+#endif
+{
+ fREe(mem);
+}
+#endif
+
+
+
+/*
+
+ Malloc_trim gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+
+*/
+
+#if __STD_C
+int malloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ char* current_brk; /* address returned by pre-check sbrk call */
+ char* new_brk; /* address returned by negative sbrk call */
+
+ unsigned long pagesz = malloc_getpagesize;
+
+ top_size = chunksize(top);
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra < (long)pagesz) /* Not enough memory to release */
+ return 0;
+
+ else
+ {
+ /* Test to make sure no one else called sbrk */
+ current_brk = (char*)(MORECORE (0));
+ if (current_brk != (char*)(top) + top_size)
+ return 0; /* Apparently we don't own memory; must fail */
+
+ else
+ {
+ new_brk = (char*)(MORECORE (-extra));
+
+ if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+ {
+ /* Try to figure out what we have */
+ current_brk = (char*)(MORECORE (0));
+ top_size = current_brk - (char*)top;
+ if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+ {
+ sbrked_mem = current_brk - sbrk_base;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ check_chunk(top);
+ return 0;
+ }
+
+ else
+ {
+ /* Success. Adjust top accordingly. */
+ set_head(top, (top_size - extra) | PREV_INUSE);
+ sbrked_mem -= extra;
+ check_chunk(top);
+ return 1;
+ }
+ }
+ }
+}
+
+
+
+/*
+ malloc_usable_size:
+
+ This routine tells you how many bytes you can actually use in an
+ allocated chunk, which may be more than you requested (although
+ often not). You can use this many bytes without worrying about
+ overwriting other allocated objects. Not a particularly great
+ programming practice, but still sometimes useful.
+
+*/
+
+#if __STD_C
+size_t malloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p;
+ if (mem == NULL)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+ if(!chunk_is_mmapped(p))
+ {
+ if (!inuse(p)) return 0;
+ check_inuse_chunk(p);
+ return chunksize(p) - SIZE_SZ;
+ }
+ return chunksize(p) - 2*SIZE_SZ;
+ }
+}
+
+
+
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+#ifdef DEBUG
+static void malloc_update_mallinfo()
+{
+ int i;
+ mbinptr b;
+ mchunkptr p;
+#ifdef DEBUG
+ mchunkptr q;
+#endif
+
+ INTERNAL_SIZE_T avail = chunksize(top);
+ int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
+
+ for (i = 1; i < NAV; ++i)
+ {
+ b = bin_at(i);
+ for (p = last(b); p != b; p = p->bk)
+ {
+#ifdef DEBUG
+ check_free_chunk(p);
+ for (q = next_chunk(p);
+ q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
+ q = next_chunk(q))
+ check_inuse_chunk(q);
+#endif
+ avail += chunksize(p);
+ navail++;
+ }
+ }
+
+ current_mallinfo.ordblks = navail;
+ current_mallinfo.uordblks = sbrked_mem - avail;
+ current_mallinfo.fordblks = avail;
+ current_mallinfo.hblks = n_mmaps;
+ current_mallinfo.hblkhd = mmapped_mem;
+ current_mallinfo.keepcost = chunksize(top);
+
+}
+#endif /* DEBUG */
+
+
+
+/*
+
+ malloc_stats:
+
+ Prints on the amount of space obtain from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), the maximum
+ number of simultaneous mmap regions used, and the current number
+ of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. (Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead.)
+
+*/
+
+#ifdef DEBUG
+void malloc_stats()
+{
+ malloc_update_mallinfo();
+ printf("max system bytes = %10u\n",
+ (unsigned int)(max_total_mem));
+ printf("system bytes = %10u\n",
+ (unsigned int)(sbrked_mem + mmapped_mem));
+ printf("in use bytes = %10u\n",
+ (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+ printf("max mmap regions = %10u\n",
+ (unsigned int)max_n_mmaps);
+#endif
+}
+#endif /* DEBUG */
+
+/*
+ mallinfo returns a copy of updated current mallinfo.
+*/
+
+#ifdef DEBUG
+struct mallinfo mALLINFo()
+{
+ malloc_update_mallinfo();
+ return current_mallinfo;
+}
+#endif /* DEBUG */
+
+
+
+
+/*
+ mallopt:
+
+ mallopt is the general SVID/XPG interface to tunable parameters.
+ The format is to provide a (parameter-number, parameter-value) pair.
+ mallopt then sets the corresponding parameter to the argument
+ value if it can (i.e., so long as the value is meaningful),
+ and returns 1 if successful else 0.
+
+ See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ switch(param_number)
+ {
+ case M_TRIM_THRESHOLD:
+ trim_threshold = value; return 1;
+ case M_TOP_PAD:
+ top_pad = value; return 1;
+ case M_MMAP_THRESHOLD:
+ mmap_threshold = value; return 1;
+ case M_MMAP_MAX:
+#if HAVE_MMAP
+ n_mmaps_max = value; return 1;
+#else
+ if (value != 0) return 0; else n_mmaps_max = value; return 1;
+#endif
+
+ default:
+ return 0;
+ }
+}
+
+int initf_malloc(void)
+{
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ assert(gd->malloc_base); /* Set up by crt0.S */
+ gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN);
+ gd->malloc_ptr = 0;
+#endif
+
+ return 0;
+}
+
+/*
+
+History:
+
+ V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
+ * return null for negative arguments
+ * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com>
+ * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+ (e.g. WIN32 platforms)
+ * Cleanup up header file inclusion for WIN32 platforms
+ * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+ * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+ memory allocation routines
+ * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+ * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+ usage of 'assert' in non-WIN32 code
+ * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+ avoid infinite loop
+ * Always call 'fREe()' rather than 'free()'
+
+ V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
+ * Fixed ordering problem with boundary-stamping
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
diff --git a/roms/u-boot/common/dlmalloc.src b/roms/u-boot/common/dlmalloc.src
new file mode 100644
index 000000000..d86acffde
--- /dev/null
+++ b/roms/u-boot/common/dlmalloc.src
@@ -0,0 +1,3265 @@
+/* ---------- To make a malloc.h, start cutting here ------------ */
+
+/*
+ A version of malloc/free/realloc written by Doug Lea and released to the
+ public domain. Send questions/comments/complaints/performance data
+ to dl@cs.oswego.edu
+
+* VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://g.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+* Why use this malloc?
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and tunable.
+ Consistent balance across these factors results in a good general-purpose
+ allocator. For a high-level description, see
+ http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+ (Much fuller descriptions are contained in the program documentation below.)
+
+ malloc(size_t n);
+ Return a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available.
+ free(Void_t* p);
+ Release the chunk of memory pointed to by p, or no effect if p is null.
+ realloc(Void_t* p, size_t n);
+ Return a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available. The returned pointer may or may not be
+ the same as p. If p is null, equivalent to malloc. Unless the
+ #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+ memalign(size_t alignment, size_t n);
+ Return a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument, which must be a power of
+ two.
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system (or as near to this as can be figured out from
+ all the includes/defines below.)
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ calloc(size_t unit, size_t quantity);
+ Returns a pointer to quantity * unit bytes, with all locations
+ set to zero.
+ cfree(Void_t* p);
+ Equivalent to free(p).
+ malloc_trim(size_t pad);
+ Release all but pad bytes of freed top-most memory back
+ to the system. Return 1 if successful, else 0.
+ malloc_usable_size(Void_t* p);
+ Report the number usable allocated bytes associated with allocated
+ chunk p. This may or may not report more bytes than were requested,
+ due to alignment and minimum size constraints.
+ malloc_stats();
+ Prints brief summary statistics on stderr.
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics.
+ mallopt(int parameter_number, int parameter_value)
+ Changes one of the tunable parameters described below. Returns
+ 1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+ Alignment: 8-byte
+ 8 byte alignment is currently hardwired into the design. This
+ seems to suffice for all current machines and C compilers.
+
+ Assumed pointer representation: 4 or 8 bytes
+ Code for 8-byte pointers is untested by me but has worked
+ reliably by Wolfram Gloger, who contributed most of the
+ changes supporting this.
+
+ Assumed size_t representation: 4 or 8 bytes
+ Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes
+ Each malloced chunk has a hidden overhead of 4 bytes holding size
+ and status information.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
+ 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
+
+ When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+ ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+ needed; 4 (8) for a trailing size field
+ and 8 (16) bytes for free list pointers. Thus, the minimum
+ allocatable size is 16/24/32 bytes.
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+
+ Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes
+ 8-byte size_t: 2^63 - 16 bytes
+
+ It is assumed that (possibly signed) size_t bit values suffice to
+ represent chunk sizes. `Possibly signed' is due to the fact
+ that `size_t' may be defined on a system as either a signed or
+ an unsigned type. To be conservative, values that would appear
+ as negative numbers are avoided.
+ Requests for sizes with a negative sign bit when the request
+ size is treaded as a long will return null.
+
+ Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+ Alignnment demands, plus the minimum allocatable size restriction
+ make the normal worst-case wastage 15 bytes (i.e., up to 15
+ more bytes will be allocated than were requested in malloc), with
+ two exceptions:
+ 1. Because requests for zero bytes allocate non-zero space,
+ the worst case wastage for a request of zero bytes is 24 bytes.
+ 2. For requests >= mmap_threshold that are serviced via
+ mmap(), the worst case wastage is 8 bytes plus the remainder
+ from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+ Here are some features that are NOT currently supported
+
+ * No user-definable hooks for callbacks and the like.
+ * No automated mechanism for fully checking that all accesses
+ to malloced memory stay within their bounds.
+ * No support for compaction.
+
+* Synopsis of compile-time options:
+
+ People have reported using previous versions of this malloc on all
+ versions of Unix, sometimes by tweaking some of the defines
+ below. It has been tested most extensively on Solaris and
+ Linux. It is also reported to work on WIN32 platforms.
+ People have also reported adapting this malloc for use in
+ stand-alone embedded systems.
+
+ The implementation is in straight, hand-tuned ANSI C. Among other
+ consequences, it uses a lot of macros. Because of this, to be at
+ all usable, this code should be compiled using an optimizing compiler
+ (for example gcc -O2) that can simplify expressions and control
+ paths.
+
+ __STD_C (default: derived from C compiler defines)
+ Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+ a C compiler sufficiently close to ANSI to get away with it.
+ DEBUG (default: NOT defined)
+ Define to enable debugging. Adds fairly extensive assertion-based
+ checking to help track down memory errors, but noticeably slows down
+ execution.
+ REALLOC_ZERO_BYTES_FREES (default: NOT defined)
+ Define this if you think that realloc(p, 0) should be equivalent
+ to free(p). Otherwise, since malloc returns a unique pointer for
+ malloc(0), so does realloc(p, 0).
+ HAVE_MEMCPY (default: defined)
+ Define if you are not otherwise using ANSI STD C, but still
+ have memcpy and memset in your C library and want to use them.
+ Otherwise, simple internal versions are supplied.
+ USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
+ Define as 1 if you want the C library versions of memset and
+ memcpy called in realloc and calloc (otherwise macro versions are used).
+ At least on some platforms, the simple macro versions usually
+ outperform libc versions.
+ HAVE_MMAP (default: defined as 1)
+ Define to non-zero to optionally make malloc() use mmap() to
+ allocate very large blocks.
+ HAVE_MREMAP (default: defined as 0 unless Linux libc set)
+ Define to non-zero to optionally make realloc() use mremap() to
+ reallocate very large blocks.
+ malloc_getpagesize (default: derived from system #includes)
+ Either a constant or routine call returning the system page size.
+ HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
+ Optionally define if you are on a system with a /usr/include/malloc.h
+ that declares struct mallinfo. It is not at all necessary to
+ define this even if you do, but will ensure consistency.
+ INTERNAL_SIZE_T (default: size_t)
+ Define to a 32-bit type (probably `unsigned int') if you are on a
+ 64-bit machine, yet do not want or need to allow malloc requests of
+ greater than 2^31 to be handled. This saves space, especially for
+ very small chunks.
+ INTERNAL_LINUX_C_LIB (default: NOT defined)
+ Defined only when compiled as part of Linux libc.
+ Also note that there is some odd internal name-mangling via defines
+ (for example, internally, `malloc' is named `mALLOc') needed
+ when compiling in this case. These look funny but don't otherwise
+ affect anything.
+ WIN32 (default: undefined)
+ Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+ LACKS_UNISTD_H (default: undefined if not WIN32)
+ Define this if your system does not have a <unistd.h>.
+ LACKS_SYS_PARAM_H (default: undefined if not WIN32)
+ Define this if your system does not have a <sys/param.h>.
+ MORECORE (default: sbrk)
+ The name of the routine to call to obtain more memory from the system.
+ MORECORE_FAILURE (default: -1)
+ The value returned upon failure of MORECORE.
+ MORECORE_CLEARS (default 1)
+ true (1) if the routine mapped to MORECORE zeroes out memory (which
+ holds for sbrk).
+ DEFAULT_TRIM_THRESHOLD
+ DEFAULT_TOP_PAD
+ DEFAULT_MMAP_THRESHOLD
+ DEFAULT_MMAP_MAX
+ Default values of tunable parameters (described in detail below)
+ controlling interaction with host system routines (sbrk, mmap, etc).
+ These values may also be changed dynamically via mallopt(). The
+ preset defaults are those that give best performance for typical
+ programs/systems.
+ USE_DL_PREFIX (default: undefined)
+ Prefix all public routines with the string 'dl'. Useful to
+ quickly avoid procedure declaration conflicts and linker symbol
+ conflicts with existing memory allocation routines.
+
+
+*/
+
+
+
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C 1
+#else
+#if __cplusplus
+#define __STD_C 1
+#else
+#define __STD_C 0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t void
+#else
+#define Void_t char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h> /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h> /* needed for malloc_stats */
+
+
+/*
+ Compile-time options
+*/
+
+
+/*
+ Debugging:
+
+ Because freed chunks may be overwritten with link fields, this
+ malloc will often die when freed memory is overwritten by user
+ programs. This can be very effective (albeit in an annoying way)
+ in helping track down dangling pointers.
+
+ If you compile with -DDEBUG, a number of assertion checks are
+ enabled that will catch more memory errors. You probably won't be
+ able to make much sense of the actual assertion errors, but they
+ should help you locate incorrectly overwritten memory. The
+ checking is fairly extensive, and will slow down execution
+ noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+ attempt to check every non-mmapped allocated and free chunk in the
+ course of computing the summmaries. (By nature, mmapped regions
+ cannot be checked very much automatically.)
+
+ Setting DEBUG may also be helpful if you are trying to modify
+ this code. The assertions in the check routines spell out in more
+ detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+#if DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+
+/*
+ INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+ of chunk sizes. On a 64-bit machine, you can reduce malloc
+ overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+ at the expense of not being able to handle requests greater than
+ 2^31. This limitation is hardly ever a concern; you are encouraged
+ to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+ REALLOC_ZERO_BYTES_FREES should be set if a call to
+ realloc with zero bytes should be the same as a call to free.
+ Some people think it should. Otherwise, since this malloc
+ returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/* #define REALLOC_ZERO_BYTES_FREES */
+
+
+/*
+ WIN32 causes an emulation of sbrk to be compiled in
+ mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+
+/*
+ Include 'windows.h' to get the necessary declarations for the
+ Microsoft Visual C++ data structures and routines used in the 'sbrk'
+ emulation.
+
+ Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
+ Visual C++ header files are included.
+*/
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+/*
+ HAVE_MEMCPY should be defined if you are not otherwise using
+ ANSI STD C, but still have memcpy and memset in your C library
+ and want to use them in calloc and realloc. Otherwise simple
+ macro versions are defined here.
+
+ USE_MEMCPY should be defined as 1 if you actually want to
+ have memset and memcpy called. People report that the macro
+ versions are often enough faster than libc versions on many
+ systems that it is better to use them.
+
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+#ifdef WIN32
+/* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */
+/* 'windows.h' */
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+#if USE_MEMCPY
+
+/* The following macros are only invoked with (2n+1)-multiples of
+ INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+ for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T mzsz = (nbytes); \
+ if(mzsz <= 9*sizeof(mzsz)) { \
+ INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \
+ if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; }}} \
+ *mz++ = 0; \
+ *mz++ = 0; \
+ *mz = 0; \
+ } else memset((charp), 0, mzsz); \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T mcsz = (nbytes); \
+ if(mcsz <= 9*sizeof(mcsz)) { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \
+ if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; }}} \
+ *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ *mcdst = *mcsrc ; \
+ } else memcpy(dest, src, mcsz); \
+} while(0)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mzp++ = 0; \
+ case 7: *mzp++ = 0; \
+ case 6: *mzp++ = 0; \
+ case 5: *mzp++ = 0; \
+ case 4: *mzp++ = 0; \
+ case 3: *mzp++ = 0; \
+ case 2: *mzp++ = 0; \
+ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mcdst++ = *mcsrc++; \
+ case 7: *mcdst++ = *mcsrc++; \
+ case 6: *mcdst++ = *mcsrc++; \
+ case 5: *mcdst++ = *mcsrc++; \
+ case 4: *mcdst++ = *mcsrc++; \
+ case 3: *mcdst++ = *mcsrc++; \
+ case 2: *mcdst++ = *mcsrc++; \
+ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#endif
+
+
+/*
+ Define HAVE_MMAP to optionally make malloc() use mmap() to
+ allocate very large blocks. These will be returned to the
+ operating system immediately after a free().
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+/*
+ Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+ large blocks. This is currently only possible on Linux with
+ kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+ Access to system page size. To the extent possible, this malloc
+ manages memory from the system in page-size units.
+
+ The following mechanics for getpagesize were adapted from
+ bsd/gnu getpagesize.h
+*/
+
+#ifndef LACKS_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+ extern size_t getpagesize();
+# define malloc_getpagesize getpagesize()
+# else
+# ifdef WIN32
+# define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
+# else
+# ifndef LACKS_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else
+# define malloc_getpagesize (4096) /* just guess */
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+
+/*
+
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing the same kind of
+ information you can get from malloc_stats. It should work on
+ any SVID/XPG compliant system that has a /usr/include/malloc.h
+ defining struct mallinfo. (If you'd like to install such a thing
+ yourself, cut out the preliminary declarations as described above
+ and below and save them in a malloc.h file. But there's no
+ compelling reason to bother to do this.)
+
+ The main declaration needed is the mallinfo struct that is returned
+ (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
+ bunch of fields, most of which are not even meaningful in this
+ version of malloc. Some of these fields are are instead filled by
+ mallinfo() with other numbers that might possibly be of interest.
+
+ HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else an SVID2/XPG2 compliant
+ version is declared below. These must be precisely the same for
+ mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#if HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+ int arena; /* total space allocated from system */
+ int ordblks; /* number of non-inuse chunks */
+ int smblks; /* unused -- always zero */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* total space in mmapped regions */
+ int usmblks; /* unused -- always zero */
+ int fsmblks; /* unused -- always zero */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total non-inuse space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST 1 /* UNUSED in this malloc */
+#define M_NLBLKS 2 /* UNUSED in this malloc */
+#define M_GRAIN 3 /* UNUSED in this malloc */
+#define M_KEEP 4 /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD -1
+#define M_TOP_PAD -2
+#define M_MMAP_THRESHOLD -3
+#define M_MMAP_MAX -4
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+ M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+ to keep before releasing via malloc_trim in free().
+
+ Automatic trimming is mainly useful in long-lived programs.
+ Because trimming via sbrk can be slow on some systems, and can
+ sometimes be wasteful (in cases where programs immediately
+ afterward allocate more large chunks) the value should be high
+ enough so that your overall system performance would improve by
+ releasing.
+
+ The trim threshold and the mmap control parameters (see below)
+ can be traded off with one another. Trimming and mmapping are
+ two different ways of releasing unused memory back to the
+ system. Between these two, it is often possible to keep
+ system-level demands of a long-lived program down to a bare
+ minimum. For example, in one test suite of sessions measuring
+ the XF86 X server on Linux, using a trim threshold of 128K and a
+ mmap threshold of 192K led to near-minimal long term resource
+ consumption.
+
+ If you are using this malloc in a long-lived program, it should
+ pay to experiment with these values. As a rough guide, you
+ might set to a value close to the average size of a process
+ (program) running on your system. Releasing this much memory
+ would allow such a process to run in memory. Generally, it's
+ worth it to tune for trimming rather tham memory mapping when a
+ program undergoes phases where several large chunks are
+ allocated and released in ways that can reuse each other's
+ storage, perhaps mixed with phases where there are no such
+ chunks at all. And in well-behaved long-lived programs,
+ controlling release of large blocks via trimming versus mapping
+ is usually faster.
+
+ However, in most programs, these parameters serve mainly as
+ protection against the system-level effects of carrying around
+ massive amounts of unneeded memory. Since frequent calls to
+ sbrk, mmap, and munmap otherwise degrade performance, the default
+ parameters are set to relatively high values that serve only as
+ safeguards.
+
+ The default trim value is high enough to cause trimming only in
+ fairly extreme (by current memory consumption standards) cases.
+ It must be greater than page size to have any useful effect. To
+ disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD (0)
+#endif
+
+/*
+ M_TOP_PAD is the amount of extra `padding' space to allocate or
+ retain whenever sbrk is called. It is used in two ways internally:
+
+ * When sbrk is called to extend the top of the arena to satisfy
+ a new malloc request, this much padding is added to the sbrk
+ request.
+
+ * When malloc_trim is called automatically from free(),
+ it is used as the `pad' argument.
+
+ In both cases, the actual amount of padding is rounded
+ so that the end of the arena is always a system page boundary.
+
+ The main reason for using padding is to avoid calling sbrk so
+ often. Having even a small pad greatly reduces the likelihood
+ that nearly every malloc request during program start-up (or
+ after trimming) will invoke sbrk, which needlessly wastes
+ time.
+
+ Automatic rounding-up to page-size units is normally sufficient
+ to avoid measurable overhead, so the default is 0. However, in
+ systems where sbrk is relatively slow, it can pay to increase
+ this value, at the expense of carrying around more memory than
+ the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+ M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ to service a request. Requests of at least this size that cannot
+ be allocated using already-existing space will be serviced via mmap.
+ (If enough normal freed space already exists it is used instead.)
+
+ Using mmap segregates relatively large chunks of memory so that
+ they can be individually obtained and released from the host
+ system. A request serviced through mmap is never reused by any
+ other request (at least not directly; the system may just so
+ happen to remap successive requests to the same locations).
+
+ Segregating space in this way has the benefit that mmapped space
+ can ALWAYS be individually released back to the system, which
+ helps keep the system level memory demands of a long-lived
+ program low. Mapped memory can never become `locked' between
+ other chunks, as can happen with normally allocated chunks, which
+ menas that even trimming via malloc_trim would not release them.
+
+ However, it has the disadvantages that:
+
+ 1. The space cannot be reclaimed, consolidated, and then
+ used to service later requests, as happens with normal chunks.
+ 2. It can lead to more wastage because of mmap page alignment
+ requirements
+ 3. It causes malloc performance to be more dependent on host
+ system memory management support routines which may vary in
+ implementation quality and may impose arbitrary
+ limitations. Generally, servicing a request via normal
+ malloc steps is faster than going through a system's mmap.
+
+ All together, these considerations should lead you to use mmap
+ only for relatively large requests.
+
+
+*/
+
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX (64)
+#else
+#define DEFAULT_MMAP_MAX (0)
+#endif
+#endif
+
+/*
+ M_MMAP_MAX is the maximum number of requests to simultaneously
+ service using mmap. This parameter exists because:
+
+ 1. Some systems have a limited number of internal tables for
+ use by mmap.
+ 2. In most systems, overreliance on mmap can degrade overall
+ performance.
+ 3. If a program allocates many large regions, it is probably
+ better off using normal sbrk-based allocation routines that
+ can reclaim and reallocate normal heap memory. Using a
+ small value allows transition into this mode after the
+ first few allocations.
+
+ Setting to 0 disables all use of mmap. If HAVE_MMAP is not set,
+ the default value is 0, and attempts to set it to non-zero values
+ in mallopt will fail.
+*/
+
+
+/*
+ USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+ Useful to quickly avoid procedure declaration conflicts and linker
+ symbol conflicts with existing memory allocation routines.
+
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+/*
+
+ Special defines for linux libc
+
+ Except when compiled using these special defines for Linux libc
+ using weak aliases, this malloc is NOT designed to work in
+ multithreaded applications. No semaphores or other concurrency
+ control are provided to ensure that multiple malloc or free calls
+ don't run at the same time, which could be disasterous. A single
+ semaphore could be used across malloc, realloc, and free (which is
+ essentially the effect of the linux weak alias approach). It would
+ be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+extern Void_t* sbrk(ptrdiff_t);
+#else
+extern Void_t* sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 1
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc __libc_calloc
+#define fREe __libc_free
+#define mALLOc __libc_malloc
+#define mEMALIGn __libc_memalign
+#define rEALLOc __libc_realloc
+#define vALLOc __libc_valloc
+#define pvALLOc __libc_pvalloc
+#define mALLINFo __libc_mallinfo
+#define mALLOPt __libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifdef USE_DL_PREFIX
+#define cALLOc dlcalloc
+#define fREe dlfree
+#define mALLOc dlmalloc
+#define mEMALIGn dlmemalign
+#define rEALLOc dlrealloc
+#define vALLOc dlvalloc
+#define pvALLOc dlpvalloc
+#define mALLINFo dlmallinfo
+#define mALLOPt dlmallopt
+#else /* USE_DL_PREFIX */
+#define cALLOc calloc
+#define fREe free
+#define mALLOc malloc
+#define mEMALIGn memalign
+#define rEALLOc realloc
+#define vALLOc valloc
+#define pvALLOc pvalloc
+#define mALLINFo mallinfo
+#define mALLOPt mallopt
+#endif /* USE_DL_PREFIX */
+
+#endif
+
+/* Public routines */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+Void_t* cALLOc(size_t, size_t);
+void cfree(Void_t*);
+int malloc_trim(size_t);
+size_t malloc_usable_size(Void_t*);
+void malloc_stats();
+int mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void fREe();
+Void_t* rEALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+Void_t* cALLOc();
+void cfree();
+int malloc_trim();
+size_t malloc_usable_size();
+void malloc_stats();
+int mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+/* ---------- To make a malloc.h, end cutting here ------------ */
+
+
+/*
+ Emulation of sbrk for WIN32
+ All code within the ifdef WIN32 is untested by me.
+
+ Thanks to Martin Fong and others for supplying this.
+*/
+
+
+#ifdef WIN32
+
+#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
+~(malloc_getpagesize-1))
+#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1))
+
+/* resrve 64MB to insure large contiguous space */
+#define RESERVED_SIZE (1024*1024*64)
+#define NEXT_SIZE (2048*1024)
+#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
+
+struct GmListElement;
+typedef struct GmListElement GmListElement;
+
+struct GmListElement
+{
+ GmListElement* next;
+ void* base;
+};
+
+static GmListElement* head = 0;
+static unsigned int gNextAddress = 0;
+static unsigned int gAddressBase = 0;
+static unsigned int gAllocatedSize = 0;
+
+static
+GmListElement* makeGmListElement (void* bas)
+{
+ GmListElement* this;
+ this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
+ assert (this);
+ if (this)
+ {
+ this->base = bas;
+ this->next = head;
+ head = this;
+ }
+ return this;
+}
+
+void gcleanup ()
+{
+ BOOL rval;
+ assert ( (head == NULL) || (head->base == (void*)gAddressBase));
+ if (gAddressBase && (gNextAddress - gAddressBase))
+ {
+ rval = VirtualFree ((void*)gAddressBase,
+ gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ assert (rval);
+ }
+ while (head)
+ {
+ GmListElement* next = head->next;
+ rval = VirtualFree (head->base, 0, MEM_RELEASE);
+ assert (rval);
+ LocalFree (head);
+ head = next;
+ }
+}
+
+static
+void* findRegion (void* start_address, unsigned long size)
+{
+ MEMORY_BASIC_INFORMATION info;
+ if (size >= TOP_MEMORY) return NULL;
+
+ while ((unsigned long)start_address + size < TOP_MEMORY)
+ {
+ VirtualQuery (start_address, &info, sizeof (info));
+ if ((info.State == MEM_FREE) && (info.RegionSize >= size))
+ return start_address;
+ else
+ {
+ /* Requested region is not available so see if the */
+ /* next region is available. Set 'start_address' */
+ /* to the next region and call 'VirtualQuery()' */
+ /* again. */
+
+ start_address = (char*)info.BaseAddress + info.RegionSize;
+
+ /* Make sure we start looking for the next region */
+ /* on the *next* 64K boundary. Otherwise, even if */
+ /* the new region is free according to */
+ /* 'VirtualQuery()', the subsequent call to */
+ /* 'VirtualAlloc()' (which follows the call to */
+ /* this routine in 'wsbrk()') will round *down* */
+ /* the requested address to a 64K boundary which */
+ /* we already know is an address in the */
+ /* unavailable region. Thus, the subsequent call */
+ /* to 'VirtualAlloc()' will fail and bring us back */
+ /* here, causing us to go into an infinite loop. */
+
+ start_address =
+ (void *) AlignPage64K((unsigned long) start_address);
+ }
+ }
+ return NULL;
+
+}
+
+
+void* wsbrk (long size)
+{
+ void* tmp;
+ if (size > 0)
+ {
+ if (gAddressBase == 0)
+ {
+ gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
+ gNextAddress = gAddressBase =
+ (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
+ MEM_RESERVE, PAGE_NOACCESS);
+ } else if (AlignPage (gNextAddress + size) > (gAddressBase +
+gAllocatedSize))
+ {
+ long new_size = max (NEXT_SIZE, AlignPage (size));
+ void* new_address = (void*)(gAddressBase+gAllocatedSize);
+ do
+ {
+ new_address = findRegion (new_address, new_size);
+
+ if (new_address == 0)
+ return (void*)-1;
+
+ gAddressBase = gNextAddress =
+ (unsigned int)VirtualAlloc (new_address, new_size,
+ MEM_RESERVE, PAGE_NOACCESS);
+ /* repeat in case of race condition */
+ /* The region that we found has been snagged */
+ /* by another thread */
+ }
+ while (gAddressBase == 0);
+
+ assert (new_address == (void*)gAddressBase);
+
+ gAllocatedSize = new_size;
+
+ if (!makeGmListElement ((void*)gAddressBase))
+ return (void*)-1;
+ }
+ if ((size + gNextAddress) > AlignPage (gNextAddress))
+ {
+ void* res;
+ res = VirtualAlloc ((void*)AlignPage (gNextAddress),
+ (size + gNextAddress -
+ AlignPage (gNextAddress)),
+ MEM_COMMIT, PAGE_READWRITE);
+ if (res == 0)
+ return (void*)-1;
+ }
+ tmp = (void*)gNextAddress;
+ gNextAddress = (unsigned int)tmp + size;
+ return tmp;
+ }
+ else if (size < 0)
+ {
+ unsigned int alignedGoal = AlignPage (gNextAddress + size);
+ /* Trim by releasing the virtual memory */
+ if (alignedGoal >= gAddressBase)
+ {
+ VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
+ MEM_DECOMMIT);
+ gNextAddress = gNextAddress + size;
+ return (void*)gNextAddress;
+ }
+ else
+ {
+ VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ gNextAddress = gAddressBase;
+ return (void*)-1;
+ }
+ }
+ else
+ {
+ return (void*)gNextAddress;
+ }
+}
+
+#endif
+
+
+
+/*
+ Type declarations
+*/
+
+
+struct malloc_chunk
+{
+ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+
+ malloc_chunk details:
+
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ described in e.g., Knuth or Standish. (See the paper by Paul
+ Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+ survey of such techniques.) Sizes of free chunks are stored both
+ in the front of each chunk and at the end. This makes
+ consolidating fragmented chunks into bigger chunks very fast. The
+ size fields also hold bits representing whether chunks are free or
+ in use.
+
+ An allocated chunk looks like this:
+
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk, if allocated | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | User data starts here... .
+ . .
+ . (malloc_usable_space() bytes) .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ Where "chunk" is the front of the chunk for the purpose of most of
+ the malloc code, but "mem" is the pointer that is returned to the
+ user. "Nextchunk" is the beginning of the next contiguous chunk.
+
+ Chunks always begin on even word boundries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus double-word aligned.
+
+ Free chunks are stored in circular doubly-linked lists, and look like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ (The very first chunk allocated always has this bit set,
+ preventing access to non-existent (or non-owned) memory.)
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_size of the NEXT chunk. (This makes it easier to
+ deal with alignments etc).
+
+ The two exceptions to all this are
+
+ 1. The special chunk `top', which doesn't bother using the
+ trailing size field since there is no
+ next contiguous chunk that would have to index off it. (After
+ initialization, `top' is forced to always exist. If it would
+ become less than MINSIZE bytes long, it is replenished via
+ malloc_extend_top.)
+
+ 2. Chunks allocated via mmap, which have the second-lowest-order
+ bit (IS_MMAPPED) set in their size fields. Because they are
+ never merged or traversed from any other chunk, they have no
+ foot size or inuse information.
+
+ Available chunks are kept in any of several places (all declared below):
+
+ * `av': An array of chunks serving as bin headers for consolidated
+ chunks. Each bin is doubly linked. The bins are approximately
+ proportionally (log) spaced. There are a lot of these bins
+ (128). This may look excessive, but works very well in
+ practice. All procedures maintain the invariant that no
+ consolidated chunk physically borders another one. Chunks in
+ bins are kept in size order, with ties going to the
+ approximately least recently used chunk.
+
+ The chunks in each bin are maintained in decreasing sorted order by
+ size. This is irrelevant for the small bins, which all contain
+ the same-sized chunks, but facilitates best-fit allocation for
+ larger chunks. (These lists are just sequential. Keeping them in
+ order almost never requires enough traversal to warrant using
+ fancier ordered data structures.) Chunks of the same size are
+ linked with the most recently freed at the front, and allocations
+ are taken from the back. This results in LRU or FIFO allocation
+ order, which tends to give each chunk an equal opportunity to be
+ consolidated with adjacent freed chunks, resulting in larger free
+ chunks and less fragmentation.
+
+ * `top': The top-most available chunk (i.e., the one bordering the
+ end of available memory) is treated specially. It is never
+ included in any bin, is used only if no other chunk is
+ available, and is released back to the system if it is very
+ large (see M_TRIM_THRESHOLD).
+
+ * `last_remainder': A bin holding only the remainder of the
+ most recently split (non-top) chunk. This bin is checked
+ before other non-fitting chunks, so as to provide better
+ locality for runs of sequentially allocated chunks.
+
+ * Implicitly, through the host system's memory mapping tables.
+ If supported, requests greater than a threshold are usually
+ serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+
+
+
+
+/* sizes, alignments */
+
+#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
+#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ)
+#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
+#define MINSIZE (sizeof(struct malloc_chunk))
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* pad request bytes into a usable size */
+
+#define request2size(req) \
+ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
+ (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
+ (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+
+
+/*
+ Physical chunk operations
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+ ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+
+
+
+/*
+ Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+
+
+/*
+ Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s) ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+
+
+
+/*
+ Bins
+
+ The bins, `av_' are an array of pairs of pointers serving as the
+ heads of (initially empty) doubly-linked lists of chunks, laid out
+ in a way so that each pair can be treated as if it were in a
+ malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+ and chunks are the same).
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically
+ spaced. (See the table below.) The `av_' array is never mentioned
+ directly in the code, but instead via bin access macros.
+
+ Bin layout:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ There is actually a little bit of slop in the numbers in bin_index
+ for the sake of speed. This makes no difference elsewhere.
+
+ The special chunks `top' and `last_remainder' get their own bins,
+ (this is implemented via yet more trickery with the av_ array),
+ although `top' is never properly linked to its bin since it is
+ always handled specially.
+
+*/
+
+#define NAV 128 /* number of bins */
+
+typedef struct malloc_chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+ The first 2 bins are never indexed. The corresponding av_ cells are instead
+ used for bookkeeping. This is not to save space, but to simplify
+ indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top (bin_at(0)->fd) /* The topmost chunk */
+#define last_remainder (bin_at(1)) /* remainder from last split */
+
+
+/*
+ Because top initially points to its own bin with initial
+ zero size, thus forcing extension on the first malloc request,
+ we avoid having any special code in malloc to check whether
+ it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i) bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ 0, 0,
+ IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
+ IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
+ IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
+ IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
+ IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
+ IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
+ IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
+ IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
+ IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
+ IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
+ IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
+ IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
+ IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/*
+ Indexing into bins
+*/
+
+#define bin_index(sz) \
+(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \
+ ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \
+ ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \
+ ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+ 126)
+/*
+ bins for chunks < 512 are all spaced 8 bytes apart, and hold
+ identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN 63
+#define MAX_SMALLBIN_SIZE 512
+#define SMALLBIN_WIDTH 8
+
+#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
+
+/*
+ Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+
+
+/*
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binblocks' is a
+ one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+ have any (possibly) non-empty bins, so they can be skipped over
+ all at once during during traversals. The bits are NOT always
+ cleared as soon as all bins in a block are empty, but instead only
+ when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH 4 /* bins per block */
+
+#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */
+
+/* bin<->block macros */
+
+#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii) (binblocks |= idx2binblock(ii))
+#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii)))
+
+
+
+
+
+/* Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad = DEFAULT_TOP_PAD;
+static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+static unsigned int n_mmaps = 0;
+static unsigned int max_n_mmaps = 0;
+static unsigned long mmapped_mem = 0;
+static unsigned long max_mmapped_mem = 0;
+
+
+
+/*
+ Debugging support
+*/
+
+#if DEBUG
+
+
+/*
+ These routines make a number of assertions about the states
+ of data structures that should be true at all times. If any
+ are not true, it's very likely that a user program has somehow
+ trashed memory. (It's also possible that there is a coding error
+ in malloc. In which case, please report it!)
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+
+ /* No checkable chunk is mmapped */
+ assert(!chunk_is_mmapped(p));
+
+ /* Check for legal address ... */
+ assert((char*)p >= sbrk_base);
+ if (p != top)
+ assert((char*)p + sz <= (char*)top);
+ else
+ assert((char*)p + sz <= sbrk_base + sbrked_mem);
+
+}
+
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ mchunkptr next = chunk_at_offset(p, sz);
+
+ do_check_chunk(p);
+
+ /* Check whether it claims to be free ... */
+ assert(!inuse(p));
+
+ /* Unless a special marker, must have OK fields */
+ if ((long)sz >= (long)MINSIZE)
+ {
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(aligned_OK(chunk2mem(p)));
+ /* ... matching footer field */
+ assert(next->prev_size == sz);
+ /* ... and is fully consolidated */
+ assert(prev_inuse(p));
+ assert (next == top || inuse(next));
+
+ /* ... and has minimally sane links */
+ assert(p->fd->bk == p);
+ assert(p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_SZ */
+ assert(sz == SIZE_SZ);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+ mchunkptr next = next_chunk(p);
+ do_check_chunk(p);
+
+ /* Check whether it claims to be in use ... */
+ assert(inuse(p));
+
+ /* ... and is surrounded by OK chunks.
+ Since more things can be checked with free chunks than inuse ones,
+ if an inuse chunk borders them and debug is on, it's worth doing them.
+ */
+ if (!prev_inuse(p))
+ {
+ mchunkptr prv = prev_chunk(p);
+ assert(next_chunk(prv) == p);
+ do_check_free_chunk(prv);
+ }
+ if (next == top)
+ {
+ assert(prev_inuse(next));
+ assert(chunksize(next) >= MINSIZE);
+ }
+ else if (!inuse(next))
+ do_check_free_chunk(next);
+
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ long room = sz - s;
+
+ do_check_inuse_chunk(p);
+
+ /* Legal size ... */
+ assert((long)sz >= (long)MINSIZE);
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(room >= 0);
+ assert(room < (long)MINSIZE);
+
+ /* ... and alignment */
+ assert(aligned_OK(chunk2mem(p)));
+
+
+ /* ... and was allocated at front of an available chunk */
+ assert(prev_inuse(p));
+
+}
+
+
+#define check_free_chunk(P) do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif
+
+
+
+/*
+ Macro-based internal utilities
+*/
+
+
+/*
+ Linking chunks in bin lists.
+ Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+ Place chunk p of size s in its bin, in size order,
+ putting it ahead of others of same size.
+*/
+
+
+#define frontlink(P, S, IDX, BK, FD) \
+{ \
+ if (S < MAX_SMALLBIN_SIZE) \
+ { \
+ IDX = smallbin_index(S); \
+ mark_binblock(IDX); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+ else \
+ { \
+ IDX = bin_index(S); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ if (FD == BK) mark_binblock(IDX); \
+ else \
+ { \
+ while (FD != BK && S < chunksize(FD)) FD = FD->fd; \
+ BK = FD->bk; \
+ } \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+}
+
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD) \
+{ \
+ BK = P->bk; \
+ FD = P->fd; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+} \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P) \
+{ \
+ last_remainder->fd = last_remainder->bk = P; \
+ P->fd = P->bk = last_remainder; \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+ (last_remainder->fd = last_remainder->bk = last_remainder)
+
+
+
+
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+ static int fd = -1;
+#endif
+
+ if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+ /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
+ * there is no following chunk whose prev_size field could be used.
+ */
+ size = (size + SIZE_SZ + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+ if (fd < 0)
+ {
+ fd = open("/dev/zero", O_RDWR);
+ if(fd < 0) return 0;
+ }
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+ if(p == (mchunkptr)-1) return 0;
+
+ n_mmaps++;
+ if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+ /* We demand that eight bytes into a page must be 8-byte aligned. */
+ assert(aligned_OK(chunk2mem(p)));
+
+ /* The offset to the start of the mmapped region is stored
+ * in the prev_size field of the chunk; normally it is zero,
+ * but that can be changed in memalign().
+ */
+ p->prev_size = 0;
+ set_head(p, size|IS_MMAPPED);
+
+ mmapped_mem += size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T size = chunksize(p);
+ int ret;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+ n_mmaps--;
+ mmapped_mem -= (size + p->prev_size);
+
+ ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ INTERNAL_SIZE_T offset = p->prev_size;
+ INTERNAL_SIZE_T size = chunksize(p);
+ char *cp;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+ /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+ new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
+
+ cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+ if (cp == (char *)-1) return 0;
+
+ p = (mchunkptr)(cp + offset);
+
+ assert(aligned_OK(chunk2mem(p)));
+
+ assert((p->prev_size == offset));
+ set_head(p, (new_size - offset)|IS_MMAPPED);
+
+ mmapped_mem -= size + offset;
+ mmapped_mem += new_size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+
+
+
+/*
+ Extend the top-most chunk by obtaining memory from system.
+ Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+ char* brk; /* return value from sbrk */
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+ INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */
+ char* new_brk; /* return of 2nd sbrk call */
+ INTERNAL_SIZE_T top_size; /* new size of top chunk */
+
+ mchunkptr old_top = top; /* Record state of old top */
+ INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+ char* old_end = (char*)(chunk_at_offset(old_top, old_top_size));
+
+ /* Pad request with top_pad plus minimal overhead */
+
+ INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE;
+ unsigned long pagesz = malloc_getpagesize;
+
+ /* If not the first time through, round to preserve page boundary */
+ /* Otherwise, we need to correct to a page size below anyway. */
+ /* (We also correct below if an intervening foreign sbrk call.) */
+
+ if (sbrk_base != (char*)(-1))
+ sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+ brk = (char*)(MORECORE (sbrk_size));
+
+ /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+ if (brk == (char*)(MORECORE_FAILURE) ||
+ (brk < old_end && old_top != initial_top))
+ return;
+
+ sbrked_mem += sbrk_size;
+
+ if (brk == old_end) /* can just add bytes to current top */
+ {
+ top_size = sbrk_size + old_top_size;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ else
+ {
+ if (sbrk_base == (char*)(-1)) /* First time through. Record base */
+ sbrk_base = brk;
+ else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */
+ sbrked_mem += brk - (char*)old_end;
+
+ /* Guarantee alignment of first new chunk made from this space */
+ front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0)
+ {
+ correction = (MALLOC_ALIGNMENT) - front_misalign;
+ brk += correction;
+ }
+ else
+ correction = 0;
+
+ /* Guarantee the next brk will be at a page boundary */
+
+ correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) &
+ ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size));
+
+ /* Allocate correction */
+ new_brk = (char*)(MORECORE (correction));
+ if (new_brk == (char*)(MORECORE_FAILURE)) return;
+
+ sbrked_mem += correction;
+
+ top = (mchunkptr)brk;
+ top_size = new_brk - brk + correction;
+ set_head(top, top_size | PREV_INUSE);
+
+ if (old_top != initial_top)
+ {
+
+ /* There must have been an intervening foreign sbrk call. */
+ /* A double fencepost is necessary to prevent consolidation */
+
+ /* If not enough space to do this, then user did something very wrong */
+ if (old_top_size < MINSIZE)
+ {
+ set_head(top, PREV_INUSE); /* will force null return from malloc */
+ return;
+ }
+
+ /* Also keep size a multiple of MALLOC_ALIGNMENT */
+ old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+ set_head_size(old_top, old_top_size);
+ chunk_at_offset(old_top, old_top_size )->size =
+ SIZE_SZ|PREV_INUSE;
+ chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+ SIZE_SZ|PREV_INUSE;
+ /* If possible, release the rest. */
+ if (old_top_size >= MINSIZE)
+ fREe(chunk2mem(old_top));
+ }
+ }
+
+ if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+ max_sbrked_mem = sbrked_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+
+ /* We always land on a page boundary */
+ assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+
+
+
+/* Main public routines */
+
+
+/*
+ Malloc Algorthim:
+
+ The requested size is first converted into a usable form, `nb'.
+ This currently means to add 4 bytes overhead plus possibly more to
+ obtain 8-byte alignment and/or to obtain a size of at least
+ MINSIZE (currently 16 bytes), the smallest allocatable size.
+ (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+ From there, the first successful of the following steps is taken:
+
+ 1. The bin corresponding to the request size is scanned, and if
+ a chunk of exactly the right size is found, it is taken.
+
+ 2. The most recently remaindered chunk is used if it is big
+ enough. This is a form of (roving) first fit, used only in
+ the absence of exact fits. Runs of consecutive requests use
+ the remainder of the chunk used for the previous such request
+ whenever possible. This limited use of a first-fit style
+ allocation strategy tends to give contiguous chunks
+ coextensive lifetimes, which improves locality and can reduce
+ fragmentation in the long run.
+
+ 3. Other bins are scanned in increasing size order, using a
+ chunk big enough to fulfill the request, and splitting off
+ any remainder. This search is strictly by best-fit; i.e.,
+ the smallest (with ties going to approximately the least
+ recently used) chunk that fits is selected.
+
+ 4. If large enough, the chunk bordering the end of memory
+ (`top') is split off. (This use of `top' is in accord with
+ the best-fit search rule. In effect, `top' is treated as
+ larger (and thus less well fitting) than any other available
+ chunk since it can be extended to be as large as necessary
+ (up to system limitations).
+
+ 5. If the request size meets the mmap threshold and the
+ system supports mmap, and there are few enough currently
+ allocated mmapped regions, and a call to mmap succeeds,
+ the request is allocated via direct memory mapping.
+
+ 6. Otherwise, the top of memory is extended by
+ obtaining more space from the system (normally using sbrk,
+ but definable to anything else via the MORECORE macro).
+ Memory is gathered from the system (in system page-sized
+ units) in a way that allows chunks obtained across different
+ sbrk calls to be consolidated, but does not require
+ contiguous memory. Thus, it should be safe to intersperse
+ mallocs with other sbrk calls.
+
+
+ All allocations are made from the the `lowest' part of any found
+ chunk. (The implementation invariant is that prev_inuse is
+ always true of any allocated chunk; i.e., that each allocated
+ chunk borders either a previously allocated and still in-use chunk,
+ or the base of its memory arena.)
+
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mchunkptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T victim_size; /* its size */
+ int idx; /* index for bin traversal */
+ mbinptr bin; /* associated bin */
+ mchunkptr remainder; /* remainder from a split */
+ long remainder_size; /* its size */
+ int remainder_index; /* its bin index */
+ unsigned long block; /* block traverser bit */
+ int startidx; /* first bin of a traversed block */
+ mchunkptr fwd; /* misc temp for linking */
+ mchunkptr bck; /* misc temp for linking */
+ mbinptr q; /* misc temp */
+
+ INTERNAL_SIZE_T nb;
+
+ if ((long)bytes < 0) return 0;
+
+ nb = request2size(bytes); /* padded request size; */
+
+ /* Check for exact match in a bin */
+
+ if (is_small_request(nb)) /* Faster version for small requests */
+ {
+ idx = smallbin_index(nb);
+
+ /* No traversal or size check necessary for small bins. */
+
+ q = bin_at(idx);
+ victim = last(q);
+
+ /* Also scan the next one, since it would have a remainder < MINSIZE */
+ if (victim == q)
+ {
+ q = next_bin(q);
+ victim = last(q);
+ }
+ if (victim != q)
+ {
+ victim_size = chunksize(victim);
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+ }
+ else
+ {
+ idx = bin_index(nb);
+ bin = bin_at(idx);
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* too big */
+ {
+ --idx; /* adjust to rescan below after checking last remainder */
+ break;
+ }
+
+ else if (remainder_size >= 0) /* exact fit */
+ {
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+
+ ++idx;
+
+ }
+
+ /* Try to use the last split-off remainder */
+
+ if ( (victim = last_remainder->fd) != last_remainder)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* re-split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ clear_last_remainder;
+
+ if (remainder_size >= 0) /* exhaust */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* Else place in bin */
+
+ frontlink(victim, victim_size, remainder_index, bck, fwd);
+ }
+
+ /*
+ If there are any possibly nonempty big-enough blocks,
+ search for best fitting chunk by scanning bins in blockwidth units.
+ */
+
+ if ( (block = idx2binblock(idx)) <= binblocks)
+ {
+
+ /* Get to the first marked block */
+
+ if ( (block & binblocks) == 0)
+ {
+ /* force to an even block boundary */
+ idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+ block <<= 1;
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+
+ /* For each possibly nonempty block ... */
+ for (;;)
+ {
+ startidx = idx; /* (track incomplete blocks) */
+ q = bin = bin_at(idx);
+
+ /* For each bin in this block ... */
+ do
+ {
+ /* Find and use first big enough chunk ... */
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ unlink(victim, bck, fwd);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ else if (remainder_size >= 0) /* take */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ unlink(victim, bck, fwd);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ }
+
+ bin = next_bin(bin);
+
+ } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+ /* Clear out the block bit. */
+
+ do /* Possibly backtrack to try to clear a partial block */
+ {
+ if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+ {
+ binblocks &= ~block;
+ break;
+ }
+ --startidx;
+ q = prev_bin(q);
+ } while (first(q) == q);
+
+ /* Get to the next possibly nonempty block */
+
+ if ( (block <<= 1) <= binblocks && (block != 0) )
+ {
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+
+ /* Try to use top chunk */
+
+ /* Require that there be a remainder, ensuring top always exists */
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ {
+
+#if HAVE_MMAP
+ /* If big and would otherwise need to extend, try to use mmap instead */
+ if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+ (victim = mmap_chunk(nb)) != 0)
+ return chunk2mem(victim);
+#endif
+
+ /* Try to extend */
+ malloc_extend_top(nb);
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ return 0; /* propagate failure */
+ }
+
+ victim = top;
+ set_head(victim, nb | PREV_INUSE);
+ top = chunk_at_offset(victim, nb);
+ set_head(top, remainder_size | PREV_INUSE);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+
+}
+
+
+
+
+/*
+
+ free() algorithm :
+
+ cases:
+
+ 1. free(0) has no effect.
+
+ 2. If the chunk was allocated via mmap, it is release via munmap().
+
+ 3. If a returned chunk borders the current high end of memory,
+ it is consolidated into the top, and if the total unused
+ topmost memory exceeds the trim threshold, malloc_trim is
+ called.
+
+ 4. Other chunks are consolidated as they arrive, and
+ placed in corresponding bins. (This includes the case of
+ consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T hd; /* its head field */
+ INTERNAL_SIZE_T sz; /* its size */
+ int idx; /* its bin index */
+ mchunkptr next; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsz; /* its size */
+ INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+ int islr; /* track whether merging with last_remainder */
+
+ if (mem == 0) /* free(0) has no effect */
+ return;
+
+ p = mem2chunk(mem);
+ hd = p->size;
+
+#if HAVE_MMAP
+ if (hd & IS_MMAPPED) /* release mmapped memory. */
+ {
+ munmap_chunk(p);
+ return;
+ }
+#endif
+
+ check_inuse_chunk(p);
+
+ sz = hd & ~PREV_INUSE;
+ next = chunk_at_offset(p, sz);
+ nextsz = chunksize(next);
+
+ if (next == top) /* merge with top */
+ {
+ sz += nextsz;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -((long) prevsz));
+ sz += prevsz;
+ unlink(p, bck, fwd);
+ }
+
+ set_head(p, sz | PREV_INUSE);
+ top = p;
+ if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
+ malloc_trim(top_pad);
+ return;
+ }
+
+ set_head(next, nextsz); /* clear inuse bit */
+
+ islr = 0;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -((long) prevsz));
+ sz += prevsz;
+
+ if (p->fd == last_remainder) /* keep as last_remainder */
+ islr = 1;
+ else
+ unlink(p, bck, fwd);
+ }
+
+ if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
+ {
+ sz += nextsz;
+
+ if (!islr && next->fd == last_remainder) /* re-insert last_remainder */
+ {
+ islr = 1;
+ link_last_remainder(p);
+ }
+ else
+ unlink(next, bck, fwd);
+ }
+
+
+ set_head(p, sz | PREV_INUSE);
+ set_foot(p, sz);
+ if (!islr)
+ frontlink(p, sz, idx, bck, fwd);
+}
+
+
+
+
+
+/*
+
+ Realloc algorithm:
+
+ Chunks that were obtained via mmap cannot be extended or shrunk
+ unless HAVE_MREMAP is defined, in which case mremap is used.
+ Otherwise, if their reallocation is for additional space, they are
+ copied. If for less, they are just left alone.
+
+ Otherwise, if the reallocation is for additional space, and the
+ chunk can be extended, it is, else a malloc-copy-free sequence is
+ taken. There are several different ways that a chunk could be
+ extended. All are tried:
+
+ * Extending forward into following adjacent free chunk.
+ * Shifting backwards, joining preceding adjacent space
+ * Both shifting backwards and extending forward.
+ * Extending into newly sbrked space
+
+ Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+
+ If the reallocation is for less space, and the new request is for
+ a `small' (<512 bytes) size, then the newly unused space is lopped
+ off and freed.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is no longer supported.
+ I don't know of any programs still relying on this feature,
+ and allowing it would also allow too many other incorrect
+ usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ mchunkptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ mchunkptr next; /* next contiguous chunk after oldp */
+ INTERNAL_SIZE_T nextsize; /* its size */
+
+ mchunkptr prev; /* previous contiguous chunk before oldp */
+ INTERNAL_SIZE_T prevsize; /* its size */
+
+ mchunkptr remainder; /* holds split off extra space from newp */
+ INTERNAL_SIZE_T remainder_size; /* its size */
+
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) { fREe(oldmem); return 0; }
+#endif
+
+ if ((long)bytes < 0) return 0;
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == 0) return mALLOc(bytes);
+
+ newp = oldp = mem2chunk(oldmem);
+ newsize = oldsize = chunksize(oldp);
+
+
+ nb = request2size(bytes);
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(oldp))
+ {
+#if HAVE_MREMAP
+ newp = mremap_chunk(oldp, nb);
+ if(newp) return chunk2mem(newp);
+#endif
+ /* Note the extra SIZE_SZ overhead. */
+ if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(bytes);
+ if (newmem == 0) return 0; /* propagate failure */
+ MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+ munmap_chunk(oldp);
+ return newmem;
+ }
+#endif
+
+ check_inuse_chunk(oldp);
+
+ if ((long)(oldsize) < (long)(nb))
+ {
+
+ /* Try expanding forward */
+
+ next = chunk_at_offset(oldp, oldsize);
+ if (next == top || !inuse(next))
+ {
+ nextsize = chunksize(next);
+
+ /* Forward into top only if a remainder */
+ if (next == top)
+ {
+ if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ newsize += nextsize;
+ top = chunk_at_offset(oldp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(oldp, nb);
+ return chunk2mem(oldp);
+ }
+ }
+
+ /* Forward into next chunk */
+ else if (((long)(nextsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ newsize += nextsize;
+ goto split;
+ }
+ }
+ else
+ {
+ next = 0;
+ nextsize = 0;
+ }
+
+ /* Try shifting backwards. */
+
+ if (!prev_inuse(oldp))
+ {
+ prev = prev_chunk(oldp);
+ prevsize = chunksize(prev);
+
+ /* try forward + backward first to save a later consolidation */
+
+ if (next != 0)
+ {
+ /* into top */
+ if (next == top)
+ {
+ if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize + nextsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ top = chunk_at_offset(newp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(newp, nb);
+ return newmem;
+ }
+ }
+
+ /* into next chunk */
+ else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += nextsize + prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* backward only */
+ if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* Must allocate */
+
+ newmem = mALLOc (bytes);
+
+ if (newmem == 0) /* propagate failure */
+ return 0;
+
+ /* Avoid copy if newp is next chunk after oldp. */
+ /* (This can only happen when new chunk is sbrk'ed.) */
+
+ if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+ {
+ newsize += chunksize(newp);
+ newp = oldp;
+ goto split;
+ }
+
+ /* Otherwise copy, free, and exit */
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ fREe(oldmem);
+ return newmem;
+ }
+
+
+ split: /* split off extra room in old or expanded chunk */
+
+ if (newsize - nb >= MINSIZE) /* split off remainder */
+ {
+ remainder = chunk_at_offset(newp, nb);
+ remainder_size = newsize - nb;
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_inuse_bit_at_offset(remainder, remainder_size);
+ fREe(chunk2mem(remainder)); /* let free() deal with it */
+ }
+ else
+ {
+ set_head_size(newp, newsize);
+ set_inuse_bit_at_offset(newp, newsize);
+ }
+
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+}
+
+
+
+
+/*
+
+ memalign algorithm:
+
+ memalign requests more than enough space from malloc, finds a spot
+ within that chunk that meets the alignment request, and then
+ possibly frees the leading and trailing space.
+
+ The alignment argument must be a power of two. This property is not
+ checked by memalign, so misuse may result in random runtime errors.
+
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ mchunkptr p; /* corresponding chunk */
+ char* brk; /* alignment point within p */
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */
+ mchunkptr remainder; /* spare room at end to split off */
+ long remainder_size; /* its size */
+
+ if ((long)bytes < 0) return 0;
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ nb = request2size(bytes);
+ m = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+ if (m == 0) return 0; /* propagate failure */
+
+ p = mem2chunk(m);
+
+ if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+ {
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ return chunk2mem(p); /* nothing more to do */
+#endif
+ }
+ else /* misaligned */
+ {
+ /*
+ Find an aligned spot inside chunk.
+ Since we need to give back leading space in a chunk of at
+ least MINSIZE, if the first calculation places us at
+ a spot with less than MINSIZE leader, we can move to the
+ next aligned spot -- we've allocated enough total room so that
+ this is always possible.
+ */
+
+ brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment));
+ if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
+
+ newp = (mchunkptr)brk;
+ leadsize = brk - (char*)(p);
+ newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ {
+ newp->prev_size = p->prev_size + leadsize;
+ set_head(newp, newsize|IS_MMAPPED);
+ return chunk2mem(newp);
+ }
+#endif
+
+ /* give back leader, use the rest */
+
+ set_head(newp, newsize | PREV_INUSE);
+ set_inuse_bit_at_offset(newp, newsize);
+ set_head_size(p, leadsize);
+ fREe(chunk2mem(p));
+ p = newp;
+
+ assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+
+ remainder_size = chunksize(p) - nb;
+
+ if (remainder_size >= (long)MINSIZE)
+ {
+ remainder = chunk_at_offset(p, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_head_size(p, nb);
+ fREe(chunk2mem(remainder));
+ }
+
+ check_inuse_chunk(p);
+ return chunk2mem(p);
+
+}
+
+
+
+
+/*
+ valloc just invokes memalign with alignment argument equal
+ to the page size of the system (or as near to this as can
+ be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+ pvalloc just invokes valloc for the nearest pagesize
+ that will accommodate request
+*/
+
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+ size_t pagesize = malloc_getpagesize;
+ return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+
+ calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+ mchunkptr p;
+ INTERNAL_SIZE_T csz;
+
+ INTERNAL_SIZE_T sz = n * elem_size;
+
+
+ /* check if expand_top called, in which case don't need to clear */
+#if MORECORE_CLEARS
+ mchunkptr oldtop = top;
+ INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+ Void_t* mem = mALLOc (sz);
+
+ if ((long)n < 0) return 0;
+
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+
+ /* Two optional cases in which clearing not necessary */
+
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(p)) return mem;
+#endif
+
+ csz = chunksize(p);
+
+#if MORECORE_CLEARS
+ if (p == oldtop && csz > oldtopsize)
+ {
+ /* clear only the bytes from non-freshly-sbrked memory */
+ csz = oldtopsize;
+ }
+#endif
+
+ MALLOC_ZERO(mem, csz - SIZE_SZ);
+ return mem;
+ }
+}
+
+/*
+
+ cfree just calls free. It is needed/defined on some systems
+ that pair it with calloc, presumably for odd historical reasons.
+
+*/
+
+#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
+#if __STD_C
+void cfree(Void_t *mem)
+#else
+void cfree(mem) Void_t *mem;
+#endif
+{
+ fREe(mem);
+}
+#endif
+
+
+
+/*
+
+ Malloc_trim gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+
+*/
+
+#if __STD_C
+int malloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ char* current_brk; /* address returned by pre-check sbrk call */
+ char* new_brk; /* address returned by negative sbrk call */
+
+ unsigned long pagesz = malloc_getpagesize;
+
+ top_size = chunksize(top);
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra < (long)pagesz) /* Not enough memory to release */
+ return 0;
+
+ else
+ {
+ /* Test to make sure no one else called sbrk */
+ current_brk = (char*)(MORECORE (0));
+ if (current_brk != (char*)(top) + top_size)
+ return 0; /* Apparently we don't own memory; must fail */
+
+ else
+ {
+ new_brk = (char*)(MORECORE (-extra));
+
+ if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+ {
+ /* Try to figure out what we have */
+ current_brk = (char*)(MORECORE (0));
+ top_size = current_brk - (char*)top;
+ if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+ {
+ sbrked_mem = current_brk - sbrk_base;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ check_chunk(top);
+ return 0;
+ }
+
+ else
+ {
+ /* Success. Adjust top accordingly. */
+ set_head(top, (top_size - extra) | PREV_INUSE);
+ sbrked_mem -= extra;
+ check_chunk(top);
+ return 1;
+ }
+ }
+ }
+}
+
+
+
+/*
+ malloc_usable_size:
+
+ This routine tells you how many bytes you can actually use in an
+ allocated chunk, which may be more than you requested (although
+ often not). You can use this many bytes without worrying about
+ overwriting other allocated objects. Not a particularly great
+ programming practice, but still sometimes useful.
+
+*/
+
+#if __STD_C
+size_t malloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p;
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+ if(!chunk_is_mmapped(p))
+ {
+ if (!inuse(p)) return 0;
+ check_inuse_chunk(p);
+ return chunksize(p) - SIZE_SZ;
+ }
+ return chunksize(p) - 2*SIZE_SZ;
+ }
+}
+
+
+
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+static void malloc_update_mallinfo()
+{
+ int i;
+ mbinptr b;
+ mchunkptr p;
+#if DEBUG
+ mchunkptr q;
+#endif
+
+ INTERNAL_SIZE_T avail = chunksize(top);
+ int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
+
+ for (i = 1; i < NAV; ++i)
+ {
+ b = bin_at(i);
+ for (p = last(b); p != b; p = p->bk)
+ {
+#if DEBUG
+ check_free_chunk(p);
+ for (q = next_chunk(p);
+ q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
+ q = next_chunk(q))
+ check_inuse_chunk(q);
+#endif
+ avail += chunksize(p);
+ navail++;
+ }
+ }
+
+ current_mallinfo.ordblks = navail;
+ current_mallinfo.uordblks = sbrked_mem - avail;
+ current_mallinfo.fordblks = avail;
+ current_mallinfo.hblks = n_mmaps;
+ current_mallinfo.hblkhd = mmapped_mem;
+ current_mallinfo.keepcost = chunksize(top);
+
+}
+
+
+
+/*
+
+ malloc_stats:
+
+ Prints on stderr the amount of space obtain from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), the maximum
+ number of simultaneous mmap regions used, and the current number
+ of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. (Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead.)
+
+*/
+
+void malloc_stats()
+{
+ malloc_update_mallinfo();
+ fprintf(stderr, "max system bytes = %10u\n",
+ (unsigned int)(max_total_mem));
+ fprintf(stderr, "system bytes = %10u\n",
+ (unsigned int)(sbrked_mem + mmapped_mem));
+ fprintf(stderr, "in use bytes = %10u\n",
+ (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+ fprintf(stderr, "max mmap regions = %10u\n",
+ (unsigned int)max_n_mmaps);
+#endif
+}
+
+/*
+ mallinfo returns a copy of updated current mallinfo.
+*/
+
+struct mallinfo mALLINFo()
+{
+ malloc_update_mallinfo();
+ return current_mallinfo;
+}
+
+
+
+
+/*
+ mallopt:
+
+ mallopt is the general SVID/XPG interface to tunable parameters.
+ The format is to provide a (parameter-number, parameter-value) pair.
+ mallopt then sets the corresponding parameter to the argument
+ value if it can (i.e., so long as the value is meaningful),
+ and returns 1 if successful else 0.
+
+ See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ switch(param_number)
+ {
+ case M_TRIM_THRESHOLD:
+ trim_threshold = value; return 1;
+ case M_TOP_PAD:
+ top_pad = value; return 1;
+ case M_MMAP_THRESHOLD:
+ mmap_threshold = value; return 1;
+ case M_MMAP_MAX:
+#if HAVE_MMAP
+ n_mmaps_max = value; return 1;
+#else
+ if (value != 0) return 0; else n_mmaps_max = value; return 1;
+#endif
+
+ default:
+ return 0;
+ }
+}
+
+/*
+
+History:
+
+ V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
+ * return null for negative arguments
+ * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com>
+ * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+ (e.g. WIN32 platforms)
+ * Cleanup up header file inclusion for WIN32 platforms
+ * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+ * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+ memory allocation routines
+ * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+ * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+ usage of 'assert' in non-WIN32 code
+ * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+ avoid infinite loop
+ * Always call 'fREe()' rather than 'free()'
+
+ V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
+ * Fixed ordering problem with boundary-stamping
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
diff --git a/roms/u-boot/common/edid.c b/roms/u-boot/common/edid.c
new file mode 100644
index 000000000..fa85bcd6a
--- /dev/null
+++ b/roms/u-boot/common/edid.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * (C) Copyright 2010
+ * Petr Stetiar <ynezz@true.cz>
+ *
+ * Contains stolen code from ddcprobe project which is:
+ * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com>
+ */
+
+#include <common.h>
+#include <edid.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+int edid_check_info(struct edid1_info *edid_info)
+{
+ if ((edid_info == NULL) || (edid_info->version == 0))
+ return -1;
+
+ if (memcmp(edid_info->header, "\x0\xff\xff\xff\xff\xff\xff\x0", 8))
+ return -1;
+
+ if (edid_info->version == 0xff && edid_info->revision == 0xff)
+ return -1;
+
+ return 0;
+}
+
+int edid_check_checksum(u8 *edid_block)
+{
+ u8 checksum = 0;
+ int i;
+
+ for (i = 0; i < 128; i++)
+ checksum += edid_block[i];
+
+ return (checksum == 0) ? 0 : -EINVAL;
+}
+
+int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin,
+ unsigned int *hmax, unsigned int *vmin,
+ unsigned int *vmax)
+{
+ int i;
+ struct edid_monitor_descriptor *monitor;
+
+ *hmin = *hmax = *vmin = *vmax = 0;
+ if (edid_check_info(edid))
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE(edid->monitor_details.descriptor); i++) {
+ monitor = &edid->monitor_details.descriptor[i];
+ if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) {
+ *hmin = monitor->data.range_data.horizontal_min;
+ *hmax = monitor->data.range_data.horizontal_max;
+ *vmin = monitor->data.range_data.vertical_min;
+ *vmax = monitor->data.range_data.vertical_max;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/* Set all parts of a timing entry to the same value */
+static void set_entry(struct timing_entry *entry, u32 value)
+{
+ entry->min = value;
+ entry->typ = value;
+ entry->max = value;
+}
+
+/**
+ * decode_timing() - Decoding an 18-byte detailed timing record
+ *
+ * @buf: Pointer to EDID detailed timing record
+ * @timing: Place to put timing
+ */
+static void decode_timing(u8 *buf, struct display_timing *timing)
+{
+ uint x_mm, y_mm;
+ unsigned int ha, hbl, hso, hspw, hborder;
+ unsigned int va, vbl, vso, vspw, vborder;
+ struct edid_detailed_timing *t = (struct edid_detailed_timing *)buf;
+
+ /* Edid contains pixel clock in terms of 10KHz */
+ set_entry(&timing->pixelclock, (buf[0] + (buf[1] << 8)) * 10000);
+ x_mm = (buf[12] + ((buf[14] & 0xf0) << 4));
+ y_mm = (buf[13] + ((buf[14] & 0x0f) << 8));
+ ha = (buf[2] + ((buf[4] & 0xf0) << 4));
+ hbl = (buf[3] + ((buf[4] & 0x0f) << 8));
+ hso = (buf[8] + ((buf[11] & 0xc0) << 2));
+ hspw = (buf[9] + ((buf[11] & 0x30) << 4));
+ hborder = buf[15];
+ va = (buf[5] + ((buf[7] & 0xf0) << 4));
+ vbl = (buf[6] + ((buf[7] & 0x0f) << 8));
+ vso = ((buf[10] >> 4) + ((buf[11] & 0x0c) << 2));
+ vspw = ((buf[10] & 0x0f) + ((buf[11] & 0x03) << 4));
+ vborder = buf[16];
+
+ set_entry(&timing->hactive, ha);
+ set_entry(&timing->hfront_porch, hso);
+ set_entry(&timing->hback_porch, hbl - hso - hspw);
+ set_entry(&timing->hsync_len, hspw);
+
+ set_entry(&timing->vactive, va);
+ set_entry(&timing->vfront_porch, vso);
+ set_entry(&timing->vback_porch, vbl - vso - vspw);
+ set_entry(&timing->vsync_len, vspw);
+
+ timing->flags = 0;
+ if (EDID_DETAILED_TIMING_FLAG_HSYNC_POLARITY(*t))
+ timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
+ else
+ timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
+ if (EDID_DETAILED_TIMING_FLAG_VSYNC_POLARITY(*t))
+ timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+ else
+ timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
+
+ if (EDID_DETAILED_TIMING_FLAG_INTERLACED(*t))
+ timing->flags = DISPLAY_FLAGS_INTERLACED;
+
+ debug("Detailed mode clock %u Hz, %d mm x %d mm\n"
+ " %04x %04x %04x %04x hborder %x\n"
+ " %04x %04x %04x %04x vborder %x\n",
+ timing->pixelclock.typ,
+ x_mm, y_mm,
+ ha, ha + hso, ha + hso + hspw,
+ ha + hbl, hborder,
+ va, va + vso, va + vso + vspw,
+ va + vbl, vborder);
+}
+
+/**
+ * Check if HDMI vendor specific data block is present in CEA block
+ * @param info CEA extension block
+ * @return true if block is found
+ */
+static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info)
+{
+ u8 end, i = 0;
+
+ /* check for end of data block */
+ end = info->dtd_offset;
+ if (end == 0)
+ end = sizeof(info->data);
+ if (end < 4 || end > sizeof(info->data))
+ return false;
+ end -= 4;
+
+ while (i < end) {
+ /* Look for vendor specific data block of appropriate size */
+ if ((EDID_CEA861_DB_TYPE(*info, i) == EDID_CEA861_DB_VENDOR) &&
+ (EDID_CEA861_DB_LEN(*info, i) >= 5)) {
+ u8 *db = &info->data[i + 1];
+ u32 oui = db[0] | (db[1] << 8) | (db[2] << 16);
+
+ if (oui == HDMI_IEEE_OUI)
+ return true;
+ }
+ i += EDID_CEA861_DB_LEN(*info, i) + 1;
+ }
+
+ return false;
+}
+
+static bool edid_find_valid_timing(void *buf, int count,
+ struct display_timing *timing,
+ bool (*mode_valid)(void *priv,
+ const struct display_timing *timing),
+ void *mode_valid_priv)
+{
+ struct edid_detailed_timing *t = buf;
+ bool found = false;
+ int i;
+
+ for (i = 0; i < count && !found; i++, t++)
+ if (EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) != 0) {
+ decode_timing((u8 *)t, timing);
+ if (mode_valid)
+ found = mode_valid(mode_valid_priv,
+ timing);
+ else
+ found = true;
+ }
+
+ return found;
+}
+
+int edid_get_timing_validate(u8 *buf, int buf_size,
+ struct display_timing *timing,
+ int *panel_bits_per_colourp,
+ bool (*mode_valid)(void *priv,
+ const struct display_timing *timing),
+ void *mode_valid_priv)
+{
+ struct edid1_info *edid = (struct edid1_info *)buf;
+ bool found;
+
+ if (buf_size < sizeof(*edid) || edid_check_info(edid)) {
+ debug("%s: Invalid buffer\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) {
+ debug("%s: Not a digital display\n", __func__);
+ return -ENOSYS;
+ }
+
+ if (!EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(*edid)) {
+ debug("%s: No preferred timing\n", __func__);
+ return -ENOENT;
+ }
+
+ /* Look for detailed timing in base EDID */
+ found = edid_find_valid_timing(edid->monitor_details.descriptor, 4,
+ timing, mode_valid, mode_valid_priv);
+
+ /* Look for detailed timing in CTA-861 Extension Block */
+ if (!found && edid->extension_flag && buf_size >= EDID_EXT_SIZE) {
+ struct edid_cea861_info *info =
+ (struct edid_cea861_info *)(buf + sizeof(*edid));
+
+ if (info->extension_tag == EDID_CEA861_EXTENSION_TAG) {
+ int count = EDID_CEA861_DTD_COUNT(*info);
+ int offset = info->dtd_offset;
+ int size = count * sizeof(struct edid_detailed_timing);
+
+ if (offset >= 4 && offset + size < EDID_SIZE)
+ found = edid_find_valid_timing(
+ (u8 *)info + offset, count, timing,
+ mode_valid, mode_valid_priv);
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ if (edid->version != 1 || edid->revision < 4) {
+ debug("%s: EDID version %d.%d does not have required info\n",
+ __func__, edid->version, edid->revision);
+ *panel_bits_per_colourp = -1;
+ } else {
+ *panel_bits_per_colourp =
+ ((edid->video_input_definition & 0x70) >> 3) + 4;
+ }
+
+ timing->hdmi_monitor = false;
+ if (edid->extension_flag && (buf_size >= EDID_EXT_SIZE)) {
+ struct edid_cea861_info *info =
+ (struct edid_cea861_info *)(buf + sizeof(*edid));
+
+ if (info->extension_tag == EDID_CEA861_EXTENSION_TAG)
+ timing->hdmi_monitor = cea_is_hdmi_vsdb_present(info);
+ }
+
+ return 0;
+}
+
+int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
+ int *panel_bits_per_colourp)
+{
+ return edid_get_timing_validate(buf, buf_size, timing,
+ panel_bits_per_colourp, NULL, NULL);
+}
+
+
+/**
+ * Snip the tailing whitespace/return of a string.
+ *
+ * @param string The string to be snipped
+ * @return the snipped string
+ */
+static char *snip(char *string)
+{
+ char *s;
+
+ /*
+ * This is always a 13 character buffer
+ * and it's not always terminated.
+ */
+ string[12] = '\0';
+ s = &string[strlen(string) - 1];
+
+ while (s >= string && (isspace(*s) || *s == '\n' || *s == '\r' ||
+ *s == '\0'))
+ *(s--) = '\0';
+
+ return string;
+}
+
+/**
+ * Print an EDID monitor descriptor block
+ *
+ * @param monitor The EDID monitor descriptor block
+ * @have_timing Modifies to 1 if the desciptor contains timing info
+ */
+static void edid_print_dtd(struct edid_monitor_descriptor *monitor,
+ unsigned int *have_timing)
+{
+ unsigned char *bytes = (unsigned char *)monitor;
+ struct edid_detailed_timing *timing =
+ (struct edid_detailed_timing *)monitor;
+
+ if (bytes[0] == 0 && bytes[1] == 0) {
+ if (monitor->type == EDID_MONITOR_DESCRIPTOR_SERIAL)
+ printf("Monitor serial number: %s\n",
+ snip(monitor->data.string));
+ else if (monitor->type == EDID_MONITOR_DESCRIPTOR_ASCII)
+ printf("Monitor ID: %s\n",
+ snip(monitor->data.string));
+ else if (monitor->type == EDID_MONITOR_DESCRIPTOR_NAME)
+ printf("Monitor name: %s\n",
+ snip(monitor->data.string));
+ else if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE)
+ printf("Monitor range limits, horizontal sync: "
+ "%d-%d kHz, vertical refresh: "
+ "%d-%d Hz, max pixel clock: "
+ "%d MHz\n",
+ monitor->data.range_data.horizontal_min,
+ monitor->data.range_data.horizontal_max,
+ monitor->data.range_data.vertical_min,
+ monitor->data.range_data.vertical_max,
+ monitor->data.range_data.pixel_clock_max * 10);
+ } else {
+ uint32_t pixclock, h_active, h_blanking, v_active, v_blanking;
+ uint32_t h_total, v_total, vfreq;
+
+ pixclock = EDID_DETAILED_TIMING_PIXEL_CLOCK(*timing);
+ h_active = EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*timing);
+ h_blanking = EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*timing);
+ v_active = EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*timing);
+ v_blanking = EDID_DETAILED_TIMING_VERTICAL_BLANKING(*timing);
+
+ h_total = h_active + h_blanking;
+ v_total = v_active + v_blanking;
+ if (v_total > 0 && h_total > 0)
+ vfreq = pixclock / (v_total * h_total);
+ else
+ vfreq = 1; /* Error case */
+ printf("\t%dx%d\%c\t%d Hz (detailed)\n", h_active,
+ v_active, h_active > 1000 ? ' ' : '\t', vfreq);
+ *have_timing = 1;
+ }
+}
+
+/**
+ * Get the manufacturer name from an EDID info.
+ *
+ * @param edid_info The EDID info to be printed
+ * @param name Returns the string of the manufacturer name
+ */
+static void edid_get_manufacturer_name(struct edid1_info *edid, char *name)
+{
+ name[0] = EDID1_INFO_MANUFACTURER_NAME_CHAR1(*edid) + 'A' - 1;
+ name[1] = EDID1_INFO_MANUFACTURER_NAME_CHAR2(*edid) + 'A' - 1;
+ name[2] = EDID1_INFO_MANUFACTURER_NAME_CHAR3(*edid) + 'A' - 1;
+ name[3] = '\0';
+}
+
+void edid_print_info(struct edid1_info *edid_info)
+{
+ int i;
+ char manufacturer[4];
+ unsigned int have_timing = 0;
+ uint32_t serial_number;
+
+ if (edid_check_info(edid_info)) {
+ printf("Not a valid EDID\n");
+ return;
+ }
+
+ printf("EDID version: %d.%d\n",
+ edid_info->version, edid_info->revision);
+
+ printf("Product ID code: %04x\n", EDID1_INFO_PRODUCT_CODE(*edid_info));
+
+ edid_get_manufacturer_name(edid_info, manufacturer);
+ printf("Manufacturer: %s\n", manufacturer);
+
+ serial_number = EDID1_INFO_SERIAL_NUMBER(*edid_info);
+ if (serial_number != 0xffffffff) {
+ if (strcmp(manufacturer, "MAG") == 0)
+ serial_number -= 0x7000000;
+ if (strcmp(manufacturer, "OQI") == 0)
+ serial_number -= 456150000;
+ if (strcmp(manufacturer, "VSC") == 0)
+ serial_number -= 640000000;
+ }
+ printf("Serial number: %08x\n", serial_number);
+ printf("Manufactured in week: %d year: %d\n",
+ edid_info->week, edid_info->year + 1990);
+
+ printf("Video input definition: %svoltage level %d%s%s%s%s%s\n",
+ EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid_info) ?
+ "digital signal, " : "analog signal, ",
+ EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(*edid_info),
+ EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(*edid_info) ?
+ ", blank to black" : "",
+ EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(*edid_info) ?
+ ", separate sync" : "",
+ EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(*edid_info) ?
+ ", composite sync" : "",
+ EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(*edid_info) ?
+ ", sync on green" : "",
+ EDID1_INFO_VIDEO_INPUT_SERRATION_V(*edid_info) ?
+ ", serration v" : "");
+
+ printf("Monitor is %s\n",
+ EDID1_INFO_FEATURE_RGB(*edid_info) ? "RGB" : "non-RGB");
+
+ printf("Maximum visible display size: %d cm x %d cm\n",
+ edid_info->max_size_horizontal,
+ edid_info->max_size_vertical);
+
+ printf("Power management features: %s%s, %s%s, %s%s\n",
+ EDID1_INFO_FEATURE_ACTIVE_OFF(*edid_info) ?
+ "" : "no ", "active off",
+ EDID1_INFO_FEATURE_SUSPEND(*edid_info) ? "" : "no ", "suspend",
+ EDID1_INFO_FEATURE_STANDBY(*edid_info) ? "" : "no ", "standby");
+
+ printf("Estabilished timings:\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_720X400_70(*edid_info))
+ printf("\t720x400\t\t70 Hz (VGA 640x400, IBM)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_720X400_88(*edid_info))
+ printf("\t720x400\t\t88 Hz (XGA2)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_640X480_60(*edid_info))
+ printf("\t640x480\t\t60 Hz (VGA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_640X480_67(*edid_info))
+ printf("\t640x480\t\t67 Hz (Mac II, Apple)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_640X480_72(*edid_info))
+ printf("\t640x480\t\t72 Hz (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_640X480_75(*edid_info))
+ printf("\t640x480\t\t75 Hz (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_800X600_56(*edid_info))
+ printf("\t800x600\t\t56 Hz (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_800X600_60(*edid_info))
+ printf("\t800x600\t\t60 Hz (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_800X600_72(*edid_info))
+ printf("\t800x600\t\t72 Hz (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_800X600_75(*edid_info))
+ printf("\t800x600\t\t75 Hz (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_832X624_75(*edid_info))
+ printf("\t832x624\t\t75 Hz (Mac II)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(*edid_info))
+ printf("\t1024x768\t87 Hz Interlaced (8514A)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(*edid_info))
+ printf("\t1024x768\t60 Hz (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(*edid_info))
+ printf("\t1024x768\t70 Hz (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(*edid_info))
+ printf("\t1024x768\t75 Hz (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(*edid_info))
+ printf("\t1280x1024\t75 (VESA)\n");
+ if (EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(*edid_info))
+ printf("\t1152x870\t75 (Mac II)\n");
+
+ /* Standard timings. */
+ printf("Standard timings:\n");
+ for (i = 0; i < ARRAY_SIZE(edid_info->standard_timings); i++) {
+ unsigned int aspect = 10000;
+ unsigned int x, y;
+ unsigned char xres, vfreq;
+
+ xres = EDID1_INFO_STANDARD_TIMING_XRESOLUTION(*edid_info, i);
+ vfreq = EDID1_INFO_STANDARD_TIMING_VFREQ(*edid_info, i);
+ if ((xres != vfreq) ||
+ ((xres != 0) && (xres != 1)) ||
+ ((vfreq != 0) && (vfreq != 1))) {
+ switch (EDID1_INFO_STANDARD_TIMING_ASPECT(*edid_info,
+ i)) {
+ case ASPECT_625:
+ aspect = 6250;
+ break;
+ case ASPECT_75:
+ aspect = 7500;
+ break;
+ case ASPECT_8:
+ aspect = 8000;
+ break;
+ case ASPECT_5625:
+ aspect = 5625;
+ break;
+ }
+ x = (xres + 31) * 8;
+ y = x * aspect / 10000;
+ printf("\t%dx%d%c\t%d Hz\n", x, y,
+ x > 1000 ? ' ' : '\t', (vfreq & 0x3f) + 60);
+ have_timing = 1;
+ }
+ }
+
+ /* Detailed timing information. */
+ for (i = 0; i < ARRAY_SIZE(edid_info->monitor_details.descriptor);
+ i++) {
+ edid_print_dtd(&edid_info->monitor_details.descriptor[i],
+ &have_timing);
+ }
+
+ if (!have_timing)
+ printf("\tNone\n");
+}
diff --git a/roms/u-boot/common/eeprom/eeprom_field.c b/roms/u-boot/common/eeprom/eeprom_field.c
new file mode 100644
index 000000000..f56eebe67
--- /dev/null
+++ b/roms/u-boot/common/eeprom/eeprom_field.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009-2016 CompuLab, Ltd.
+ *
+ * Authors: Nikita Kiryanov <nikita@compulab.co.il>
+ * Igor Grinberg <grinberg@compulab.co.il>
+ */
+
+#include <common.h>
+#include <linux/string.h>
+#include <eeprom_field.h>
+
+static void __eeprom_field_print_bin(const struct eeprom_field *field,
+ char *delimiter, bool reverse)
+{
+ int i;
+ int from = reverse ? field->size - 1 : 0;
+ int to = reverse ? 0 : field->size - 1;
+
+ printf(PRINT_FIELD_SEGMENT, field->name);
+ for (i = from; i != to; reverse ? i-- : i++)
+ printf("%02x%s", field->buf[i], delimiter);
+
+ printf("%02x\n", field->buf[i]);
+}
+
+static int __eeprom_field_update_bin(struct eeprom_field *field,
+ const char *value, bool reverse)
+{
+ int len = strlen(value);
+ int k, j, i = reverse ? len - 1 : 0;
+ unsigned char byte;
+ char *endptr;
+
+ /* each two characters in the string fit in one byte */
+ if (len > field->size * 2)
+ return -1;
+
+ memset(field->buf, 0, field->size);
+
+ /* i - string iterator, j - buf iterator */
+ for (j = 0; j < field->size; j++) {
+ byte = 0;
+ char tmp[3] = { 0, 0, 0 };
+
+ if ((reverse && i < 0) || (!reverse && i >= len))
+ break;
+
+ for (k = 0; k < 2; k++) {
+ if (reverse && i == 0) {
+ tmp[k] = value[i];
+ break;
+ }
+
+ tmp[k] = value[reverse ? i - 1 + k : i + k];
+ }
+
+ byte = simple_strtoul(tmp, &endptr, 0);
+ if (*endptr != '\0' || byte < 0)
+ return -1;
+
+ field->buf[j] = byte;
+ i = reverse ? i - 2 : i + 2;
+ }
+
+ return 0;
+}
+
+static int __eeprom_field_update_bin_delim(struct eeprom_field *field,
+ char *value, char *delimiter)
+{
+ int count = 0;
+ int i, val;
+ const char *tmp = value;
+ char *tok;
+ char *endptr;
+
+ tmp = strstr(tmp, delimiter);
+ while (tmp != NULL) {
+ count++;
+ tmp++;
+ tmp = strstr(tmp, delimiter);
+ }
+
+ if (count > field->size)
+ return -1;
+
+ tok = strtok(value, delimiter);
+ for (i = 0; tok && i < field->size; i++) {
+ val = simple_strtoul(tok, &endptr, 0);
+ if (*endptr != '\0')
+ return -1;
+
+ /* here we assume that each tok is no more than byte long */
+ field->buf[i] = (unsigned char)val;
+ tok = strtok(NULL, delimiter);
+ }
+
+ return 0;
+}
+
+/**
+ * eeprom_field_print_bin() - print a field which contains binary data
+ *
+ * Treat the field data as simple binary data, and print it as two digit
+ * hexadecimal values.
+ * Sample output:
+ * Field Name 0102030405060708090a
+ *
+ * @field: an initialized field to print
+ */
+void eeprom_field_print_bin(const struct eeprom_field *field)
+{
+ __eeprom_field_print_bin(field, "", false);
+}
+
+/**
+ * eeprom_field_update_bin() - Update field with new data in binary form
+ *
+ * @field: an initialized field
+ * @value: a string of values (i.e. "10b234a")
+ */
+int eeprom_field_update_bin(struct eeprom_field *field, char *value)
+{
+ return __eeprom_field_update_bin(field, value, false);
+}
+
+/**
+ * eeprom_field_update_reserved() - Update reserved field with new data in
+ * binary form
+ *
+ * @field: an initialized field
+ * @value: a space delimited string of byte values (i.e. "1 02 3 0x4")
+ */
+int eeprom_field_update_reserved(struct eeprom_field *field, char *value)
+{
+ return __eeprom_field_update_bin_delim(field, value, " ");
+}
+
+/**
+ * eeprom_field_print_bin_rev() - print a field which contains binary data in
+ * reverse order
+ *
+ * Treat the field data as simple binary data, and print it in reverse order
+ * as two digit hexadecimal values.
+ *
+ * Data in field:
+ * 0102030405060708090a
+ * Sample output:
+ * Field Name 0a090807060504030201
+ *
+ * @field: an initialized field to print
+ */
+void eeprom_field_print_bin_rev(const struct eeprom_field *field)
+{
+ __eeprom_field_print_bin(field, "", true);
+}
+
+/**
+ * eeprom_field_update_bin_rev() - Update field with new data in binary form,
+ * storing it in reverse
+ *
+ * This function takes a string of byte values, and stores them
+ * in the field in the reverse order. i.e. if the input string was "1234",
+ * "3412" will be written to the field.
+ *
+ * @field: an initialized field
+ * @value: a string of byte values
+ */
+int eeprom_field_update_bin_rev(struct eeprom_field *field, char *value)
+{
+ return __eeprom_field_update_bin(field, value, true);
+}
+
+/**
+ * eeprom_field_print_mac_addr() - print a field which contains a mac address
+ *
+ * Treat the field data as simple binary data, and print it formatted as a MAC
+ * address.
+ * Sample output:
+ * Field Name 01:02:03:04:05:06
+ *
+ * @field: an initialized field to print
+ */
+void eeprom_field_print_mac(const struct eeprom_field *field)
+{
+ __eeprom_field_print_bin(field, ":", false);
+}
+
+/**
+ * eeprom_field_update_mac() - Update a mac address field which contains binary
+ * data
+ *
+ * @field: an initialized field
+ * @value: a colon delimited string of byte values (i.e. "1:02:3:ff")
+ */
+int eeprom_field_update_mac(struct eeprom_field *field, char *value)
+{
+ return __eeprom_field_update_bin_delim(field, value, ":");
+}
+
+/**
+ * eeprom_field_print_ascii() - print a field which contains ASCII data
+ * @field: an initialized field to print
+ */
+void eeprom_field_print_ascii(const struct eeprom_field *field)
+{
+ char format[8];
+
+ sprintf(format, "%%.%ds\n", field->size);
+ printf(PRINT_FIELD_SEGMENT, field->name);
+ printf(format, field->buf);
+}
+
+/**
+ * eeprom_field_update_ascii() - Update field with new data in ASCII form
+ * @field: an initialized field
+ * @value: the new string data
+ *
+ * Returns 0 on success, -1 of failure (new string too long).
+ */
+int eeprom_field_update_ascii(struct eeprom_field *field, char *value)
+{
+ if (strlen(value) >= field->size) {
+ printf("%s: new data too long\n", field->name);
+ return -1;
+ }
+
+ strncpy((char *)field->buf, value, field->size - 1);
+ field->buf[field->size - 1] = '\0';
+
+ return 0;
+}
+
+/**
+ * eeprom_field_print_reserved() - print the "Reserved fields" field
+ *
+ * Print a notice that the following field_size bytes are reserved.
+ *
+ * Sample output:
+ * Reserved fields (64 bytes)
+ *
+ * @field: an initialized field to print
+ */
+void eeprom_field_print_reserved(const struct eeprom_field *field)
+{
+ printf(PRINT_FIELD_SEGMENT, "Reserved fields\t");
+ printf("(%d bytes)\n", field->size);
+}
diff --git a/roms/u-boot/common/eeprom/eeprom_layout.c b/roms/u-boot/common/eeprom/eeprom_layout.c
new file mode 100644
index 000000000..5a9be1da0
--- /dev/null
+++ b/roms/u-boot/common/eeprom/eeprom_layout.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009-2016 CompuLab, Ltd.
+ *
+ * Authors: Nikita Kiryanov <nikita@compulab.co.il>
+ * Igor Grinberg <grinberg@compulab.co.il>
+ */
+
+#include <common.h>
+#include <linux/kernel.h>
+#include <eeprom_layout.h>
+#include <eeprom_field.h>
+
+#define NO_LAYOUT_FIELDS "Unknown layout. Dumping raw data\n"
+
+struct eeprom_field layout_unknown[1] = {
+ { NO_LAYOUT_FIELDS, 256, NULL, eeprom_field_print_bin,
+ eeprom_field_update_bin },
+};
+
+/*
+ * eeprom_layout_detect() - detect layout based on the contents of the data.
+ * @data: Pointer to the data to be analyzed.
+ *
+ * Returns: the detected layout version.
+ */
+__weak int eeprom_layout_detect(unsigned char *data)
+{
+ return LAYOUT_VERSION_UNRECOGNIZED;
+}
+
+/*
+ * __eeprom_layout_assign() - set the layout fields
+ * @layout: A pointer to an existing struct layout.
+ * @layout_version: The version number of the desired layout
+ */
+__weak void __eeprom_layout_assign(struct eeprom_layout *layout,
+ int layout_version)
+{
+ layout->fields = layout_unknown;
+ layout->num_of_fields = ARRAY_SIZE(layout_unknown);
+}
+void eeprom_layout_assign(struct eeprom_layout *layout, int layout_version) \
+ __attribute__((weak, alias("__eeprom_layout_assign")));
+
+/*
+ * eeprom_layout_print() - print the layout and the data which is assigned to it
+ * @layout: A pointer to an existing struct layout.
+ */
+static void eeprom_layout_print(const struct eeprom_layout *layout)
+{
+ int i;
+ struct eeprom_field *fields = layout->fields;
+
+ for (i = 0; i < layout->num_of_fields; i++)
+ fields[i].print(&fields[i]);
+}
+
+/*
+ * eeprom_layout_update_field() - update a single field in the layout data.
+ * @layout: A pointer to an existing struct layout.
+ * @field_name: The name of the field to update.
+ * @new_data: The new field data (a string. Format depends on the field)
+ *
+ * Returns: 0 on success, negative error value on failure.
+ */
+static int eeprom_layout_update_field(struct eeprom_layout *layout,
+ char *field_name, char *new_data)
+{
+ int i, err;
+ struct eeprom_field *fields = layout->fields;
+
+ if (new_data == NULL)
+ return 0;
+
+ if (field_name == NULL)
+ return -1;
+
+ for (i = 0; i < layout->num_of_fields; i++) {
+ if (fields[i].name == RESERVED_FIELDS ||
+ strcmp(fields[i].name, field_name))
+ continue;
+
+ err = fields[i].update(&fields[i], new_data);
+ if (err)
+ printf("Invalid data for field %s\n", field_name);
+
+ return err;
+ }
+
+ printf("No such field '%s'\n", field_name);
+
+ return -1;
+}
+
+/*
+ * eeprom_layout_setup() - setup layout struct with the layout data and
+ * metadata as dictated by layout_version
+ * @layout: A pointer to an existing struct layout.
+ * @buf: A buffer initialized with the eeprom data.
+ * @buf_size: Size of buf in bytes.
+ * @layout version: The version number of the layout.
+ */
+void eeprom_layout_setup(struct eeprom_layout *layout, unsigned char *buf,
+ unsigned int buf_size, int layout_version)
+{
+ int i;
+
+ if (layout_version == LAYOUT_VERSION_AUTODETECT)
+ layout->layout_version = eeprom_layout_detect(buf);
+ else
+ layout->layout_version = layout_version;
+
+ eeprom_layout_assign(layout, layout_version);
+ layout->data = buf;
+ for (i = 0; i < layout->num_of_fields; i++) {
+ layout->fields[i].buf = buf;
+ buf += layout->fields[i].size;
+ }
+
+ layout->data_size = buf_size;
+ layout->print = eeprom_layout_print;
+ layout->update = eeprom_layout_update_field;
+}
diff --git a/roms/u-boot/common/exports.c b/roms/u-boot/common/exports.c
new file mode 100644
index 000000000..20d8b759b
--- /dev/null
+++ b/roms/u-boot/common/exports.c
@@ -0,0 +1,35 @@
+#include <common.h>
+#include <command.h>
+#include <exports.h>
+#include <malloc.h>
+#include <spi.h>
+#include <i2c.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+__attribute__((unused)) static void dummy(void)
+{
+}
+
+unsigned long get_version(void)
+{
+ return XF_VERSION;
+}
+
+#define EXPORT_FUNC(f, a, x, ...) gd->jt->x = f;
+
+#ifndef CONFIG_PHY_AQUANTIA
+# define mdio_get_current_dev dummy
+# define phy_find_by_mask dummy
+# define mdio_phydev_for_ethname dummy
+# define miiphy_set_current_dev dummy
+#endif
+
+int jumptable_init(void)
+{
+ gd->jt = malloc(sizeof(struct jt_funcs));
+#include <_exports.h>
+
+ return 0;
+}
diff --git a/roms/u-boot/common/fdt_region.c b/roms/u-boot/common/fdt_region.c
new file mode 100644
index 000000000..e4ef0ca77
--- /dev/null
+++ b/roms/u-boot/common/fdt_region.c
@@ -0,0 +1,671 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2013 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <fdt_support.h>
+#include <linux/libfdt_env.h>
+#include <fdt_region.h>
+
+#ifndef USE_HOSTCC
+#include <fdt.h>
+#include <linux/libfdt.h>
+#else
+#include "fdt_host.h"
+#endif
+
+#define FDT_MAX_DEPTH 32
+
+static int str_in_list(const char *str, char * const list[], int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ if (!strcmp(list[i], str))
+ return 1;
+
+ return 0;
+}
+
+int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
+ char * const exc_prop[], int exc_prop_count,
+ struct fdt_region region[], int max_regions,
+ char *path, int path_len, int add_string_tab)
+{
+ int stack[FDT_MAX_DEPTH] = { 0 };
+ char *end;
+ int nextoffset = 0;
+ uint32_t tag;
+ int count = 0;
+ int start = -1;
+ int depth = -1;
+ int want = 0;
+ int base = fdt_off_dt_struct(fdt);
+ bool expect_end = false;
+
+ end = path;
+ *end = '\0';
+ do {
+ const struct fdt_property *prop;
+ const char *name;
+ const char *str;
+ int include = 0;
+ int stop_at = 0;
+ int offset;
+ int len;
+
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ stop_at = nextoffset;
+
+ /* If we see two root nodes, something is wrong */
+ if (expect_end && tag != FDT_END)
+ return -FDT_ERR_BADLAYOUT;
+
+ switch (tag) {
+ case FDT_PROP:
+ include = want >= 2;
+ stop_at = offset;
+ prop = fdt_get_property_by_offset(fdt, offset, NULL);
+ str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ if (!str)
+ return -FDT_ERR_BADSTRUCTURE;
+ if (str_in_list(str, exc_prop, exc_prop_count))
+ include = 0;
+ break;
+
+ case FDT_NOP:
+ include = want >= 2;
+ stop_at = offset;
+ break;
+
+ case FDT_BEGIN_NODE:
+ depth++;
+ if (depth == FDT_MAX_DEPTH)
+ return -FDT_ERR_BADSTRUCTURE;
+ name = fdt_get_name(fdt, offset, &len);
+
+ /* The root node must have an empty name */
+ if (!depth && *name)
+ return -FDT_ERR_BADLAYOUT;
+ if (end - path + 2 + len >= path_len)
+ return -FDT_ERR_NOSPACE;
+ if (end != path + 1)
+ *end++ = '/';
+ strcpy(end, name);
+ end += len;
+ stack[depth] = want;
+ if (want == 1)
+ stop_at = offset;
+ if (str_in_list(path, inc, inc_count))
+ want = 2;
+ else if (want)
+ want--;
+ else
+ stop_at = offset;
+ include = want;
+ break;
+
+ case FDT_END_NODE:
+ /* Depth must never go below -1 */
+ if (depth < 0)
+ return -FDT_ERR_BADSTRUCTURE;
+ include = want;
+ want = stack[depth--];
+ while (end > path && *--end != '/')
+ ;
+ *end = '\0';
+ if (depth == -1)
+ expect_end = true;
+ break;
+
+ case FDT_END:
+ include = 1;
+ break;
+ }
+
+ if (include && start == -1) {
+ /* Should we merge with previous? */
+ if (count && count <= max_regions &&
+ offset == region[count - 1].offset +
+ region[count - 1].size - base)
+ start = region[--count].offset - base;
+ else
+ start = offset;
+ }
+
+ if (!include && start != -1) {
+ if (count < max_regions) {
+ region[count].offset = base + start;
+ region[count].size = stop_at - start;
+ }
+ count++;
+ start = -1;
+ }
+ } while (tag != FDT_END);
+
+ if (nextoffset != fdt_size_dt_struct(fdt))
+ return -FDT_ERR_BADLAYOUT;
+
+ /* Add a region for the END tag and the string table */
+ if (count < max_regions) {
+ region[count].offset = base + start;
+ region[count].size = nextoffset - start;
+ if (add_string_tab)
+ region[count].size += fdt_size_dt_strings(fdt);
+ }
+ count++;
+
+ return count;
+}
+
+/**
+ * fdt_add_region() - Add a new region to our list
+ * @info: State information
+ * @offset: Start offset of region
+ * @size: Size of region
+ *
+ * The region is added if there is space, but in any case we increment the
+ * count. If permitted, and the new region overlaps the last one, we merge
+ * them.
+ */
+static int fdt_add_region(struct fdt_region_state *info, int offset, int size)
+{
+ struct fdt_region *reg;
+
+ reg = info->region ? &info->region[info->count - 1] : NULL;
+ if (info->can_merge && info->count &&
+ info->count <= info->max_regions &&
+ reg && offset <= reg->offset + reg->size) {
+ reg->size = offset + size - reg->offset;
+ } else if (info->count++ < info->max_regions) {
+ if (reg) {
+ reg++;
+ reg->offset = offset;
+ reg->size = size;
+ }
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int region_list_contains_offset(struct fdt_region_state *info,
+ const void *fdt, int target)
+{
+ struct fdt_region *reg;
+ int num;
+
+ target += fdt_off_dt_struct(fdt);
+ for (reg = info->region, num = 0; num < info->count; reg++, num++) {
+ if (target >= reg->offset && target < reg->offset + reg->size)
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * fdt_add_alias_regions() - Add regions covering the aliases that we want
+ *
+ * The /aliases node is not automatically included by fdtgrep unless the
+ * command-line arguments cause to be included (or not excluded). However
+ * aliases are special in that we generally want to include those which
+ * reference a node that fdtgrep includes.
+ *
+ * In fact we want to include only aliases for those nodes still included in
+ * the fdt, and drop the other aliases since they point to nodes that will not
+ * be present.
+ *
+ * This function scans the aliases and adds regions for those which we want
+ * to keep.
+ *
+ * @fdt: Device tree to scan
+ * @region: List of regions
+ * @count: Number of regions in the list so far (i.e. starting point for this
+ * function)
+ * @max_regions: Maximum number of regions in @region list
+ * @info: Place to put the region state
+ * @return number of regions after processing, or -FDT_ERR_NOSPACE if we did
+ * not have enough room in the regions table for the regions we wanted to add.
+ */
+int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
+ int max_regions, struct fdt_region_state *info)
+{
+ int base = fdt_off_dt_struct(fdt);
+ int node, node_end, offset;
+ int did_alias_header;
+
+ node = fdt_subnode_offset(fdt, 0, "aliases");
+ if (node < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ /*
+ * Find the next node so that we know where the /aliases node ends. We
+ * need special handling if /aliases is the last node.
+ */
+ node_end = fdt_next_subnode(fdt, node);
+ if (node_end == -FDT_ERR_NOTFOUND)
+ /* Move back to the FDT_END_NODE tag of '/' */
+ node_end = fdt_size_dt_struct(fdt) - sizeof(fdt32_t) * 2;
+ else if (node_end < 0) /* other error */
+ return node_end;
+ node_end -= sizeof(fdt32_t); /* Move to FDT_END_NODE tag of /aliases */
+
+ did_alias_header = 0;
+ info->region = region;
+ info->count = count;
+ info->can_merge = 0;
+ info->max_regions = max_regions;
+
+ for (offset = fdt_first_property_offset(fdt, node);
+ offset >= 0;
+ offset = fdt_next_property_offset(fdt, offset)) {
+ const struct fdt_property *prop;
+ const char *name;
+ int target, next;
+
+ prop = fdt_get_property_by_offset(fdt, offset, NULL);
+ name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ target = fdt_path_offset(fdt, name);
+ if (!region_list_contains_offset(info, fdt, target))
+ continue;
+ next = fdt_next_property_offset(fdt, offset);
+ if (next < 0)
+ next = node_end;
+
+ if (!did_alias_header) {
+ fdt_add_region(info, base + node, 12);
+ did_alias_header = 1;
+ }
+ fdt_add_region(info, base + offset, next - offset);
+ }
+
+ /* Add the FDT_END_NODE tag */
+ if (did_alias_header)
+ fdt_add_region(info, base + node_end, sizeof(fdt32_t));
+
+ return info->count < max_regions ? info->count : -FDT_ERR_NOSPACE;
+}
+
+/**
+ * fdt_include_supernodes() - Include supernodes required by this node
+ * @info: State information
+ * @depth: Current stack depth
+ *
+ * When we decided to include a node or property which is not at the top
+ * level, this function forces the inclusion of higher level nodes. For
+ * example, given this tree:
+ *
+ * / {
+ * testing {
+ * }
+ * }
+ *
+ * If we decide to include testing then we need the root node to have a valid
+ * tree. This function adds those regions.
+ */
+static int fdt_include_supernodes(struct fdt_region_state *info, int depth)
+{
+ int base = fdt_off_dt_struct(info->fdt);
+ int start, stop_at;
+ int i;
+
+ /*
+ * Work down the stack looking for supernodes that we didn't include.
+ * The algortihm here is actually pretty simple, since we know that
+ * no previous subnode had to include these nodes, or if it did, we
+ * marked them as included (on the stack) already.
+ */
+ for (i = 0; i <= depth; i++) {
+ if (!info->stack[i].included) {
+ start = info->stack[i].offset;
+
+ /* Add the FDT_BEGIN_NODE tag of this supernode */
+ fdt_next_tag(info->fdt, start, &stop_at);
+ if (fdt_add_region(info, base + start, stop_at - start))
+ return -1;
+
+ /* Remember that this supernode is now included */
+ info->stack[i].included = 1;
+ info->can_merge = 1;
+ }
+
+ /* Force (later) generation of the FDT_END_NODE tag */
+ if (!info->stack[i].want)
+ info->stack[i].want = WANT_NODES_ONLY;
+ }
+
+ return 0;
+}
+
+enum {
+ FDT_DONE_NOTHING,
+ FDT_DONE_MEM_RSVMAP,
+ FDT_DONE_STRUCT,
+ FDT_DONE_END,
+ FDT_DONE_STRINGS,
+ FDT_DONE_ALL,
+};
+
+int fdt_first_region(const void *fdt,
+ int (*h_include)(void *priv, const void *fdt, int offset,
+ int type, const char *data, int size),
+ void *priv, struct fdt_region *region,
+ char *path, int path_len, int flags,
+ struct fdt_region_state *info)
+{
+ struct fdt_region_ptrs *p = &info->ptrs;
+
+ /* Set up our state */
+ info->fdt = fdt;
+ info->can_merge = 1;
+ info->max_regions = 1;
+ info->start = -1;
+ p->want = WANT_NOTHING;
+ p->end = path;
+ *p->end = '\0';
+ p->nextoffset = 0;
+ p->depth = -1;
+ p->done = FDT_DONE_NOTHING;
+
+ return fdt_next_region(fdt, h_include, priv, region,
+ path, path_len, flags, info);
+}
+
+/***********************************************************************
+ *
+ * Theory of operation
+ *
+ * Note: in this description 'included' means that a node (or other part
+ * of the tree) should be included in the region list, i.e. it will have
+ * a region which covers its part of the tree.
+ *
+ * This function maintains some state from the last time it is called.
+ * It checks the next part of the tree that it is supposed to look at
+ * (p.nextoffset) to see if that should be included or not. When it
+ * finds something to include, it sets info->start to its offset. This
+ * marks the start of the region we want to include.
+ *
+ * Once info->start is set to the start (i.e. not -1), we continue
+ * scanning until we find something that we don't want included. This
+ * will be the end of a region. At this point we can close off the
+ * region and add it to the list. So we do so, and reset info->start
+ * to -1.
+ *
+ * One complication here is that we want to merge regions. So when we
+ * come to add another region later, we may in fact merge it with the
+ * previous one if one ends where the other starts.
+ *
+ * The function fdt_add_region() will return -1 if it fails to add the
+ * region, because we already have a region ready to be returned, and
+ * the new one cannot be merged in with it. In this case, we must return
+ * the region we found, and wait for another call to this function.
+ * When it comes, we will repeat the processing of the tag and again
+ * try to add a region. This time it will succeed.
+ *
+ * The current state of the pointers (stack, offset, etc.) is maintained
+ * in a ptrs member. At the start of every loop iteration we make a copy
+ * of it. The copy is then updated as the tag is processed. Only if we
+ * get to the end of the loop iteration (and successfully call
+ * fdt_add_region() if we need to) can we commit the changes we have
+ * made to these pointers. For example, if we see an FDT_END_NODE tag,
+ * we will decrement the depth value. But if we need to add a region
+ * for this tag (let's say because the previous tag is included and this
+ * FDT_END_NODE tag is not included) then we will only commit the result
+ * if we were able to add the region. That allows us to retry again next
+ * time.
+ *
+ * We keep track of a variable called 'want' which tells us what we want
+ * to include when there is no specific information provided by the
+ * h_include function for a particular property. This basically handles
+ * the inclusion of properties which are pulled in by virtue of the node
+ * they are in. So if you include a node, its properties are also
+ * included. In this case 'want' will be WANT_NODES_AND_PROPS. The
+ * FDT_REG_DIRECT_SUBNODES feature also makes use of 'want'. While we
+ * are inside the subnode, 'want' will be set to WANT_NODES_ONLY, so
+ * that only the subnode's FDT_BEGIN_NODE and FDT_END_NODE tags will be
+ * included, and properties will be skipped. If WANT_NOTHING is
+ * selected, then we will just rely on what the h_include() function
+ * tells us.
+ *
+ * Using 'want' we work out 'include', which tells us whether this
+ * current tag should be included or not. As you can imagine, if the
+ * value of 'include' changes, that means we are on a boundary between
+ * nodes to include and nodes to exclude. At this point we either close
+ * off a previous region and add it to the list, or mark the start of a
+ * new region.
+ *
+ * Apart from the nodes, we have mem_rsvmap, the FDT_END tag and the
+ * string list. Each of these dealt with as a whole (i.e. we create a
+ * region for each if it is to be included). For mem_rsvmap we don't
+ * allow it to merge with the first struct region. For the stringlist,
+ * we don't allow it to merge with the last struct region (which
+ * contains at minimum the FDT_END tag).
+ *
+ *********************************************************************/
+
+int fdt_next_region(const void *fdt,
+ int (*h_include)(void *priv, const void *fdt, int offset,
+ int type, const char *data, int size),
+ void *priv, struct fdt_region *region,
+ char *path, int path_len, int flags,
+ struct fdt_region_state *info)
+{
+ int base = fdt_off_dt_struct(fdt);
+ int last_node = 0;
+ const char *str;
+
+ info->region = region;
+ info->count = 0;
+ if (info->ptrs.done < FDT_DONE_MEM_RSVMAP &&
+ (flags & FDT_REG_ADD_MEM_RSVMAP)) {
+ /* Add the memory reserve map into its own region */
+ if (fdt_add_region(info, fdt_off_mem_rsvmap(fdt),
+ fdt_off_dt_struct(fdt) -
+ fdt_off_mem_rsvmap(fdt)))
+ return 0;
+ info->can_merge = 0; /* Don't allow merging with this */
+ info->ptrs.done = FDT_DONE_MEM_RSVMAP;
+ }
+
+ /*
+ * Work through the tags one by one, deciding whether each needs to
+ * be included or not. We set the variable 'include' to indicate our
+ * decision. 'want' is used to track what we want to include - it
+ * allows us to pick up all the properties (and/or subnode tags) of
+ * a node.
+ */
+ while (info->ptrs.done < FDT_DONE_STRUCT) {
+ const struct fdt_property *prop;
+ struct fdt_region_ptrs p;
+ const char *name;
+ int include = 0;
+ int stop_at = 0;
+ uint32_t tag;
+ int offset;
+ int val;
+ int len;
+
+ /*
+ * Make a copy of our pointers. If we make it to the end of
+ * this block then we will commit them back to info->ptrs.
+ * Otherwise we can try again from the same starting state
+ * next time we are called.
+ */
+ p = info->ptrs;
+
+ /*
+ * Find the tag, and the offset of the next one. If we need to
+ * stop including tags, then by default we stop *after*
+ * including the current tag
+ */
+ offset = p.nextoffset;
+ tag = fdt_next_tag(fdt, offset, &p.nextoffset);
+ stop_at = p.nextoffset;
+
+ switch (tag) {
+ case FDT_PROP:
+ stop_at = offset;
+ prop = fdt_get_property_by_offset(fdt, offset, NULL);
+ str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ val = h_include(priv, fdt, last_node, FDT_IS_PROP, str,
+ strlen(str) + 1);
+ if (val == -1) {
+ include = p.want >= WANT_NODES_AND_PROPS;
+ } else {
+ include = val;
+ /*
+ * Make sure we include the } for this block.
+ * It might be more correct to have this done
+ * by the call to fdt_include_supernodes() in
+ * the case where it adds the node we are
+ * currently in, but this is equivalent.
+ */
+ if ((flags & FDT_REG_SUPERNODES) && val &&
+ !p.want)
+ p.want = WANT_NODES_ONLY;
+ }
+
+ /* Value grepping is not yet supported */
+ break;
+
+ case FDT_NOP:
+ include = p.want >= WANT_NODES_AND_PROPS;
+ stop_at = offset;
+ break;
+
+ case FDT_BEGIN_NODE:
+ last_node = offset;
+ p.depth++;
+ if (p.depth == FDT_MAX_DEPTH)
+ return -FDT_ERR_BADSTRUCTURE;
+ name = fdt_get_name(fdt, offset, &len);
+ if (p.end - path + 2 + len >= path_len)
+ return -FDT_ERR_NOSPACE;
+
+ /* Build the full path of this node */
+ if (p.end != path + 1)
+ *p.end++ = '/';
+ strcpy(p.end, name);
+ p.end += len;
+ info->stack[p.depth].want = p.want;
+ info->stack[p.depth].offset = offset;
+
+ /*
+ * If we are not intending to include this node unless
+ * it matches, make sure we stop *before* its tag.
+ */
+ if (p.want == WANT_NODES_ONLY ||
+ !(flags & (FDT_REG_DIRECT_SUBNODES |
+ FDT_REG_ALL_SUBNODES))) {
+ stop_at = offset;
+ p.want = WANT_NOTHING;
+ }
+ val = h_include(priv, fdt, offset, FDT_IS_NODE, path,
+ p.end - path + 1);
+
+ /* Include this if requested */
+ if (val) {
+ p.want = (flags & FDT_REG_ALL_SUBNODES) ?
+ WANT_ALL_NODES_AND_PROPS :
+ WANT_NODES_AND_PROPS;
+ }
+
+ /* If not requested, decay our 'p.want' value */
+ else if (p.want) {
+ if (p.want != WANT_ALL_NODES_AND_PROPS)
+ p.want--;
+
+ /* Not including this tag, so stop now */
+ } else {
+ stop_at = offset;
+ }
+
+ /*
+ * Decide whether to include this tag, and update our
+ * stack with the state for this node
+ */
+ include = p.want;
+ info->stack[p.depth].included = include;
+ break;
+
+ case FDT_END_NODE:
+ include = p.want;
+ if (p.depth < 0)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ /*
+ * If we don't want this node, stop right away, unless
+ * we are including subnodes
+ */
+ if (!p.want && !(flags & FDT_REG_DIRECT_SUBNODES))
+ stop_at = offset;
+ p.want = info->stack[p.depth].want;
+ p.depth--;
+ while (p.end > path && *--p.end != '/')
+ ;
+ *p.end = '\0';
+ break;
+
+ case FDT_END:
+ /* We always include the end tag */
+ include = 1;
+ p.done = FDT_DONE_STRUCT;
+ break;
+ }
+
+ /* If this tag is to be included, mark it as region start */
+ if (include && info->start == -1) {
+ /* Include any supernodes required by this one */
+ if (flags & FDT_REG_SUPERNODES) {
+ if (fdt_include_supernodes(info, p.depth))
+ return 0;
+ }
+ info->start = offset;
+ }
+
+ /*
+ * If this tag is not to be included, finish up the current
+ * region.
+ */
+ if (!include && info->start != -1) {
+ if (fdt_add_region(info, base + info->start,
+ stop_at - info->start))
+ return 0;
+ info->start = -1;
+ info->can_merge = 1;
+ }
+
+ /* If we have made it this far, we can commit our pointers */
+ info->ptrs = p;
+ }
+
+ /* Add a region for the END tag and a separate one for string table */
+ if (info->ptrs.done < FDT_DONE_END) {
+ if (info->ptrs.nextoffset != fdt_size_dt_struct(fdt))
+ return -FDT_ERR_BADSTRUCTURE;
+
+ if (fdt_add_region(info, base + info->start,
+ info->ptrs.nextoffset - info->start))
+ return 0;
+ info->ptrs.done++;
+ }
+ if (info->ptrs.done < FDT_DONE_STRINGS) {
+ if (flags & FDT_REG_ADD_STRING_TAB) {
+ info->can_merge = 0;
+ if (fdt_off_dt_strings(fdt) <
+ base + info->ptrs.nextoffset)
+ return -FDT_ERR_BADLAYOUT;
+ if (fdt_add_region(info, fdt_off_dt_strings(fdt),
+ fdt_size_dt_strings(fdt)))
+ return 0;
+ }
+ info->ptrs.done++;
+ }
+
+ return info->count > 0 ? 0 : -FDT_ERR_NOTFOUND;
+}
diff --git a/roms/u-boot/common/fdt_support.c b/roms/u-boot/common/fdt_support.c
new file mode 100644
index 000000000..a9a32df1e
--- /dev/null
+++ b/roms/u-boot/common/fdt_support.c
@@ -0,0 +1,1952 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2007
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <env.h>
+#include <log.h>
+#include <mapmem.h>
+#include <net.h>
+#include <stdio_dev.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <asm/global_data.h>
+#include <linux/libfdt.h>
+#include <fdt_support.h>
+#include <exports.h>
+#include <fdtdec.h>
+
+/**
+ * fdt_getprop_u32_default_node - Return a node's property or a default
+ *
+ * @fdt: ptr to device tree
+ * @off: offset of node
+ * @cell: cell offset in property
+ * @prop: property name
+ * @dflt: default value if the property isn't found
+ *
+ * Convenience function to return a node's property or a default value if
+ * the property doesn't exist.
+ */
+u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell,
+ const char *prop, const u32 dflt)
+{
+ const fdt32_t *val;
+ int len;
+
+ val = fdt_getprop(fdt, off, prop, &len);
+
+ /* Check if property exists */
+ if (!val)
+ return dflt;
+
+ /* Check if property is long enough */
+ if (len < ((cell + 1) * sizeof(uint32_t)))
+ return dflt;
+
+ return fdt32_to_cpu(*val);
+}
+
+/**
+ * fdt_getprop_u32_default - Find a node and return it's property or a default
+ *
+ * @fdt: ptr to device tree
+ * @path: path of node
+ * @prop: property name
+ * @dflt: default value if the property isn't found
+ *
+ * Convenience function to find a node and return it's property or a
+ * default value if it doesn't exist.
+ */
+u32 fdt_getprop_u32_default(const void *fdt, const char *path,
+ const char *prop, const u32 dflt)
+{
+ int off;
+
+ off = fdt_path_offset(fdt, path);
+ if (off < 0)
+ return dflt;
+
+ return fdt_getprop_u32_default_node(fdt, off, 0, prop, dflt);
+}
+
+/**
+ * fdt_find_and_setprop: Find a node and set it's property
+ *
+ * @fdt: ptr to device tree
+ * @node: path of node
+ * @prop: property name
+ * @val: ptr to new value
+ * @len: length of new property value
+ * @create: flag to create the property if it doesn't exist
+ *
+ * Convenience function to directly set a property given the path to the node.
+ */
+int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
+ const void *val, int len, int create)
+{
+ int nodeoff = fdt_path_offset(fdt, node);
+
+ if (nodeoff < 0)
+ return nodeoff;
+
+ if ((!create) && (fdt_get_property(fdt, nodeoff, prop, NULL) == NULL))
+ return 0; /* create flag not set; so exit quietly */
+
+ return fdt_setprop(fdt, nodeoff, prop, val, len);
+}
+
+/**
+ * fdt_find_or_add_subnode() - find or possibly add a subnode of a given node
+ *
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node with a given name.
+ * If the subnode does not exist, it will be created.
+ */
+int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+ int offset;
+
+ offset = fdt_subnode_offset(fdt, parentoffset, name);
+
+ if (offset == -FDT_ERR_NOTFOUND)
+ offset = fdt_add_subnode(fdt, parentoffset, name);
+
+ if (offset < 0)
+ printf("%s: %s: %s\n", __func__, name, fdt_strerror(offset));
+
+ return offset;
+}
+
+#if defined(CONFIG_OF_STDOUT_VIA_ALIAS) && defined(CONFIG_CONS_INDEX)
+static int fdt_fixup_stdout(void *fdt, int chosenoff)
+{
+ int err;
+ int aliasoff;
+ char sername[9] = { 0 };
+ const void *path;
+ int len;
+ char tmp[256]; /* long enough */
+
+ sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
+
+ aliasoff = fdt_path_offset(fdt, "/aliases");
+ if (aliasoff < 0) {
+ err = aliasoff;
+ goto noalias;
+ }
+
+ path = fdt_getprop(fdt, aliasoff, sername, &len);
+ if (!path) {
+ err = len;
+ goto noalias;
+ }
+
+ /* fdt_setprop may break "path" so we copy it to tmp buffer */
+ memcpy(tmp, path, len);
+
+ err = fdt_setprop(fdt, chosenoff, "linux,stdout-path", tmp, len);
+ if (err < 0)
+ printf("WARNING: could not set linux,stdout-path %s.\n",
+ fdt_strerror(err));
+
+ return err;
+
+noalias:
+ printf("WARNING: %s: could not read %s alias: %s\n",
+ __func__, sername, fdt_strerror(err));
+
+ return 0;
+}
+#else
+static int fdt_fixup_stdout(void *fdt, int chosenoff)
+{
+ return 0;
+}
+#endif
+
+static inline int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name,
+ uint64_t val, int is_u64)
+{
+ if (is_u64)
+ return fdt_setprop_u64(fdt, nodeoffset, name, val);
+ else
+ return fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val);
+}
+
+int fdt_root(void *fdt)
+{
+ char *serial;
+ int err;
+
+ err = fdt_check_header(fdt);
+ if (err < 0) {
+ printf("fdt_root: %s\n", fdt_strerror(err));
+ return err;
+ }
+
+ serial = env_get("serial#");
+ if (serial) {
+ err = fdt_setprop(fdt, 0, "serial-number", serial,
+ strlen(serial) + 1);
+
+ if (err < 0) {
+ printf("WARNING: could not set serial-number %s.\n",
+ fdt_strerror(err));
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end)
+{
+ int nodeoffset;
+ int err, j, total;
+ int is_u64;
+ uint64_t addr, size;
+
+ /* just return if the size of initrd is zero */
+ if (initrd_start == initrd_end)
+ return 0;
+
+ /* find or create "/chosen" node. */
+ nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ total = fdt_num_mem_rsv(fdt);
+
+ /*
+ * Look for an existing entry and update it. If we don't find
+ * the entry, we will j be the next available slot.
+ */
+ for (j = 0; j < total; j++) {
+ err = fdt_get_mem_rsv(fdt, j, &addr, &size);
+ if (addr == initrd_start) {
+ fdt_del_mem_rsv(fdt, j);
+ break;
+ }
+ }
+
+ err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start);
+ if (err < 0) {
+ printf("fdt_initrd: %s\n", fdt_strerror(err));
+ return err;
+ }
+
+ is_u64 = (fdt_address_cells(fdt, 0) == 2);
+
+ err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-start",
+ (uint64_t)initrd_start, is_u64);
+
+ if (err < 0) {
+ printf("WARNING: could not set linux,initrd-start %s.\n",
+ fdt_strerror(err));
+ return err;
+ }
+
+ err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-end",
+ (uint64_t)initrd_end, is_u64);
+
+ if (err < 0) {
+ printf("WARNING: could not set linux,initrd-end %s.\n",
+ fdt_strerror(err));
+
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * board_fdt_chosen_bootargs - boards may override this function to use
+ * alternative kernel command line arguments
+ */
+__weak char *board_fdt_chosen_bootargs(void)
+{
+ return env_get("bootargs");
+}
+
+int fdt_chosen(void *fdt)
+{
+ int nodeoffset;
+ int err;
+ char *str; /* used to set string properties */
+
+ err = fdt_check_header(fdt);
+ if (err < 0) {
+ printf("fdt_chosen: %s\n", fdt_strerror(err));
+ return err;
+ }
+
+ /* find or create "/chosen" node. */
+ nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ str = board_fdt_chosen_bootargs();
+
+ if (str) {
+ err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
+ strlen(str) + 1);
+ if (err < 0) {
+ printf("WARNING: could not set bootargs %s.\n",
+ fdt_strerror(err));
+ return err;
+ }
+ }
+
+ return fdt_fixup_stdout(fdt, nodeoffset);
+}
+
+void do_fixup_by_path(void *fdt, const char *path, const char *prop,
+ const void *val, int len, int create)
+{
+#if defined(DEBUG)
+ int i;
+ debug("Updating property '%s/%s' = ", path, prop);
+ for (i = 0; i < len; i++)
+ debug(" %.2x", *(u8*)(val+i));
+ debug("\n");
+#endif
+ int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);
+ if (rc)
+ printf("Unable to update property %s:%s, err=%s\n",
+ path, prop, fdt_strerror(rc));
+}
+
+void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
+ u32 val, int create)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ do_fixup_by_path(fdt, path, prop, &tmp, sizeof(tmp), create);
+}
+
+void do_fixup_by_prop(void *fdt,
+ const char *pname, const void *pval, int plen,
+ const char *prop, const void *val, int len,
+ int create)
+{
+ int off;
+#if defined(DEBUG)
+ int i;
+ debug("Updating property '%s' = ", prop);
+ for (i = 0; i < len; i++)
+ debug(" %.2x", *(u8*)(val+i));
+ debug("\n");
+#endif
+ off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen);
+ while (off != -FDT_ERR_NOTFOUND) {
+ if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL))
+ fdt_setprop(fdt, off, prop, val, len);
+ off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen);
+ }
+}
+
+void do_fixup_by_prop_u32(void *fdt,
+ const char *pname, const void *pval, int plen,
+ const char *prop, u32 val, int create)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ do_fixup_by_prop(fdt, pname, pval, plen, prop, &tmp, 4, create);
+}
+
+void do_fixup_by_compat(void *fdt, const char *compat,
+ const char *prop, const void *val, int len, int create)
+{
+ int off = -1;
+#if defined(DEBUG)
+ int i;
+ debug("Updating property '%s' = ", prop);
+ for (i = 0; i < len; i++)
+ debug(" %.2x", *(u8*)(val+i));
+ debug("\n");
+#endif
+ off = fdt_node_offset_by_compatible(fdt, -1, compat);
+ while (off != -FDT_ERR_NOTFOUND) {
+ if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL))
+ fdt_setprop(fdt, off, prop, val, len);
+ off = fdt_node_offset_by_compatible(fdt, off, compat);
+ }
+}
+
+void do_fixup_by_compat_u32(void *fdt, const char *compat,
+ const char *prop, u32 val, int create)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ do_fixup_by_compat(fdt, compat, prop, &tmp, 4, create);
+}
+
+#ifdef CONFIG_ARCH_FIXUP_FDT_MEMORY
+/*
+ * fdt_pack_reg - pack address and size array into the "reg"-suitable stream
+ */
+static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size,
+ int n)
+{
+ int i;
+ int address_cells = fdt_address_cells(fdt, 0);
+ int size_cells = fdt_size_cells(fdt, 0);
+ char *p = buf;
+
+ for (i = 0; i < n; i++) {
+ if (address_cells == 2)
+ *(fdt64_t *)p = cpu_to_fdt64(address[i]);
+ else
+ *(fdt32_t *)p = cpu_to_fdt32(address[i]);
+ p += 4 * address_cells;
+
+ if (size_cells == 2)
+ *(fdt64_t *)p = cpu_to_fdt64(size[i]);
+ else
+ *(fdt32_t *)p = cpu_to_fdt32(size[i]);
+ p += 4 * size_cells;
+ }
+
+ return p - (char *)buf;
+}
+
+#if CONFIG_NR_DRAM_BANKS > 4
+#define MEMORY_BANKS_MAX CONFIG_NR_DRAM_BANKS
+#else
+#define MEMORY_BANKS_MAX 4
+#endif
+int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
+{
+ int err, nodeoffset;
+ int len, i;
+ u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */
+
+ if (banks > MEMORY_BANKS_MAX) {
+ printf("%s: num banks %d exceeds hardcoded limit %d."
+ " Recompile with higher MEMORY_BANKS_MAX?\n",
+ __FUNCTION__, banks, MEMORY_BANKS_MAX);
+ return -1;
+ }
+
+ err = fdt_check_header(blob);
+ if (err < 0) {
+ printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
+ return err;
+ }
+
+ /* find or create "/memory" node. */
+ nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory");
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
+ sizeof("memory"));
+ if (err < 0) {
+ printf("WARNING: could not set %s %s.\n", "device_type",
+ fdt_strerror(err));
+ return err;
+ }
+
+ for (i = 0; i < banks; i++) {
+ if (start[i] == 0 && size[i] == 0)
+ break;
+ }
+
+ banks = i;
+
+ if (!banks)
+ return 0;
+
+ len = fdt_pack_reg(blob, tmp, start, size, banks);
+
+ err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
+ if (err < 0) {
+ printf("WARNING: could not set %s %s.\n",
+ "reg", fdt_strerror(err));
+ return err;
+ }
+ return 0;
+}
+
+int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int areas)
+{
+ int err, nodeoffset;
+ int len;
+ u8 tmp[8 * 16]; /* Up to 64-bit address + 64-bit size */
+
+ if (areas > 8) {
+ printf("%s: num areas %d exceeds hardcoded limit %d\n",
+ __func__, areas, 8);
+ return -1;
+ }
+
+ err = fdt_check_header(blob);
+ if (err < 0) {
+ printf("%s: %s\n", __func__, fdt_strerror(err));
+ return err;
+ }
+
+ /* find or create "/memory" node. */
+ nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory");
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ len = fdt_pack_reg(blob, tmp, start, size, areas);
+
+ err = fdt_setprop(blob, nodeoffset, "linux,usable-memory", tmp, len);
+ if (err < 0) {
+ printf("WARNING: could not set %s %s.\n",
+ "reg", fdt_strerror(err));
+ return err;
+ }
+
+ return 0;
+}
+#endif
+
+int fdt_fixup_memory(void *blob, u64 start, u64 size)
+{
+ return fdt_fixup_memory_banks(blob, &start, &size, 1);
+}
+
+void fdt_fixup_ethernet(void *fdt)
+{
+ int i = 0, j, prop;
+ char *tmp, *end;
+ char mac[16];
+ const char *path;
+ unsigned char mac_addr[ARP_HLEN];
+ int offset;
+#ifdef FDT_SEQ_MACADDR_FROM_ENV
+ int nodeoff;
+ const struct fdt_property *fdt_prop;
+#endif
+
+ if (fdt_path_offset(fdt, "/aliases") < 0)
+ return;
+
+ /* Cycle through all aliases */
+ for (prop = 0; ; prop++) {
+ const char *name;
+
+ /* FDT might have been edited, recompute the offset */
+ offset = fdt_first_property_offset(fdt,
+ fdt_path_offset(fdt, "/aliases"));
+ /* Select property number 'prop' */
+ for (j = 0; j < prop; j++)
+ offset = fdt_next_property_offset(fdt, offset);
+
+ if (offset < 0)
+ break;
+
+ path = fdt_getprop_by_offset(fdt, offset, &name, NULL);
+ if (!strncmp(name, "ethernet", 8)) {
+ /* Treat plain "ethernet" same as "ethernet0". */
+ if (!strcmp(name, "ethernet")
+#ifdef FDT_SEQ_MACADDR_FROM_ENV
+ || !strcmp(name, "ethernet0")
+#endif
+ )
+ i = 0;
+#ifndef FDT_SEQ_MACADDR_FROM_ENV
+ else
+ i = trailing_strtol(name);
+#endif
+ if (i != -1) {
+ if (i == 0)
+ strcpy(mac, "ethaddr");
+ else
+ sprintf(mac, "eth%daddr", i);
+ } else {
+ continue;
+ }
+#ifdef FDT_SEQ_MACADDR_FROM_ENV
+ nodeoff = fdt_path_offset(fdt, path);
+ fdt_prop = fdt_get_property(fdt, nodeoff, "status",
+ NULL);
+ if (fdt_prop && !strcmp(fdt_prop->data, "disabled"))
+ continue;
+ i++;
+#endif
+ tmp = env_get(mac);
+ if (!tmp)
+ continue;
+
+ for (j = 0; j < 6; j++) {
+ mac_addr[j] = tmp ?
+ simple_strtoul(tmp, &end, 16) : 0;
+ if (tmp)
+ tmp = (*end) ? end + 1 : end;
+ }
+
+ do_fixup_by_path(fdt, path, "mac-address",
+ &mac_addr, 6, 0);
+ do_fixup_by_path(fdt, path, "local-mac-address",
+ &mac_addr, 6, 1);
+ }
+ }
+}
+
+int fdt_record_loadable(void *blob, u32 index, const char *name,
+ uintptr_t load_addr, u32 size, uintptr_t entry_point,
+ const char *type, const char *os)
+{
+ int err, node;
+
+ err = fdt_check_header(blob);
+ if (err < 0) {
+ printf("%s: %s\n", __func__, fdt_strerror(err));
+ return err;
+ }
+
+ /* find or create "/fit-images" node */
+ node = fdt_find_or_add_subnode(blob, 0, "fit-images");
+ if (node < 0)
+ return node;
+
+ /* find or create "/fit-images/<name>" node */
+ node = fdt_find_or_add_subnode(blob, node, name);
+ if (node < 0)
+ return node;
+
+ fdt_setprop_u64(blob, node, "load", load_addr);
+ if (entry_point != -1)
+ fdt_setprop_u64(blob, node, "entry", entry_point);
+ fdt_setprop_u32(blob, node, "size", size);
+ if (type)
+ fdt_setprop_string(blob, node, "type", type);
+ if (os)
+ fdt_setprop_string(blob, node, "os", os);
+
+ return node;
+}
+
+/* Resize the fdt to its actual size + a bit of padding */
+int fdt_shrink_to_minimum(void *blob, uint extrasize)
+{
+ int i;
+ uint64_t addr, size;
+ int total, ret;
+ uint actualsize;
+ int fdt_memrsv = 0;
+
+ if (!blob)
+ return 0;
+
+ total = fdt_num_mem_rsv(blob);
+ for (i = 0; i < total; i++) {
+ fdt_get_mem_rsv(blob, i, &addr, &size);
+ if (addr == (uintptr_t)blob) {
+ fdt_del_mem_rsv(blob, i);
+ fdt_memrsv = 1;
+ break;
+ }
+ }
+
+ /*
+ * Calculate the actual size of the fdt
+ * plus the size needed for 5 fdt_add_mem_rsv, one
+ * for the fdt itself and 4 for a possible initrd
+ * ((initrd-start + initrd-end) * 2 (name & value))
+ */
+ actualsize = fdt_off_dt_strings(blob) +
+ fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry);
+
+ actualsize += extrasize;
+ /* Make it so the fdt ends on a page boundary */
+ actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x1000);
+ actualsize = actualsize - ((uintptr_t)blob & 0xfff);
+
+ /* Change the fdt header to reflect the correct size */
+ fdt_set_totalsize(blob, actualsize);
+
+ if (fdt_memrsv) {
+ /* Add the new reservation */
+ ret = fdt_add_mem_rsv(blob, map_to_sysmem(blob), actualsize);
+ if (ret < 0)
+ return ret;
+ }
+
+ return actualsize;
+}
+
+#ifdef CONFIG_PCI
+#define CONFIG_SYS_PCI_NR_INBOUND_WIN 4
+
+#define FDT_PCI_PREFETCH (0x40000000)
+#define FDT_PCI_MEM32 (0x02000000)
+#define FDT_PCI_IO (0x01000000)
+#define FDT_PCI_MEM64 (0x03000000)
+
+int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
+
+ int addrcell, sizecell, len, r;
+ u32 *dma_range;
+ /* sized based on pci addr cells, size-cells, & address-cells */
+ u32 dma_ranges[(3 + 2 + 2) * CONFIG_SYS_PCI_NR_INBOUND_WIN];
+
+ addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1);
+ sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1);
+
+ dma_range = &dma_ranges[0];
+ for (r = 0; r < hose->region_count; r++) {
+ u64 bus_start, phys_start, size;
+
+ /* skip if !PCI_REGION_SYS_MEMORY */
+ if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY))
+ continue;
+
+ bus_start = (u64)hose->regions[r].bus_start;
+ phys_start = (u64)hose->regions[r].phys_start;
+ size = (u64)hose->regions[r].size;
+
+ dma_range[0] = 0;
+ if (size >= 0x100000000ull)
+ dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM64);
+ else
+ dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM32);
+ if (hose->regions[r].flags & PCI_REGION_PREFETCH)
+ dma_range[0] |= cpu_to_fdt32(FDT_PCI_PREFETCH);
+#ifdef CONFIG_SYS_PCI_64BIT
+ dma_range[1] = cpu_to_fdt32(bus_start >> 32);
+#else
+ dma_range[1] = 0;
+#endif
+ dma_range[2] = cpu_to_fdt32(bus_start & 0xffffffff);
+
+ if (addrcell == 2) {
+ dma_range[3] = cpu_to_fdt32(phys_start >> 32);
+ dma_range[4] = cpu_to_fdt32(phys_start & 0xffffffff);
+ } else {
+ dma_range[3] = cpu_to_fdt32(phys_start & 0xffffffff);
+ }
+
+ if (sizecell == 2) {
+ dma_range[3 + addrcell + 0] =
+ cpu_to_fdt32(size >> 32);
+ dma_range[3 + addrcell + 1] =
+ cpu_to_fdt32(size & 0xffffffff);
+ } else {
+ dma_range[3 + addrcell + 0] =
+ cpu_to_fdt32(size & 0xffffffff);
+ }
+
+ dma_range += (3 + addrcell + sizecell);
+ }
+
+ len = dma_range - &dma_ranges[0];
+ if (len)
+ fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4);
+
+ return 0;
+}
+#endif
+
+int fdt_increase_size(void *fdt, int add_len)
+{
+ int newlen;
+
+ newlen = fdt_totalsize(fdt) + add_len;
+
+ /* Open in place with a new len */
+ return fdt_open_into(fdt, fdt, newlen);
+}
+
+#ifdef CONFIG_FDT_FIXUP_PARTITIONS
+#include <jffs2/load_kernel.h>
+#include <mtd_node.h>
+
+static int fdt_del_subnodes(const void *blob, int parent_offset)
+{
+ int off, ndepth;
+ int ret;
+
+ for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth);
+ (off >= 0) && (ndepth > 0);
+ off = fdt_next_node(blob, off, &ndepth)) {
+ if (ndepth == 1) {
+ debug("delete %s: offset: %x\n",
+ fdt_get_name(blob, off, 0), off);
+ ret = fdt_del_node((void *)blob, off);
+ if (ret < 0) {
+ printf("Can't delete node: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ } else {
+ ndepth = 0;
+ off = parent_offset;
+ }
+ }
+ }
+ return 0;
+}
+
+static int fdt_del_partitions(void *blob, int parent_offset)
+{
+ const void *prop;
+ int ndepth = 0;
+ int off;
+ int ret;
+
+ off = fdt_next_node(blob, parent_offset, &ndepth);
+ if (off > 0 && ndepth == 1) {
+ prop = fdt_getprop(blob, off, "label", NULL);
+ if (prop == NULL) {
+ /*
+ * Could not find label property, nand {}; node?
+ * Check subnode, delete partitions there if any.
+ */
+ return fdt_del_partitions(blob, off);
+ } else {
+ ret = fdt_del_subnodes(blob, parent_offset);
+ if (ret < 0) {
+ printf("Can't remove subnodes: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+static int fdt_node_set_part_info(void *blob, int parent_offset,
+ struct mtd_device *dev)
+{
+ struct list_head *pentry;
+ struct part_info *part;
+ int off, ndepth = 0;
+ int part_num, ret;
+ int sizecell;
+ char buf[64];
+
+ ret = fdt_del_partitions(blob, parent_offset);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Check if size/address is 1 or 2 cells.
+ * We assume #address-cells and #size-cells have same value.
+ */
+ sizecell = fdt_getprop_u32_default_node(blob, parent_offset,
+ 0, "#size-cells", 1);
+
+ /*
+ * Check if it is nand {}; subnode, adjust
+ * the offset in this case
+ */
+ off = fdt_next_node(blob, parent_offset, &ndepth);
+ if (off > 0 && ndepth == 1)
+ parent_offset = off;
+
+ part_num = 0;
+ list_for_each_prev(pentry, &dev->parts) {
+ int newoff;
+
+ part = list_entry(pentry, struct part_info, link);
+
+ debug("%2d: %-20s0x%08llx\t0x%08llx\t%d\n",
+ part_num, part->name, part->size,
+ part->offset, part->mask_flags);
+
+ sprintf(buf, "partition@%llx", part->offset);
+add_sub:
+ ret = fdt_add_subnode(blob, parent_offset, buf);
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_sub;
+ else
+ goto err_size;
+ } else if (ret < 0) {
+ printf("Can't add partition node: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+ newoff = ret;
+
+ /* Check MTD_WRITEABLE_CMD flag */
+ if (part->mask_flags & 1) {
+add_ro:
+ ret = fdt_setprop(blob, newoff, "read_only", NULL, 0);
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_ro;
+ else
+ goto err_size;
+ } else if (ret < 0)
+ goto err_prop;
+ }
+
+add_reg:
+ if (sizecell == 2) {
+ ret = fdt_setprop_u64(blob, newoff,
+ "reg", part->offset);
+ if (!ret)
+ ret = fdt_appendprop_u64(blob, newoff,
+ "reg", part->size);
+ } else {
+ ret = fdt_setprop_u32(blob, newoff,
+ "reg", part->offset);
+ if (!ret)
+ ret = fdt_appendprop_u32(blob, newoff,
+ "reg", part->size);
+ }
+
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_reg;
+ else
+ goto err_size;
+ } else if (ret < 0)
+ goto err_prop;
+
+add_label:
+ ret = fdt_setprop_string(blob, newoff, "label", part->name);
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_label;
+ else
+ goto err_size;
+ } else if (ret < 0)
+ goto err_prop;
+
+ part_num++;
+ }
+ return 0;
+err_size:
+ printf("Can't increase blob size: %s\n", fdt_strerror(ret));
+ return ret;
+err_prop:
+ printf("Can't add property: %s\n", fdt_strerror(ret));
+ return ret;
+}
+
+/*
+ * Update partitions in nor/nand nodes using info from
+ * mtdparts environment variable. The nodes to update are
+ * specified by node_info structure which contains mtd device
+ * type and compatible string: E. g. the board code in
+ * ft_board_setup() could use:
+ *
+ * struct node_info nodes[] = {
+ * { "fsl,mpc5121-nfc", MTD_DEV_TYPE_NAND, },
+ * { "cfi-flash", MTD_DEV_TYPE_NOR, },
+ * };
+ *
+ * fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
+ */
+void fdt_fixup_mtdparts(void *blob, const struct node_info *node_info,
+ int node_info_size)
+{
+ struct mtd_device *dev;
+ int i, idx;
+ int noff;
+ bool inited = false;
+
+ for (i = 0; i < node_info_size; i++) {
+ idx = 0;
+ noff = -1;
+
+ while ((noff = fdt_node_offset_by_compatible(blob, noff,
+ node_info[i].compat)) >= 0) {
+ const char *prop;
+
+ prop = fdt_getprop(blob, noff, "status", NULL);
+ if (prop && !strcmp(prop, "disabled"))
+ continue;
+
+ debug("%s: %s, mtd dev type %d\n",
+ fdt_get_name(blob, noff, 0),
+ node_info[i].compat, node_info[i].type);
+
+ if (!inited) {
+ if (mtdparts_init() != 0)
+ return;
+ inited = true;
+ }
+
+ dev = device_find(node_info[i].type, idx++);
+ if (dev) {
+ if (fdt_node_set_part_info(blob, noff, dev))
+ return; /* return on error */
+ }
+ }
+ }
+}
+#endif
+
+void fdt_del_node_and_alias(void *blob, const char *alias)
+{
+ int off = fdt_path_offset(blob, alias);
+
+ if (off < 0)
+ return;
+
+ fdt_del_node(blob, off);
+
+ off = fdt_path_offset(blob, "/aliases");
+ fdt_delprop(blob, off, alias);
+}
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+#define OF_BAD_ADDR FDT_ADDR_T_NONE
+#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
+ (ns) > 0)
+
+/* Debug utility */
+#ifdef DEBUG
+static void of_dump_addr(const char *s, const fdt32_t *addr, int na)
+{
+ printf("%s", s);
+ while(na--)
+ printf(" %08x", *(addr++));
+ printf("\n");
+}
+#else
+static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { }
+#endif
+
+/**
+ * struct of_bus - Callbacks for bus specific translators
+ * @name: A string used to identify this bus in debug output.
+ * @addresses: The name of the DT property from which addresses are
+ * to be read, typically "reg".
+ * @match: Return non-zero if the node whose parent is at
+ * parentoffset in the FDT blob corresponds to a bus
+ * of this type, otherwise return zero. If NULL a match
+ * is assumed.
+ * @count_cells:Count how many cells (be32 values) a node whose parent
+ * is at parentoffset in the FDT blob will require to
+ * represent its address (written to *addrc) & size
+ * (written to *sizec).
+ * @map: Map the address addr from the address space of this
+ * bus to that of its parent, making use of the ranges
+ * read from DT to an array at range. na and ns are the
+ * number of cells (be32 values) used to hold and address
+ * or size, respectively, for this bus. pna is the number
+ * of cells used to hold an address for the parent bus.
+ * Returns the address in the address space of the parent
+ * bus.
+ * @translate: Update the value of the address cells at addr within an
+ * FDT by adding offset to it. na specifies the number of
+ * cells used to hold the address being translated. Returns
+ * zero on success, non-zero on error.
+ *
+ * Each bus type will include a struct of_bus in the of_busses array,
+ * providing implementations of some or all of the functions used to
+ * match the bus & handle address translation for its children.
+ */
+struct of_bus {
+ const char *name;
+ const char *addresses;
+ int (*match)(const void *blob, int parentoffset);
+ void (*count_cells)(const void *blob, int parentoffset,
+ int *addrc, int *sizec);
+ u64 (*map)(fdt32_t *addr, const fdt32_t *range,
+ int na, int ns, int pna);
+ int (*translate)(fdt32_t *addr, u64 offset, int na);
+};
+
+/* Default translator (generic bus) */
+void fdt_support_default_count_cells(const void *blob, int parentoffset,
+ int *addrc, int *sizec)
+{
+ const fdt32_t *prop;
+
+ if (addrc)
+ *addrc = fdt_address_cells(blob, parentoffset);
+
+ if (sizec) {
+ prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
+ if (prop)
+ *sizec = be32_to_cpup(prop);
+ else
+ *sizec = 1;
+ }
+}
+
+static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range,
+ int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = fdt_read_number(range, na);
+ s = fdt_read_number(range + na + pna, ns);
+ da = fdt_read_number(addr, na);
+
+ debug("OF: default map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na)
+{
+ u64 a = fdt_read_number(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = cpu_to_fdt32(a >> 32);
+ addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF_ISA_BUS
+
+/* ISA bus translator */
+static int of_bus_isa_match(const void *blob, int parentoffset)
+{
+ const char *name;
+
+ name = fdt_get_name(blob, parentoffset, NULL);
+ if (!name)
+ return 0;
+
+ return !strcmp(name, "isa");
+}
+
+static void of_bus_isa_count_cells(const void *blob, int parentoffset,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 2;
+ if (sizec)
+ *sizec = 1;
+}
+
+static u64 of_bus_isa_map(fdt32_t *addr, const fdt32_t *range,
+ int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & cpu_to_be32(1))
+ return OF_BAD_ADDR;
+
+ cp = fdt_read_number(range + 1, na - 1);
+ s = fdt_read_number(range + na + pna, ns);
+ da = fdt_read_number(addr + 1, na - 1);
+
+ debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_isa_translate(fdt32_t *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+#endif /* CONFIG_OF_ISA_BUS */
+
+/* Array of bus specific translators */
+static struct of_bus of_busses[] = {
+#ifdef CONFIG_OF_ISA_BUS
+ /* ISA */
+ {
+ .name = "isa",
+ .addresses = "reg",
+ .match = of_bus_isa_match,
+ .count_cells = of_bus_isa_count_cells,
+ .map = of_bus_isa_map,
+ .translate = of_bus_isa_translate,
+ },
+#endif /* CONFIG_OF_ISA_BUS */
+ /* Default */
+ {
+ .name = "default",
+ .addresses = "reg",
+ .count_cells = fdt_support_default_count_cells,
+ .map = of_bus_default_map,
+ .translate = of_bus_default_translate,
+ },
+};
+
+static struct of_bus *of_match_bus(const void *blob, int parentoffset)
+{
+ struct of_bus *bus;
+
+ if (ARRAY_SIZE(of_busses) == 1)
+ return of_busses;
+
+ for (bus = of_busses; bus; bus++) {
+ if (!bus->match || bus->match(blob, parentoffset))
+ return bus;
+ }
+
+ /*
+ * We should always have matched the default bus at least, since
+ * it has a NULL match field. If we didn't then it somehow isn't
+ * in the of_busses array or something equally catastrophic has
+ * gone wrong.
+ */
+ assert(0);
+ return NULL;
+}
+
+static int of_translate_one(const void *blob, int parent, struct of_bus *bus,
+ struct of_bus *pbus, fdt32_t *addr,
+ int na, int ns, int pna, const char *rprop)
+{
+ const fdt32_t *ranges;
+ int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+
+ /* Normally, an absence of a "ranges" property means we are
+ * crossing a non-translatable boundary, and thus the addresses
+ * below the current not cannot be converted to CPU physical ones.
+ * Unfortunately, while this is very clear in the spec, it's not
+ * what Apple understood, and they do have things like /uni-n or
+ * /ht nodes with no "ranges" property and a lot of perfectly
+ * useable mapped devices below them. Thus we treat the absence of
+ * "ranges" as equivalent to an empty "ranges" property which means
+ * a 1:1 translation at that level. It's up to the caller not to try
+ * to translate addresses that aren't supposed to be translated in
+ * the first place. --BenH.
+ */
+ ranges = fdt_getprop(blob, parent, rprop, &rlen);
+ if (ranges == NULL || rlen == 0) {
+ offset = fdt_read_number(addr, na);
+ memset(addr, 0, pna * 4);
+ debug("OF: no ranges, 1:1 translation\n");
+ goto finish;
+ }
+
+ debug("OF: walking ranges...\n");
+
+ /* Now walk through the ranges */
+ rlen /= 4;
+ rone = na + pna + ns;
+ for (; rlen >= rone; rlen -= rone, ranges += rone) {
+ offset = bus->map(addr, ranges, na, ns, pna);
+ if (offset != OF_BAD_ADDR)
+ break;
+ }
+ if (offset == OF_BAD_ADDR) {
+ debug("OF: not found !\n");
+ return 1;
+ }
+ memcpy(addr, ranges + na, 4 * pna);
+
+ finish:
+ of_dump_addr("OF: parent translation for:", addr, pna);
+ debug("OF: with offset: %llu\n", offset);
+
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+static u64 __of_translate_address(const void *blob, int node_offset,
+ const fdt32_t *in_addr, const char *rprop)
+{
+ int parent;
+ struct of_bus *bus, *pbus;
+ fdt32_t addr[OF_MAX_ADDR_CELLS];
+ int na, ns, pna, pns;
+ u64 result = OF_BAD_ADDR;
+
+ debug("OF: ** translation for device %s **\n",
+ fdt_get_name(blob, node_offset, NULL));
+
+ /* Get parent & match bus type */
+ parent = fdt_parent_offset(blob, node_offset);
+ if (parent < 0)
+ goto bail;
+ bus = of_match_bus(blob, parent);
+
+ /* Cound address cells & copy address locally */
+ bus->count_cells(blob, parent, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ printf("%s: Bad cell count for %s\n", __FUNCTION__,
+ fdt_get_name(blob, node_offset, NULL));
+ goto bail;
+ }
+ memcpy(addr, in_addr, na * 4);
+
+ debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
+ bus->name, na, ns, fdt_get_name(blob, parent, NULL));
+ of_dump_addr("OF: translating address:", addr, na);
+
+ /* Translate */
+ for (;;) {
+ /* Switch to parent bus */
+ node_offset = parent;
+ parent = fdt_parent_offset(blob, node_offset);
+
+ /* If root, we have finished */
+ if (parent < 0) {
+ debug("OF: reached root node\n");
+ result = fdt_read_number(addr, na);
+ break;
+ }
+
+ /* Get new parent bus and counts */
+ pbus = of_match_bus(blob, parent);
+ pbus->count_cells(blob, parent, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ printf("%s: Bad cell count for %s\n", __FUNCTION__,
+ fdt_get_name(blob, node_offset, NULL));
+ break;
+ }
+
+ debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
+ pbus->name, pna, pns, fdt_get_name(blob, parent, NULL));
+
+ /* Apply bus translation */
+ if (of_translate_one(blob, node_offset, bus, pbus,
+ addr, na, ns, pna, rprop))
+ break;
+
+ /* Complete the move up one level */
+ na = pna;
+ ns = pns;
+ bus = pbus;
+
+ of_dump_addr("OF: one level translation:", addr, na);
+ }
+ bail:
+
+ return result;
+}
+
+u64 fdt_translate_address(const void *blob, int node_offset,
+ const fdt32_t *in_addr)
+{
+ return __of_translate_address(blob, node_offset, in_addr, "ranges");
+}
+
+u64 fdt_translate_dma_address(const void *blob, int node_offset,
+ const fdt32_t *in_addr)
+{
+ return __of_translate_address(blob, node_offset, in_addr, "dma-ranges");
+}
+
+int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size)
+{
+ bool found_dma_ranges = false;
+ struct of_bus *bus_node;
+ const fdt32_t *ranges;
+ int na, ns, pna, pns;
+ int parent = node;
+ int ret = 0;
+ int len;
+
+ /* Find the closest dma-ranges property */
+ while (parent >= 0) {
+ ranges = fdt_getprop(blob, parent, "dma-ranges", &len);
+
+ /* Ignore empty ranges, they imply no translation required */
+ if (ranges && len > 0)
+ break;
+
+ /* Once we find 'dma-ranges', then a missing one is an error */
+ if (found_dma_ranges && !ranges) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ranges)
+ found_dma_ranges = true;
+
+ parent = fdt_parent_offset(blob, parent);
+ }
+
+ if (!ranges || parent < 0) {
+ debug("no dma-ranges found for node %s\n",
+ fdt_get_name(blob, node, NULL));
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /* switch to that node */
+ node = parent;
+ parent = fdt_parent_offset(blob, node);
+ if (parent < 0) {
+ printf("Found dma-ranges in root node, shoudln't happen\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Get the address sizes both for the bus and its parent */
+ bus_node = of_match_bus(blob, node);
+ bus_node->count_cells(blob, node, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ printf("%s: Bad cell count for %s\n", __FUNCTION__,
+ fdt_get_name(blob, node, NULL));
+ return -EINVAL;
+ goto out;
+ }
+
+ bus_node = of_match_bus(blob, parent);
+ bus_node->count_cells(blob, parent, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ printf("%s: Bad cell count for %s\n", __FUNCTION__,
+ fdt_get_name(blob, parent, NULL));
+ return -EINVAL;
+ goto out;
+ }
+
+ *bus = fdt_read_number(ranges, na);
+ *cpu = fdt_translate_dma_address(blob, node, ranges + na);
+ *size = fdt_read_number(ranges + na + pna, ns);
+out:
+ return ret;
+}
+
+/**
+ * fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
+ * who's reg property matches a physical cpu address
+ *
+ * @blob: ptr to device tree
+ * @compat: compatiable string to match
+ * @compat_off: property name
+ *
+ */
+int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
+ phys_addr_t compat_off)
+{
+ int len, off = fdt_node_offset_by_compatible(blob, -1, compat);
+ while (off != -FDT_ERR_NOTFOUND) {
+ const fdt32_t *reg = fdt_getprop(blob, off, "reg", &len);
+ if (reg) {
+ if (compat_off == fdt_translate_address(blob, off, reg))
+ return off;
+ }
+ off = fdt_node_offset_by_compatible(blob, off, compat);
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+/**
+ * fdt_alloc_phandle: Return next free phandle value
+ *
+ * @blob: ptr to device tree
+ */
+int fdt_alloc_phandle(void *blob)
+{
+ int offset;
+ uint32_t phandle = 0;
+
+ for (offset = fdt_next_node(blob, -1, NULL); offset >= 0;
+ offset = fdt_next_node(blob, offset, NULL)) {
+ phandle = max(phandle, fdt_get_phandle(blob, offset));
+ }
+
+ return phandle + 1;
+}
+
+/*
+ * fdt_set_phandle: Create a phandle property for the given node
+ *
+ * @fdt: ptr to device tree
+ * @nodeoffset: node to update
+ * @phandle: phandle value to set (must be unique)
+ */
+int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle)
+{
+ int ret;
+
+#ifdef DEBUG
+ int off = fdt_node_offset_by_phandle(fdt, phandle);
+
+ if ((off >= 0) && (off != nodeoffset)) {
+ char buf[64];
+
+ fdt_get_path(fdt, nodeoffset, buf, sizeof(buf));
+ printf("Trying to update node %s with phandle %u ",
+ buf, phandle);
+
+ fdt_get_path(fdt, off, buf, sizeof(buf));
+ printf("that already exists in node %s.\n", buf);
+ return -FDT_ERR_BADPHANDLE;
+ }
+#endif
+
+ ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * For now, also set the deprecated "linux,phandle" property, so that we
+ * don't break older kernels.
+ */
+ ret = fdt_setprop_cell(fdt, nodeoffset, "linux,phandle", phandle);
+
+ return ret;
+}
+
+/*
+ * fdt_create_phandle: Create a phandle property for the given node
+ *
+ * @fdt: ptr to device tree
+ * @nodeoffset: node to update
+ */
+unsigned int fdt_create_phandle(void *fdt, int nodeoffset)
+{
+ /* see if there is a phandle already */
+ int phandle = fdt_get_phandle(fdt, nodeoffset);
+
+ /* if we got 0, means no phandle so create one */
+ if (phandle == 0) {
+ int ret;
+
+ phandle = fdt_alloc_phandle(fdt);
+ ret = fdt_set_phandle(fdt, nodeoffset, phandle);
+ if (ret < 0) {
+ printf("Can't set phandle %u: %s\n", phandle,
+ fdt_strerror(ret));
+ return 0;
+ }
+ }
+
+ return phandle;
+}
+
+/*
+ * fdt_set_node_status: Set status for the given node
+ *
+ * @fdt: ptr to device tree
+ * @nodeoffset: node to update
+ * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED,
+ * FDT_STATUS_FAIL, FDT_STATUS_FAIL_ERROR_CODE
+ * @error_code: optional, only used if status is FDT_STATUS_FAIL_ERROR_CODE
+ */
+int fdt_set_node_status(void *fdt, int nodeoffset,
+ enum fdt_status status, unsigned int error_code)
+{
+ char buf[16];
+ int ret = 0;
+
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ switch (status) {
+ case FDT_STATUS_OKAY:
+ ret = fdt_setprop_string(fdt, nodeoffset, "status", "okay");
+ break;
+ case FDT_STATUS_DISABLED:
+ ret = fdt_setprop_string(fdt, nodeoffset, "status", "disabled");
+ break;
+ case FDT_STATUS_FAIL:
+ ret = fdt_setprop_string(fdt, nodeoffset, "status", "fail");
+ break;
+ case FDT_STATUS_FAIL_ERROR_CODE:
+ sprintf(buf, "fail-%d", error_code);
+ ret = fdt_setprop_string(fdt, nodeoffset, "status", buf);
+ break;
+ default:
+ printf("Invalid fdt status: %x\n", status);
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * fdt_set_status_by_alias: Set status for the given node given an alias
+ *
+ * @fdt: ptr to device tree
+ * @alias: alias of node to update
+ * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED,
+ * FDT_STATUS_FAIL, FDT_STATUS_FAIL_ERROR_CODE
+ * @error_code: optional, only used if status is FDT_STATUS_FAIL_ERROR_CODE
+ */
+int fdt_set_status_by_alias(void *fdt, const char* alias,
+ enum fdt_status status, unsigned int error_code)
+{
+ int offset = fdt_path_offset(fdt, alias);
+
+ return fdt_set_node_status(fdt, offset, status, error_code);
+}
+
+#if defined(CONFIG_VIDEO) || defined(CONFIG_LCD)
+int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf)
+{
+ int noff;
+ int ret;
+
+ noff = fdt_node_offset_by_compatible(blob, -1, compat);
+ if (noff != -FDT_ERR_NOTFOUND) {
+ debug("%s: %s\n", fdt_get_name(blob, noff, 0), compat);
+add_edid:
+ ret = fdt_setprop(blob, noff, "edid", edid_buf, 128);
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_edid;
+ else
+ goto err_size;
+ } else if (ret < 0) {
+ printf("Can't add property: %s\n", fdt_strerror(ret));
+ return ret;
+ }
+ }
+ return 0;
+err_size:
+ printf("Can't increase blob size: %s\n", fdt_strerror(ret));
+ return ret;
+}
+#endif
+
+/*
+ * Verify the physical address of device tree node for a given alias
+ *
+ * This function locates the device tree node of a given alias, and then
+ * verifies that the physical address of that device matches the given
+ * parameter. It displays a message if there is a mismatch.
+ *
+ * Returns 1 on success, 0 on failure
+ */
+int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr)
+{
+ const char *path;
+ const fdt32_t *reg;
+ int node, len;
+ u64 dt_addr;
+
+ path = fdt_getprop(fdt, anode, alias, NULL);
+ if (!path) {
+ /* If there's no such alias, then it's not a failure */
+ return 1;
+ }
+
+ node = fdt_path_offset(fdt, path);
+ if (node < 0) {
+ printf("Warning: device tree alias '%s' points to invalid "
+ "node %s.\n", alias, path);
+ return 0;
+ }
+
+ reg = fdt_getprop(fdt, node, "reg", &len);
+ if (!reg) {
+ printf("Warning: device tree node '%s' has no address.\n",
+ path);
+ return 0;
+ }
+
+ dt_addr = fdt_translate_address(fdt, node, reg);
+ if (addr != dt_addr) {
+ printf("Warning: U-Boot configured device %s at address %llu,\n"
+ "but the device tree has it address %llx.\n",
+ alias, addr, dt_addr);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Returns the base address of an SOC or PCI node
+ */
+u64 fdt_get_base_address(const void *fdt, int node)
+{
+ int size;
+ const fdt32_t *prop;
+
+ prop = fdt_getprop(fdt, node, "reg", &size);
+
+ return prop ? fdt_translate_address(fdt, node, prop) : OF_BAD_ADDR;
+}
+
+/*
+ * Read a property of size <prop_len>. Currently only supports 1 or 2 cells,
+ * or 3 cells specially for a PCI address.
+ */
+static int fdt_read_prop(const fdt32_t *prop, int prop_len, int cell_off,
+ uint64_t *val, int cells)
+{
+ const fdt32_t *prop32;
+ const unaligned_fdt64_t *prop64;
+
+ if ((cell_off + cells) > prop_len)
+ return -FDT_ERR_NOSPACE;
+
+ prop32 = &prop[cell_off];
+
+ /*
+ * Special handling for PCI address in PCI bus <ranges>
+ *
+ * PCI child address is made up of 3 cells. Advance the cell offset
+ * by 1 so that the PCI child address can be correctly read.
+ */
+ if (cells == 3)
+ cell_off += 1;
+ prop64 = (const fdt64_t *)&prop[cell_off];
+
+ switch (cells) {
+ case 1:
+ *val = fdt32_to_cpu(*prop32);
+ break;
+ case 2:
+ case 3:
+ *val = fdt64_to_cpu(*prop64);
+ break;
+ default:
+ return -FDT_ERR_NOSPACE;
+ }
+
+ return 0;
+}
+
+/**
+ * fdt_read_range - Read a node's n'th range property
+ *
+ * @fdt: ptr to device tree
+ * @node: offset of node
+ * @n: range index
+ * @child_addr: pointer to storage for the "child address" field
+ * @addr: pointer to storage for the CPU view translated physical start
+ * @len: pointer to storage for the range length
+ *
+ * Convenience function that reads and interprets a specific range out of
+ * a number of the "ranges" property array.
+ */
+int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr,
+ uint64_t *addr, uint64_t *len)
+{
+ int pnode = fdt_parent_offset(fdt, node);
+ const fdt32_t *ranges;
+ int pacells;
+ int acells;
+ int scells;
+ int ranges_len;
+ int cell = 0;
+ int r = 0;
+
+ /*
+ * The "ranges" property is an array of
+ * { <child address> <parent address> <size in child address space> }
+ *
+ * All 3 elements can span a diffent number of cells. Fetch their size.
+ */
+ pacells = fdt_getprop_u32_default_node(fdt, pnode, 0, "#address-cells", 1);
+ acells = fdt_getprop_u32_default_node(fdt, node, 0, "#address-cells", 1);
+ scells = fdt_getprop_u32_default_node(fdt, node, 0, "#size-cells", 1);
+
+ /* Now try to get the ranges property */
+ ranges = fdt_getprop(fdt, node, "ranges", &ranges_len);
+ if (!ranges)
+ return -FDT_ERR_NOTFOUND;
+ ranges_len /= sizeof(uint32_t);
+
+ /* Jump to the n'th entry */
+ cell = n * (pacells + acells + scells);
+
+ /* Read <child address> */
+ if (child_addr) {
+ r = fdt_read_prop(ranges, ranges_len, cell, child_addr,
+ acells);
+ if (r)
+ return r;
+ }
+ cell += acells;
+
+ /* Read <parent address> */
+ if (addr)
+ *addr = fdt_translate_address(fdt, node, ranges + cell);
+ cell += pacells;
+
+ /* Read <size in child address space> */
+ if (len) {
+ r = fdt_read_prop(ranges, ranges_len, cell, len, scells);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+/**
+ * fdt_setup_simplefb_node - Fill and enable a simplefb node
+ *
+ * @fdt: ptr to device tree
+ * @node: offset of the simplefb node
+ * @base_address: framebuffer base address
+ * @width: width in pixels
+ * @height: height in pixels
+ * @stride: bytes per line
+ * @format: pixel format string
+ *
+ * Convenience function to fill and enable a simplefb node.
+ */
+int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
+ u32 height, u32 stride, const char *format)
+{
+ char name[32];
+ fdt32_t cells[4];
+ int i, addrc, sizec, ret;
+
+ fdt_support_default_count_cells(fdt, fdt_parent_offset(fdt, node),
+ &addrc, &sizec);
+ i = 0;
+ if (addrc == 2)
+ cells[i++] = cpu_to_fdt32(base_address >> 32);
+ cells[i++] = cpu_to_fdt32(base_address);
+ if (sizec == 2)
+ cells[i++] = 0;
+ cells[i++] = cpu_to_fdt32(height * stride);
+
+ ret = fdt_setprop(fdt, node, "reg", cells, sizeof(cells[0]) * i);
+ if (ret < 0)
+ return ret;
+
+ snprintf(name, sizeof(name), "framebuffer@%llx", base_address);
+ ret = fdt_set_name(fdt, node, name);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_setprop_u32(fdt, node, "width", width);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_setprop_u32(fdt, node, "height", height);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_setprop_u32(fdt, node, "stride", stride);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_setprop_string(fdt, node, "format", format);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_setprop_string(fdt, node, "status", "okay");
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * Update native-mode in display-timings from display environment variable.
+ * The node to update are specified by path.
+ */
+int fdt_fixup_display(void *blob, const char *path, const char *display)
+{
+ int off, toff;
+
+ if (!display || !path)
+ return -FDT_ERR_NOTFOUND;
+
+ toff = fdt_path_offset(blob, path);
+ if (toff >= 0)
+ toff = fdt_subnode_offset(blob, toff, "display-timings");
+ if (toff < 0)
+ return toff;
+
+ for (off = fdt_first_subnode(blob, toff);
+ off >= 0;
+ off = fdt_next_subnode(blob, off)) {
+ uint32_t h = fdt_get_phandle(blob, off);
+ debug("%s:0x%x\n", fdt_get_name(blob, off, NULL),
+ fdt32_to_cpu(h));
+ if (strcasecmp(fdt_get_name(blob, off, NULL), display) == 0)
+ return fdt_setprop_u32(blob, toff, "native-mode", h);
+ }
+ return toff;
+}
+
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+/**
+ * fdt_overlay_apply_verbose - Apply an overlay with verbose error reporting
+ *
+ * @fdt: ptr to device tree
+ * @fdto: ptr to device tree overlay
+ *
+ * Convenience function to apply an overlay and display helpful messages
+ * in the case of an error
+ */
+int fdt_overlay_apply_verbose(void *fdt, void *fdto)
+{
+ int err;
+ bool has_symbols;
+
+ err = fdt_path_offset(fdt, "/__symbols__");
+ has_symbols = err >= 0;
+
+ err = fdt_overlay_apply(fdt, fdto);
+ if (err < 0) {
+ printf("failed on fdt_overlay_apply(): %s\n",
+ fdt_strerror(err));
+ if (!has_symbols) {
+ printf("base fdt does did not have a /__symbols__ node\n");
+ printf("make sure you've compiled with -@\n");
+ }
+ }
+ return err;
+}
+#endif
+
+/**
+ * fdt_valid() - Check if an FDT is valid. If not, change it to NULL
+ *
+ * @blobp: Pointer to FDT pointer
+ * @return 1 if OK, 0 if bad (in which case *blobp is set to NULL)
+ */
+int fdt_valid(struct fdt_header **blobp)
+{
+ const void *blob = *blobp;
+ int err;
+
+ if (!blob) {
+ printf("The address of the fdt is invalid (NULL).\n");
+ return 0;
+ }
+
+ err = fdt_check_header(blob);
+ if (err == 0)
+ return 1; /* valid */
+
+ if (err < 0) {
+ printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
+ /*
+ * Be more informative on bad version.
+ */
+ if (err == -FDT_ERR_BADVERSION) {
+ if (fdt_version(blob) <
+ FDT_FIRST_SUPPORTED_VERSION) {
+ printf(" - too old, fdt %d < %d",
+ fdt_version(blob),
+ FDT_FIRST_SUPPORTED_VERSION);
+ }
+ if (fdt_last_comp_version(blob) >
+ FDT_LAST_SUPPORTED_VERSION) {
+ printf(" - too new, fdt %d > %d",
+ fdt_version(blob),
+ FDT_LAST_SUPPORTED_VERSION);
+ }
+ }
+ printf("\n");
+ *blobp = NULL;
+ return 0;
+ }
+ return 1;
+}
diff --git a/roms/u-boot/common/flash.c b/roms/u-boot/common/flash.c
new file mode 100644
index 000000000..bb82385c1
--- /dev/null
+++ b/roms/u-boot/common/flash.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <flash.h>
+#include <log.h>
+#include <uuid.h>
+
+#include <mtd/cfi_flash.h>
+
+extern flash_info_t flash_info[]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+/*-----------------------------------------------------------------------
+ * Set protection status for monitor sectors
+ *
+ * The monitor is always located in the _first_ Flash bank.
+ * If necessary you have to map the second bank at lower addresses.
+ */
+void
+flash_protect(int flag, ulong from, ulong to, flash_info_t *info)
+{
+ ulong b_end;
+ short s_end;
+ int i;
+
+ /* Do nothing if input data is bad. */
+ if (!info || info->sector_count == 0 || info->size == 0 || to < from) {
+ return;
+ }
+
+ s_end = info->sector_count - 1; /* index of last sector */
+ b_end = info->start[0] + info->size - 1; /* bank end address */
+
+ debug("%s %s: from 0x%08lX to 0x%08lX\n", __func__,
+ (flag & FLAG_PROTECT_SET) ? "ON" :
+ (flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???",
+ from, to);
+
+ /* There is nothing to do if we have no data about the flash
+ * or the protect range and flash range don't overlap.
+ */
+ if (info->flash_id == FLASH_UNKNOWN ||
+ to < info->start[0] || from > b_end) {
+ return;
+ }
+
+ for (i=0; i<info->sector_count; ++i) {
+ ulong end; /* last address in current sect */
+
+ end = (i == s_end) ? b_end : info->start[i + 1] - 1;
+
+ /* Update protection if any part of the sector
+ * is in the specified range.
+ */
+ if (from <= end && to >= info->start[i]) {
+ if (flag & FLAG_PROTECT_CLEAR) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ flash_real_protect(info, i, 0);
+#else
+ info->protect[i] = 0;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ debug("protect off %d\n", i);
+ }
+ else if (flag & FLAG_PROTECT_SET) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ flash_real_protect(info, i, 1);
+#else
+ info->protect[i] = 1;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ debug("protect on %d\n", i);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+flash_info_t *
+addr2info(ulong addr)
+{
+ flash_info_t *info;
+ int i;
+
+ for (i=0, info = &flash_info[0]; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
+ if (info->flash_id != FLASH_UNKNOWN &&
+ addr >= info->start[0] &&
+ /* WARNING - The '- 1' is needed if the flash
+ * is at the end of the address space, since
+ * info->start[0] + info->size wraps back to 0.
+ * Please don't change this unless you understand this.
+ */
+ addr <= info->start[0] + info->size - 1) {
+ return (info);
+ }
+ }
+
+ return (NULL);
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ * Make sure all target addresses are within Flash bounds,
+ * and no protected sectors are hit.
+ * Returns:
+ * ERR_OK 0 - OK
+ * ERR_TIMEOUT 1 - write timeout
+ * ERR_NOT_ERASED 2 - Flash not erased
+ * ERR_PROTECTED 4 - target range includes protected sectors
+ * ERR_INVAL 8 - target address not in Flash memory
+ * ERR_ALIGN 16 - target address not aligned on boundary
+ * (only some targets require alignment)
+ */
+int
+flash_write(char *src, ulong addr, ulong cnt)
+{
+ int i;
+ ulong end = addr + cnt - 1;
+ flash_info_t *info_first = addr2info(addr);
+ flash_info_t *info_last = addr2info(end);
+ flash_info_t *info;
+ __maybe_unused char *src_orig = src;
+ __maybe_unused char *addr_orig = (char *)addr;
+ __maybe_unused ulong cnt_orig = cnt;
+
+ if (cnt == 0) {
+ return (ERR_OK);
+ }
+
+ if (!info_first || !info_last) {
+ return (ERR_INVAL);
+ }
+
+ for (info = info_first; info <= info_last; ++info) {
+ ulong b_end = info->start[0] + info->size; /* bank end addr */
+ short s_end = info->sector_count - 1;
+ for (i=0; i<info->sector_count; ++i) {
+ ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
+
+ if ((end >= info->start[i]) && (addr < e_addr) &&
+ (info->protect[i] != 0) ) {
+ return (ERR_PROTECTED);
+ }
+ }
+ }
+
+ /* finally write data to flash */
+ for (info = info_first; info <= info_last && cnt>0; ++info) {
+ ulong len;
+
+ len = info->start[0] + info->size - addr;
+ if (len > cnt)
+ len = cnt;
+ if ((i = write_buff(info, (uchar *)src, addr, len)) != 0) {
+ return (i);
+ }
+ cnt -= len;
+ addr += len;
+ src += len;
+ }
+
+#if defined(CONFIG_FLASH_VERIFY)
+ if (memcmp(src_orig, addr_orig, cnt_orig)) {
+ printf("\nVerify failed!\n");
+ return ERR_PROG_ERROR;
+ }
+#endif /* CONFIG_SYS_FLASH_VERIFY_AFTER_WRITE */
+
+ return (ERR_OK);
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_perror(int err)
+{
+ switch (err) {
+ case ERR_OK:
+ break;
+ case ERR_TIMEOUT:
+ puts ("Timeout writing to Flash\n");
+ break;
+ case ERR_NOT_ERASED:
+ puts ("Flash not Erased\n");
+ break;
+ case ERR_PROTECTED:
+ puts ("Can't write to protected Flash sectors\n");
+ break;
+ case ERR_INVAL:
+ puts ("Outside available Flash\n");
+ break;
+ case ERR_ALIGN:
+ puts ("Start and/or end address not on sector boundary\n");
+ break;
+ case ERR_UNKNOWN_FLASH_VENDOR:
+ puts ("Unknown Vendor of Flash\n");
+ break;
+ case ERR_UNKNOWN_FLASH_TYPE:
+ puts ("Unknown Type of Flash\n");
+ break;
+ case ERR_PROG_ERROR:
+ puts ("General Flash Programming Error\n");
+ break;
+ case ERR_ABORTED:
+ puts("Flash Programming Aborted\n");
+ break;
+ default:
+ printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);
+ break;
+ }
+}
diff --git a/roms/u-boot/common/hash.c b/roms/u-boot/common/hash.c
new file mode 100644
index 000000000..90cf46bcb
--- /dev/null
+++ b/roms/u-boot/common/hash.c
@@ -0,0 +1,639 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * (C) Copyright 2011
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#ifndef USE_HOSTCC
+#include <common.h>
+#include <command.h>
+#include <env.h>
+#include <log.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <hw_sha.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <u-boot/crc.h>
+#else
+#include "mkimage.h"
+#include <time.h>
+#endif /* !USE_HOSTCC*/
+
+#include <hash.h>
+#include <image.h>
+#include <u-boot/crc.h>
+#include <u-boot/sha1.h>
+#include <u-boot/sha256.h>
+#include <u-boot/sha512.h>
+#include <u-boot/md5.h>
+
+#if !defined(USE_HOSTCC) && defined(CONFIG_NEEDS_MANUAL_RELOC)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+static void reloc_update(void);
+
+#if defined(CONFIG_SHA1) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
+static int hash_init_sha1(struct hash_algo *algo, void **ctxp)
+{
+ sha1_context *ctx = malloc(sizeof(sha1_context));
+ sha1_starts(ctx);
+ *ctxp = ctx;
+ return 0;
+}
+
+static int hash_update_sha1(struct hash_algo *algo, void *ctx, const void *buf,
+ unsigned int size, int is_last)
+{
+ sha1_update((sha1_context *)ctx, buf, size);
+ return 0;
+}
+
+static int hash_finish_sha1(struct hash_algo *algo, void *ctx, void *dest_buf,
+ int size)
+{
+ if (size < algo->digest_size)
+ return -1;
+
+ sha1_finish((sha1_context *)ctx, dest_buf);
+ free(ctx);
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SHA256) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
+static int hash_init_sha256(struct hash_algo *algo, void **ctxp)
+{
+ sha256_context *ctx = malloc(sizeof(sha256_context));
+ sha256_starts(ctx);
+ *ctxp = ctx;
+ return 0;
+}
+
+static int hash_update_sha256(struct hash_algo *algo, void *ctx,
+ const void *buf, unsigned int size, int is_last)
+{
+ sha256_update((sha256_context *)ctx, buf, size);
+ return 0;
+}
+
+static int hash_finish_sha256(struct hash_algo *algo, void *ctx, void
+ *dest_buf, int size)
+{
+ if (size < algo->digest_size)
+ return -1;
+
+ sha256_finish((sha256_context *)ctx, dest_buf);
+ free(ctx);
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SHA384) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
+static int hash_init_sha384(struct hash_algo *algo, void **ctxp)
+{
+ sha512_context *ctx = malloc(sizeof(sha512_context));
+ sha384_starts(ctx);
+ *ctxp = ctx;
+ return 0;
+}
+
+static int hash_update_sha384(struct hash_algo *algo, void *ctx,
+ const void *buf, unsigned int size, int is_last)
+{
+ sha384_update((sha512_context *)ctx, buf, size);
+ return 0;
+}
+
+static int hash_finish_sha384(struct hash_algo *algo, void *ctx, void
+ *dest_buf, int size)
+{
+ if (size < algo->digest_size)
+ return -1;
+
+ sha384_finish((sha512_context *)ctx, dest_buf);
+ free(ctx);
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SHA512) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
+static int hash_init_sha512(struct hash_algo *algo, void **ctxp)
+{
+ sha512_context *ctx = malloc(sizeof(sha512_context));
+ sha512_starts(ctx);
+ *ctxp = ctx;
+ return 0;
+}
+
+static int hash_update_sha512(struct hash_algo *algo, void *ctx,
+ const void *buf, unsigned int size, int is_last)
+{
+ sha512_update((sha512_context *)ctx, buf, size);
+ return 0;
+}
+
+static int hash_finish_sha512(struct hash_algo *algo, void *ctx, void
+ *dest_buf, int size)
+{
+ if (size < algo->digest_size)
+ return -1;
+
+ sha512_finish((sha512_context *)ctx, dest_buf);
+ free(ctx);
+ return 0;
+}
+#endif
+
+
+static int hash_init_crc16_ccitt(struct hash_algo *algo, void **ctxp)
+{
+ uint16_t *ctx = malloc(sizeof(uint16_t));
+ *ctx = 0;
+ *ctxp = ctx;
+ return 0;
+}
+
+static int hash_update_crc16_ccitt(struct hash_algo *algo, void *ctx,
+ const void *buf, unsigned int size,
+ int is_last)
+{
+ *((uint16_t *)ctx) = crc16_ccitt(*((uint16_t *)ctx), buf, size);
+ return 0;
+}
+
+static int hash_finish_crc16_ccitt(struct hash_algo *algo, void *ctx,
+ void *dest_buf, int size)
+{
+ if (size < algo->digest_size)
+ return -1;
+
+ *((uint16_t *)dest_buf) = *((uint16_t *)ctx);
+ free(ctx);
+ return 0;
+}
+
+static int hash_init_crc32(struct hash_algo *algo, void **ctxp)
+{
+ uint32_t *ctx = malloc(sizeof(uint32_t));
+ *ctx = 0;
+ *ctxp = ctx;
+ return 0;
+}
+
+static int hash_update_crc32(struct hash_algo *algo, void *ctx,
+ const void *buf, unsigned int size, int is_last)
+{
+ *((uint32_t *)ctx) = crc32(*((uint32_t *)ctx), buf, size);
+ return 0;
+}
+
+static int hash_finish_crc32(struct hash_algo *algo, void *ctx, void *dest_buf,
+ int size)
+{
+ if (size < algo->digest_size)
+ return -1;
+
+ *((uint32_t *)dest_buf) = *((uint32_t *)ctx);
+ free(ctx);
+ return 0;
+}
+
+/*
+ * These are the hash algorithms we support. If we have hardware acceleration
+ * is enable we will use that, otherwise a software version of the algorithm.
+ * Note that algorithm names must be in lower case.
+ */
+static struct hash_algo hash_algo[] = {
+#ifdef CONFIG_SHA1
+ {
+ .name = "sha1",
+ .digest_size = SHA1_SUM_LEN,
+ .chunk_size = CHUNKSZ_SHA1,
+#ifdef CONFIG_SHA_HW_ACCEL
+ .hash_func_ws = hw_sha1,
+#else
+ .hash_func_ws = sha1_csum_wd,
+#endif
+#ifdef CONFIG_SHA_PROG_HW_ACCEL
+ .hash_init = hw_sha_init,
+ .hash_update = hw_sha_update,
+ .hash_finish = hw_sha_finish,
+#else
+ .hash_init = hash_init_sha1,
+ .hash_update = hash_update_sha1,
+ .hash_finish = hash_finish_sha1,
+#endif
+ },
+#endif
+#ifdef CONFIG_SHA256
+ {
+ .name = "sha256",
+ .digest_size = SHA256_SUM_LEN,
+ .chunk_size = CHUNKSZ_SHA256,
+#ifdef CONFIG_SHA_HW_ACCEL
+ .hash_func_ws = hw_sha256,
+#else
+ .hash_func_ws = sha256_csum_wd,
+#endif
+#ifdef CONFIG_SHA_PROG_HW_ACCEL
+ .hash_init = hw_sha_init,
+ .hash_update = hw_sha_update,
+ .hash_finish = hw_sha_finish,
+#else
+ .hash_init = hash_init_sha256,
+ .hash_update = hash_update_sha256,
+ .hash_finish = hash_finish_sha256,
+#endif
+ },
+#endif
+#ifdef CONFIG_SHA384
+ {
+ .name = "sha384",
+ .digest_size = SHA384_SUM_LEN,
+ .chunk_size = CHUNKSZ_SHA384,
+#ifdef CONFIG_SHA512_HW_ACCEL
+ .hash_func_ws = hw_sha384,
+#else
+ .hash_func_ws = sha384_csum_wd,
+#endif
+#if defined(CONFIG_SHA512_HW_ACCEL) && defined(CONFIG_SHA_PROG_HW_ACCEL)
+ .hash_init = hw_sha_init,
+ .hash_update = hw_sha_update,
+ .hash_finish = hw_sha_finish,
+#else
+ .hash_init = hash_init_sha384,
+ .hash_update = hash_update_sha384,
+ .hash_finish = hash_finish_sha384,
+#endif
+ },
+#endif
+#ifdef CONFIG_SHA512
+ {
+ .name = "sha512",
+ .digest_size = SHA512_SUM_LEN,
+ .chunk_size = CHUNKSZ_SHA512,
+#ifdef CONFIG_SHA512_HW_ACCEL
+ .hash_func_ws = hw_sha512,
+#else
+ .hash_func_ws = sha512_csum_wd,
+#endif
+#if defined(CONFIG_SHA512_HW_ACCEL) && defined(CONFIG_SHA_PROG_HW_ACCEL)
+ .hash_init = hw_sha_init,
+ .hash_update = hw_sha_update,
+ .hash_finish = hw_sha_finish,
+#else
+ .hash_init = hash_init_sha512,
+ .hash_update = hash_update_sha512,
+ .hash_finish = hash_finish_sha512,
+#endif
+ },
+#endif
+ {
+ .name = "crc16-ccitt",
+ .digest_size = 2,
+ .chunk_size = CHUNKSZ,
+ .hash_func_ws = crc16_ccitt_wd_buf,
+ .hash_init = hash_init_crc16_ccitt,
+ .hash_update = hash_update_crc16_ccitt,
+ .hash_finish = hash_finish_crc16_ccitt,
+ },
+ {
+ .name = "crc32",
+ .digest_size = 4,
+ .chunk_size = CHUNKSZ_CRC32,
+ .hash_func_ws = crc32_wd_buf,
+ .hash_init = hash_init_crc32,
+ .hash_update = hash_update_crc32,
+ .hash_finish = hash_finish_crc32,
+ },
+};
+
+/* Try to minimize code size for boards that don't want much hashing */
+#if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM) || \
+ defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_CMD_HASH) || \
+ defined(CONFIG_SHA384) || defined(CONFIG_SHA512)
+#define multi_hash() 1
+#else
+#define multi_hash() 0
+#endif
+
+static void reloc_update(void)
+{
+#if !defined(USE_HOSTCC) && defined(CONFIG_NEEDS_MANUAL_RELOC)
+ int i;
+ static bool done;
+
+ if (!done) {
+ done = true;
+ for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
+ hash_algo[i].name += gd->reloc_off;
+ hash_algo[i].hash_func_ws += gd->reloc_off;
+ hash_algo[i].hash_init += gd->reloc_off;
+ hash_algo[i].hash_update += gd->reloc_off;
+ hash_algo[i].hash_finish += gd->reloc_off;
+ }
+ }
+#endif
+}
+
+int hash_lookup_algo(const char *algo_name, struct hash_algo **algop)
+{
+ int i;
+
+ reloc_update();
+
+ for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
+ if (!strcmp(algo_name, hash_algo[i].name)) {
+ *algop = &hash_algo[i];
+ return 0;
+ }
+ }
+
+ debug("Unknown hash algorithm '%s'\n", algo_name);
+ return -EPROTONOSUPPORT;
+}
+
+int hash_progressive_lookup_algo(const char *algo_name,
+ struct hash_algo **algop)
+{
+ int i;
+
+ reloc_update();
+
+ for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
+ if (!strcmp(algo_name, hash_algo[i].name)) {
+ if (hash_algo[i].hash_init) {
+ *algop = &hash_algo[i];
+ return 0;
+ }
+ }
+ }
+
+ debug("Unknown hash algorithm '%s'\n", algo_name);
+ return -EPROTONOSUPPORT;
+}
+
+#ifndef USE_HOSTCC
+int hash_parse_string(const char *algo_name, const char *str, uint8_t *result)
+{
+ struct hash_algo *algo;
+ int ret;
+ int i;
+
+ ret = hash_lookup_algo(algo_name, &algo);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < algo->digest_size; i++) {
+ char chr[3];
+
+ strncpy(chr, &str[i * 2], 2);
+ result[i] = simple_strtoul(chr, NULL, 16);
+ }
+
+ return 0;
+}
+
+int hash_block(const char *algo_name, const void *data, unsigned int len,
+ uint8_t *output, int *output_size)
+{
+ struct hash_algo *algo;
+ int ret;
+
+ ret = hash_lookup_algo(algo_name, &algo);
+ if (ret)
+ return ret;
+
+ if (output_size && *output_size < algo->digest_size) {
+ debug("Output buffer size %d too small (need %d bytes)",
+ *output_size, algo->digest_size);
+ return -ENOSPC;
+ }
+ if (output_size)
+ *output_size = algo->digest_size;
+ algo->hash_func_ws(data, len, output, algo->chunk_size);
+
+ return 0;
+}
+
+#if defined(CONFIG_CMD_HASH) || defined(CONFIG_CMD_SHA1SUM) || defined(CONFIG_CMD_CRC32)
+/**
+ * store_result: Store the resulting sum to an address or variable
+ *
+ * @algo: Hash algorithm being used
+ * @sum: Hash digest (algo->digest_size bytes)
+ * @dest: Destination, interpreted as a hex address if it starts
+ * with * (or allow_env_vars is 0) or otherwise as an
+ * environment variable.
+ * @allow_env_vars: non-zero to permit storing the result to an
+ * variable environment
+ */
+static void store_result(struct hash_algo *algo, const uint8_t *sum,
+ const char *dest, int allow_env_vars)
+{
+ unsigned int i;
+ int env_var = 0;
+
+ /*
+ * If environment variables are allowed, then we assume that 'dest'
+ * is an environment variable, unless it starts with *, in which
+ * case we assume it is an address. If not allowed, it is always an
+ * address. This is to support the crc32 command.
+ */
+ if (allow_env_vars) {
+ if (*dest == '*')
+ dest++;
+ else
+ env_var = 1;
+ }
+
+ if (env_var) {
+ char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1];
+ char *str_ptr = str_output;
+
+ for (i = 0; i < algo->digest_size; i++) {
+ sprintf(str_ptr, "%02x", sum[i]);
+ str_ptr += 2;
+ }
+ *str_ptr = '\0';
+ env_set(dest, str_output);
+ } else {
+ ulong addr;
+ void *buf;
+
+ addr = simple_strtoul(dest, NULL, 16);
+ buf = map_sysmem(addr, algo->digest_size);
+ memcpy(buf, sum, algo->digest_size);
+ unmap_sysmem(buf);
+ }
+}
+
+/**
+ * parse_verify_sum: Parse a hash verification parameter
+ *
+ * @algo: Hash algorithm being used
+ * @verify_str: Argument to parse. If it starts with * then it is
+ * interpreted as a hex address containing the hash.
+ * If the length is exactly the right number of hex digits
+ * for the digest size, then we assume it is a hex digest.
+ * Otherwise we assume it is an environment variable, and
+ * look up its value (it must contain a hex digest).
+ * @vsum: Returns binary digest value (algo->digest_size bytes)
+ * @allow_env_vars: non-zero to permit storing the result to an environment
+ * variable. If 0 then verify_str is assumed to be an
+ * address, and the * prefix is not expected.
+ * @return 0 if ok, non-zero on error
+ */
+static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
+ uint8_t *vsum, int allow_env_vars)
+{
+ int env_var = 0;
+
+ /* See comment above in store_result() */
+ if (allow_env_vars) {
+ if (*verify_str == '*')
+ verify_str++;
+ else
+ env_var = 1;
+ }
+
+ if (!env_var) {
+ ulong addr;
+ void *buf;
+
+ addr = simple_strtoul(verify_str, NULL, 16);
+ buf = map_sysmem(addr, algo->digest_size);
+ memcpy(vsum, buf, algo->digest_size);
+ } else {
+ char *vsum_str;
+ int digits = algo->digest_size * 2;
+
+ /*
+ * As with the original code from sha1sum.c, we assume that a
+ * string which matches the digest size exactly is a hex
+ * string and not an environment variable.
+ */
+ if (strlen(verify_str) == digits)
+ vsum_str = verify_str;
+ else {
+ vsum_str = env_get(verify_str);
+ if (vsum_str == NULL || strlen(vsum_str) != digits) {
+ printf("Expected %d hex digits in env var\n",
+ digits);
+ return 1;
+ }
+ }
+
+ hash_parse_string(algo->name, vsum_str, vsum);
+ }
+ return 0;
+}
+
+static void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output)
+{
+ int i;
+
+ printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1);
+ for (i = 0; i < algo->digest_size; i++)
+ printf("%02x", output[i]);
+}
+
+int hash_command(const char *algo_name, int flags, struct cmd_tbl *cmdtp,
+ int flag, int argc, char *const argv[])
+{
+ ulong addr, len;
+
+ if ((argc < 2) || ((flags & HASH_FLAG_VERIFY) && (argc < 3)))
+ return CMD_RET_USAGE;
+
+ addr = simple_strtoul(*argv++, NULL, 16);
+ len = simple_strtoul(*argv++, NULL, 16);
+
+ if (multi_hash()) {
+ struct hash_algo *algo;
+ u8 *output;
+ uint8_t vsum[HASH_MAX_DIGEST_SIZE];
+ void *buf;
+
+ if (hash_lookup_algo(algo_name, &algo)) {
+ printf("Unknown hash algorithm '%s'\n", algo_name);
+ return CMD_RET_USAGE;
+ }
+ argc -= 2;
+
+ if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
+ puts("HASH_MAX_DIGEST_SIZE exceeded\n");
+ return 1;
+ }
+
+ output = memalign(ARCH_DMA_MINALIGN,
+ sizeof(uint32_t) * HASH_MAX_DIGEST_SIZE);
+
+ buf = map_sysmem(addr, len);
+ algo->hash_func_ws(buf, len, output, algo->chunk_size);
+ unmap_sysmem(buf);
+
+ /* Try to avoid code bloat when verify is not needed */
+#if defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_SHA1SUM_VERIFY) || \
+ defined(CONFIG_HASH_VERIFY)
+ if (flags & HASH_FLAG_VERIFY) {
+#else
+ if (0) {
+#endif
+ if (parse_verify_sum(algo, *argv, vsum,
+ flags & HASH_FLAG_ENV)) {
+ printf("ERROR: %s does not contain a valid "
+ "%s sum\n", *argv, algo->name);
+ return 1;
+ }
+ if (memcmp(output, vsum, algo->digest_size) != 0) {
+ int i;
+
+ hash_show(algo, addr, len, output);
+ printf(" != ");
+ for (i = 0; i < algo->digest_size; i++)
+ printf("%02x", vsum[i]);
+ puts(" ** ERROR **\n");
+ return 1;
+ }
+ } else {
+ hash_show(algo, addr, len, output);
+ printf("\n");
+
+ if (argc) {
+ store_result(algo, output, *argv,
+ flags & HASH_FLAG_ENV);
+ }
+ unmap_sysmem(output);
+
+ }
+
+ /* Horrible code size hack for boards that just want crc32 */
+ } else {
+ ulong crc;
+ ulong *ptr;
+
+ crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32);
+
+ printf("CRC32 for %08lx ... %08lx ==> %08lx\n",
+ addr, addr + len - 1, crc);
+
+ if (argc >= 3) {
+ ptr = (ulong *)simple_strtoul(argv[0], NULL, 16);
+ *ptr = crc;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_CMD_HASH || CONFIG_CMD_SHA1SUM || CONFIG_CMD_CRC32) */
+#endif /* !USE_HOSTCC */
diff --git a/roms/u-boot/common/hwconfig.c b/roms/u-boot/common/hwconfig.c
new file mode 100644
index 000000000..26a561c36
--- /dev/null
+++ b/roms/u-boot/common/hwconfig.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * An inteface for configuring a hardware via u-boot environment.
+ *
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ */
+
+#ifndef HWCONFIG_TEST
+#include <config.h>
+#include <common.h>
+#include <env.h>
+#include <exports.h>
+#include <hwconfig.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* HWCONFIG_TEST */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *hwconfig_parse(const char *opts, size_t maxlen,
+ const char *opt, char *stopchs, char eqch,
+ size_t *arglen)
+{
+ size_t optlen = strlen(opt);
+ char *str;
+ const char *start = opts;
+ const char *end;
+
+next:
+ str = strstr(opts, opt);
+ end = str + optlen;
+ if (end - start > maxlen)
+ return NULL;
+
+ if (str && (str == opts || strpbrk(str - 1, stopchs) == str - 1) &&
+ (strpbrk(end, stopchs) == end || *end == eqch ||
+ *end == '\0')) {
+ const char *arg_end;
+
+ if (!arglen)
+ return str;
+
+ if (*end != eqch)
+ return NULL;
+
+ arg_end = strpbrk(str, stopchs);
+ if (!arg_end)
+ *arglen = min(maxlen, strlen(str)) - optlen - 1;
+ else
+ *arglen = arg_end - end - 1;
+
+ return end + 1;
+ } else if (str) {
+ opts = end;
+ goto next;
+ }
+ return NULL;
+}
+
+const char cpu_hwconfig[] __attribute__((weak)) = "";
+const char board_hwconfig[] __attribute__((weak)) = "";
+
+static const char *__hwconfig(const char *opt, size_t *arglen,
+ const char *env_hwconfig)
+{
+ const char *ret;
+
+ /* if we are passed a buffer use it, otherwise try the environment */
+ if (!env_hwconfig) {
+ if (!(gd->flags & GD_FLG_ENV_READY)) {
+ printf("WARNING: Calling __hwconfig without a buffer "
+ "and before environment is ready\n");
+ return NULL;
+ }
+ env_hwconfig = env_get("hwconfig");
+ }
+
+ if (env_hwconfig) {
+ ret = hwconfig_parse(env_hwconfig, strlen(env_hwconfig),
+ opt, ";", ':', arglen);
+ if (ret)
+ return ret;
+ }
+
+ ret = hwconfig_parse(board_hwconfig, strlen(board_hwconfig),
+ opt, ";", ':', arglen);
+ if (ret)
+ return ret;
+
+ return hwconfig_parse(cpu_hwconfig, strlen(cpu_hwconfig),
+ opt, ";", ':', arglen);
+}
+
+/*
+ * hwconfig_f - query if a particular hwconfig option is specified
+ * @opt: a string representing an option
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call can be used to find out whether U-Boot should configure
+ * a particular hardware option.
+ *
+ * Returns non-zero value if the hardware option can be used and thus
+ * should be configured, 0 otherwise.
+ *
+ * This function also returns non-zero value if CONFIG_HWCONFIG is
+ * undefined.
+ *
+ * Returning non-zero value without CONFIG_HWCONFIG has its crucial
+ * purpose: the hwconfig() call should be a "transparent" interface,
+ * e.g. if a board doesn't need hwconfig facility, then we assume
+ * that the board file only calls things that are actually used, so
+ * hwconfig() will always return true result.
+ */
+int hwconfig_f(const char *opt, char *buf)
+{
+ return !!__hwconfig(opt, NULL, buf);
+}
+
+/*
+ * hwconfig_arg_f - get hwconfig option's argument
+ * @opt: a string representing an option
+ * @arglen: a pointer to an allocated size_t variable
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * Unlike hwconfig_f() function, this function returns a pointer to the
+ * start of the hwconfig arguments, if option is not found or it has
+ * no specified arguments, the function returns NULL pointer.
+ *
+ * If CONFIG_HWCONFIG is undefined, the function returns "", and
+ * arglen is set to 0.
+ */
+const char *hwconfig_arg_f(const char *opt, size_t *arglen, char *buf)
+{
+ return __hwconfig(opt, arglen, buf);
+}
+
+/*
+ * hwconfig_arg_cmp_f - compare hwconfig option's argument
+ * @opt: a string representing an option
+ * @arg: a string for comparing an option's argument
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call is similar to hwconfig_arg_f, but instead of returning
+ * hwconfig argument and its length, it is comparing it to @arg.
+ *
+ * Returns non-zero value if @arg matches, 0 otherwise.
+ *
+ * If CONFIG_HWCONFIG is undefined, the function returns a non-zero
+ * value, i.e. the argument matches.
+ */
+int hwconfig_arg_cmp_f(const char *opt, const char *arg, char *buf)
+{
+ const char *argstr;
+ size_t arglen;
+
+ argstr = hwconfig_arg_f(opt, &arglen, buf);
+ if (!argstr || arglen != strlen(arg))
+ return 0;
+
+ return !strncmp(argstr, arg, arglen);
+}
+
+/*
+ * hwconfig_sub_f - query if a particular hwconfig sub-option is specified
+ * @opt: a string representing an option
+ * @subopt: a string representing a sub-option
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call is similar to hwconfig_f(), except that it takes additional
+ * argument @subopt. In this example:
+ * "dr_usb:mode=peripheral"
+ * "dr_usb" is an option, "mode" is a sub-option, and "peripheral" is its
+ * argument.
+ */
+int hwconfig_sub_f(const char *opt, const char *subopt, char *buf)
+{
+ size_t arglen;
+ const char *arg;
+
+ arg = __hwconfig(opt, &arglen, buf);
+ if (!arg)
+ return 0;
+ return !!hwconfig_parse(arg, arglen, subopt, ",;", '=', NULL);
+}
+
+/*
+ * hwconfig_subarg_f - get hwconfig sub-option's argument
+ * @opt: a string representing an option
+ * @subopt: a string representing a sub-option
+ * @subarglen: a pointer to an allocated size_t variable
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call is similar to hwconfig_arg_f(), except that it takes an
+ * additional argument @subopt, and so works with sub-options.
+ */
+const char *hwconfig_subarg_f(const char *opt, const char *subopt,
+ size_t *subarglen, char *buf)
+{
+ size_t arglen;
+ const char *arg;
+
+ arg = __hwconfig(opt, &arglen, buf);
+ if (!arg)
+ return NULL;
+ return hwconfig_parse(arg, arglen, subopt, ",;", '=', subarglen);
+}
+
+/*
+ * hwconfig_arg_cmp_f - compare hwconfig sub-option's argument
+ * @opt: a string representing an option
+ * @subopt: a string representing a sub-option
+ * @subarg: a string for comparing an sub-option's argument
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call is similar to hwconfig_arg_cmp_f, except that it takes an
+ * additional argument @subopt, and so works with sub-options.
+ */
+int hwconfig_subarg_cmp_f(const char *opt, const char *subopt,
+ const char *subarg, char *buf)
+{
+ const char *argstr;
+ size_t arglen;
+
+ argstr = hwconfig_subarg_f(opt, subopt, &arglen, buf);
+ if (!argstr || arglen != strlen(subarg))
+ return 0;
+
+ return !strncmp(argstr, subarg, arglen);
+}
+
+#ifdef HWCONFIG_TEST
+int main()
+{
+ const char *ret;
+ size_t len;
+
+ env_set("hwconfig", "key1:subkey1=value1,subkey2=value2;key2:value3;;;;"
+ "key3;:,:=;key4", 1);
+
+ ret = hwconfig_arg("key1", &len);
+ printf("%zd %.*s\n", len, (int)len, ret);
+ assert(len == 29);
+ assert(hwconfig_arg_cmp("key1", "subkey1=value1,subkey2=value2"));
+ assert(!strncmp(ret, "subkey1=value1,subkey2=value2", len));
+
+ ret = hwconfig_subarg("key1", "subkey1", &len);
+ printf("%zd %.*s\n", len, (int)len, ret);
+ assert(len == 6);
+ assert(hwconfig_subarg_cmp("key1", "subkey1", "value1"));
+ assert(!strncmp(ret, "value1", len));
+
+ ret = hwconfig_subarg("key1", "subkey2", &len);
+ printf("%zd %.*s\n", len, (int)len, ret);
+ assert(len == 6);
+ assert(hwconfig_subarg_cmp("key1", "subkey2", "value2"));
+ assert(!strncmp(ret, "value2", len));
+
+ ret = hwconfig_arg("key2", &len);
+ printf("%zd %.*s\n", len, (int)len, ret);
+ assert(len == 6);
+ assert(hwconfig_arg_cmp("key2", "value3"));
+ assert(!strncmp(ret, "value3", len));
+
+ assert(hwconfig("key3"));
+ assert(hwconfig_arg("key4", &len) == NULL);
+ assert(hwconfig_arg("bogus", &len) == NULL);
+
+ unenv_set("hwconfig");
+
+ assert(hwconfig(NULL) == 0);
+ assert(hwconfig("") == 0);
+ assert(hwconfig("key3") == 0);
+
+ return 0;
+}
+#endif /* HWCONFIG_TEST */
diff --git a/roms/u-boot/common/image-android-dt.c b/roms/u-boot/common/image-android-dt.c
new file mode 100644
index 000000000..a2d52df4a
--- /dev/null
+++ b/roms/u-boot/common/image-android-dt.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018 Linaro Ltd.
+ * Sam Protsenko <semen.protsenko@linaro.org>
+ */
+
+#include <image-android-dt.h>
+#include <dt_table.h>
+#include <common.h>
+#include <linux/libfdt.h>
+#include <mapmem.h>
+
+/**
+ * Check if image header is correct.
+ *
+ * @param hdr_addr Start address of DT image
+ * @return true if header is correct or false if header is incorrect
+ */
+bool android_dt_check_header(ulong hdr_addr)
+{
+ const struct dt_table_header *hdr;
+ u32 magic;
+
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ magic = fdt32_to_cpu(hdr->magic);
+ unmap_sysmem(hdr);
+
+ return magic == DT_TABLE_MAGIC;
+}
+
+/**
+ * Get the address of FDT (dtb or dtbo) in memory by its index in image.
+ *
+ * @param hdr_addr Start address of DT image
+ * @param index Index of desired FDT in image (starting from 0)
+ * @param[out] addr If not NULL, will contain address to specified FDT
+ * @param[out] size If not NULL, will contain size of specified FDT
+ *
+ * @return true on success or false on error
+ */
+bool android_dt_get_fdt_by_index(ulong hdr_addr, u32 index, ulong *addr,
+ u32 *size)
+{
+ const struct dt_table_header *hdr;
+ const struct dt_table_entry *e;
+ u32 entry_count, entries_offset, entry_size;
+ ulong e_addr;
+ u32 dt_offset, dt_size;
+
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ entry_count = fdt32_to_cpu(hdr->dt_entry_count);
+ entries_offset = fdt32_to_cpu(hdr->dt_entries_offset);
+ entry_size = fdt32_to_cpu(hdr->dt_entry_size);
+ unmap_sysmem(hdr);
+
+ if (index >= entry_count) {
+ printf("Error: index >= dt_entry_count (%u >= %u)\n", index,
+ entry_count);
+ return false;
+ }
+
+ e_addr = hdr_addr + entries_offset + index * entry_size;
+ e = map_sysmem(e_addr, sizeof(*e));
+ dt_offset = fdt32_to_cpu(e->dt_offset);
+ dt_size = fdt32_to_cpu(e->dt_size);
+ unmap_sysmem(e);
+
+ if (addr)
+ *addr = hdr_addr + dt_offset;
+ if (size)
+ *size = dt_size;
+
+ return true;
+}
+
+#if !defined(CONFIG_SPL_BUILD)
+static void android_dt_print_fdt_info(const struct fdt_header *fdt)
+{
+ u32 fdt_size;
+ int root_node_off;
+ const char *compatible;
+
+ root_node_off = fdt_path_offset(fdt, "/");
+ if (root_node_off < 0) {
+ printf("Error: Root node not found\n");
+ return;
+ }
+
+ fdt_size = fdt_totalsize(fdt);
+ compatible = fdt_getprop(fdt, root_node_off, "compatible",
+ NULL);
+
+ printf(" (FDT)size = %d\n", fdt_size);
+ printf(" (FDT)compatible = %s\n",
+ compatible ? compatible : "(unknown)");
+}
+
+/**
+ * Print information about DT image structure.
+ *
+ * @param hdr_addr Start address of DT image
+ */
+void android_dt_print_contents(ulong hdr_addr)
+{
+ const struct dt_table_header *hdr;
+ u32 entry_count, entries_offset, entry_size;
+ u32 i;
+
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ entry_count = fdt32_to_cpu(hdr->dt_entry_count);
+ entries_offset = fdt32_to_cpu(hdr->dt_entries_offset);
+ entry_size = fdt32_to_cpu(hdr->dt_entry_size);
+
+ /* Print image header info */
+ printf("dt_table_header:\n");
+ printf(" magic = %08x\n", fdt32_to_cpu(hdr->magic));
+ printf(" total_size = %d\n", fdt32_to_cpu(hdr->total_size));
+ printf(" header_size = %d\n", fdt32_to_cpu(hdr->header_size));
+ printf(" dt_entry_size = %d\n", entry_size);
+ printf(" dt_entry_count = %d\n", entry_count);
+ printf(" dt_entries_offset = %d\n", entries_offset);
+ printf(" page_size = %d\n", fdt32_to_cpu(hdr->page_size));
+ printf(" version = %d\n", fdt32_to_cpu(hdr->version));
+
+ unmap_sysmem(hdr);
+
+ /* Print image entries info */
+ for (i = 0; i < entry_count; ++i) {
+ const ulong e_addr = hdr_addr + entries_offset + i * entry_size;
+ const struct dt_table_entry *e;
+ const struct fdt_header *fdt;
+ u32 dt_offset, dt_size;
+ u32 j;
+
+ e = map_sysmem(e_addr, sizeof(*e));
+ dt_offset = fdt32_to_cpu(e->dt_offset);
+ dt_size = fdt32_to_cpu(e->dt_size);
+
+ printf("dt_table_entry[%d]:\n", i);
+ printf(" dt_size = %d\n", dt_size);
+ printf(" dt_offset = %d\n", dt_offset);
+ printf(" id = %08x\n", fdt32_to_cpu(e->id));
+ printf(" rev = %08x\n", fdt32_to_cpu(e->rev));
+ for (j = 0; j < 4; ++j) {
+ printf(" custom[%d] = %08x\n", j,
+ fdt32_to_cpu(e->custom[j]));
+ }
+
+ unmap_sysmem(e);
+
+ /* Print FDT info for this entry */
+ fdt = map_sysmem(hdr_addr + dt_offset, sizeof(*fdt));
+ android_dt_print_fdt_info(fdt);
+ unmap_sysmem(fdt);
+ }
+}
+#endif
diff --git a/roms/u-boot/common/image-android.c b/roms/u-boot/common/image-android.c
new file mode 100644
index 000000000..d07b0e0f0
--- /dev/null
+++ b/roms/u-boot/common/image-android.c
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#include <common.h>
+#include <env.h>
+#include <image.h>
+#include <image-android-dt.h>
+#include <android_image.h>
+#include <malloc.h>
+#include <errno.h>
+#include <asm/unaligned.h>
+#include <mapmem.h>
+#include <linux/libfdt.h>
+
+#define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000
+
+static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
+
+static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr)
+{
+ /*
+ * All the Android tools that generate a boot.img use this
+ * address as the default.
+ *
+ * Even though it doesn't really make a lot of sense, and it
+ * might be valid on some platforms, we treat that adress as
+ * the default value for this field, and try to execute the
+ * kernel in place in such a case.
+ *
+ * Otherwise, we will return the actual value set by the user.
+ */
+ if (hdr->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR)
+ return (ulong)hdr + hdr->page_size;
+
+ /*
+ * abootimg creates images where all load addresses are 0
+ * and we need to fix them.
+ */
+ if (hdr->kernel_addr == 0 && hdr->ramdisk_addr == 0)
+ return env_get_ulong("kernel_addr_r", 16, 0);
+
+ return hdr->kernel_addr;
+}
+
+/**
+ * android_image_get_kernel() - processes kernel part of Android boot images
+ * @hdr: Pointer to image header, which is at the start
+ * of the image.
+ * @verify: Checksum verification flag. Currently unimplemented.
+ * @os_data: Pointer to a ulong variable, will hold os data start
+ * address.
+ * @os_len: Pointer to a ulong variable, will hold os data length.
+ *
+ * This function returns the os image's start address and length. Also,
+ * it appends the kernel command line to the bootargs env variable.
+ *
+ * Return: Zero, os start address and length on success,
+ * otherwise on failure.
+ */
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+ ulong *os_data, ulong *os_len)
+{
+ u32 kernel_addr = android_image_get_kernel_addr(hdr);
+ const struct image_header *ihdr = (const struct image_header *)
+ ((uintptr_t)hdr + hdr->page_size);
+
+ /*
+ * Not all Android tools use the id field for signing the image with
+ * sha1 (or anything) so we don't check it. It is not obvious that the
+ * string is null terminated so we take care of this.
+ */
+ strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
+ andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
+ if (strlen(andr_tmp_str))
+ printf("Android's image name: %s\n", andr_tmp_str);
+
+ printf("Kernel load addr 0x%08x size %u KiB\n",
+ kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
+
+ int len = 0;
+ if (*hdr->cmdline) {
+ printf("Kernel command line: %s\n", hdr->cmdline);
+ len += strlen(hdr->cmdline);
+ }
+
+ char *bootargs = env_get("bootargs");
+ if (bootargs)
+ len += strlen(bootargs);
+
+ char *newbootargs = malloc(len + 2);
+ if (!newbootargs) {
+ puts("Error: malloc in android_image_get_kernel failed!\n");
+ return -ENOMEM;
+ }
+ *newbootargs = '\0';
+
+ if (bootargs) {
+ strcpy(newbootargs, bootargs);
+ strcat(newbootargs, " ");
+ }
+ if (*hdr->cmdline)
+ strcat(newbootargs, hdr->cmdline);
+
+ env_set("bootargs", newbootargs);
+
+ if (os_data) {
+ if (image_get_magic(ihdr) == IH_MAGIC) {
+ *os_data = image_get_data(ihdr);
+ } else {
+ *os_data = (ulong)hdr;
+ *os_data += hdr->page_size;
+ }
+ }
+ if (os_len) {
+ if (image_get_magic(ihdr) == IH_MAGIC)
+ *os_len = image_get_data_size(ihdr);
+ else
+ *os_len = hdr->kernel_size;
+ }
+ return 0;
+}
+
+int android_image_check_header(const struct andr_img_hdr *hdr)
+{
+ return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
+}
+
+ulong android_image_get_end(const struct andr_img_hdr *hdr)
+{
+ ulong end;
+
+ /*
+ * The header takes a full page, the remaining components are aligned
+ * on page boundary
+ */
+ end = (ulong)hdr;
+ end += hdr->page_size;
+ end += ALIGN(hdr->kernel_size, hdr->page_size);
+ end += ALIGN(hdr->ramdisk_size, hdr->page_size);
+ end += ALIGN(hdr->second_size, hdr->page_size);
+
+ if (hdr->header_version >= 1)
+ end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
+
+ if (hdr->header_version >= 2)
+ end += ALIGN(hdr->dtb_size, hdr->page_size);
+
+ return end;
+}
+
+ulong android_image_get_kload(const struct andr_img_hdr *hdr)
+{
+ return android_image_get_kernel_addr(hdr);
+}
+
+ulong android_image_get_kcomp(const struct andr_img_hdr *hdr)
+{
+ const void *p = (void *)((uintptr_t)hdr + hdr->page_size);
+
+ if (image_get_magic((image_header_t *)p) == IH_MAGIC)
+ return image_get_comp((image_header_t *)p);
+ else if (get_unaligned_le32(p) == LZ4F_MAGIC)
+ return IH_COMP_LZ4;
+ else
+ return IH_COMP_NONE;
+}
+
+int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
+ ulong *rd_data, ulong *rd_len)
+{
+ if (!hdr->ramdisk_size) {
+ *rd_data = *rd_len = 0;
+ return -1;
+ }
+
+ printf("RAM disk load addr 0x%08x size %u KiB\n",
+ hdr->ramdisk_addr, DIV_ROUND_UP(hdr->ramdisk_size, 1024));
+
+ *rd_data = (unsigned long)hdr;
+ *rd_data += hdr->page_size;
+ *rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
+
+ *rd_len = hdr->ramdisk_size;
+ return 0;
+}
+
+int android_image_get_second(const struct andr_img_hdr *hdr,
+ ulong *second_data, ulong *second_len)
+{
+ if (!hdr->second_size) {
+ *second_data = *second_len = 0;
+ return -1;
+ }
+
+ *second_data = (unsigned long)hdr;
+ *second_data += hdr->page_size;
+ *second_data += ALIGN(hdr->kernel_size, hdr->page_size);
+ *second_data += ALIGN(hdr->ramdisk_size, hdr->page_size);
+
+ printf("second address is 0x%lx\n",*second_data);
+
+ *second_len = hdr->second_size;
+ return 0;
+}
+
+/**
+ * android_image_get_dtbo() - Get address and size of recovery DTBO image.
+ * @hdr_addr: Boot image header address
+ * @addr: If not NULL, will contain address of recovery DTBO image
+ * @size: If not NULL, will contain size of recovery DTBO image
+ *
+ * Get the address and size of DTBO image in "Recovery DTBO" area of Android
+ * Boot Image in RAM. The format of this image is Android DTBO (see
+ * corresponding "DTB/DTBO Partitions" AOSP documentation for details). Once
+ * the address is obtained from this function, one can use 'adtimg' U-Boot
+ * command or android_dt_*() functions to extract desired DTBO blob.
+ *
+ * This DTBO (included in boot image) is only needed for non-A/B devices, and it
+ * only can be found in recovery image. On A/B devices we can always rely on
+ * "dtbo" partition. See "Including DTBO in Recovery for Non-A/B Devices" in
+ * AOSP documentation for details.
+ *
+ * Return: true on success or false on error.
+ */
+bool android_image_get_dtbo(ulong hdr_addr, ulong *addr, u32 *size)
+{
+ const struct andr_img_hdr *hdr;
+ ulong dtbo_img_addr;
+ bool ret = true;
+
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ if (android_image_check_header(hdr)) {
+ printf("Error: Boot Image header is incorrect\n");
+ ret = false;
+ goto exit;
+ }
+
+ if (hdr->header_version < 1) {
+ printf("Error: header_version must be >= 1 to get dtbo\n");
+ ret = false;
+ goto exit;
+ }
+
+ if (hdr->recovery_dtbo_size == 0) {
+ printf("Error: recovery_dtbo_size is 0\n");
+ ret = false;
+ goto exit;
+ }
+
+ /* Calculate the address of DTB area in boot image */
+ dtbo_img_addr = hdr_addr;
+ dtbo_img_addr += hdr->page_size;
+ dtbo_img_addr += ALIGN(hdr->kernel_size, hdr->page_size);
+ dtbo_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
+ dtbo_img_addr += ALIGN(hdr->second_size, hdr->page_size);
+
+ if (addr)
+ *addr = dtbo_img_addr;
+ if (size)
+ *size = hdr->recovery_dtbo_size;
+
+exit:
+ unmap_sysmem(hdr);
+ return ret;
+}
+
+/**
+ * android_image_get_dtb_img_addr() - Get the address of DTB area in boot image.
+ * @hdr_addr: Boot image header address
+ * @addr: Will contain the address of DTB area in boot image
+ *
+ * Return: true on success or false on fail.
+ */
+static bool android_image_get_dtb_img_addr(ulong hdr_addr, ulong *addr)
+{
+ const struct andr_img_hdr *hdr;
+ ulong dtb_img_addr;
+ bool ret = true;
+
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ if (android_image_check_header(hdr)) {
+ printf("Error: Boot Image header is incorrect\n");
+ ret = false;
+ goto exit;
+ }
+
+ if (hdr->header_version < 2) {
+ printf("Error: header_version must be >= 2 to get dtb\n");
+ ret = false;
+ goto exit;
+ }
+
+ if (hdr->dtb_size == 0) {
+ printf("Error: dtb_size is 0\n");
+ ret = false;
+ goto exit;
+ }
+
+ /* Calculate the address of DTB area in boot image */
+ dtb_img_addr = hdr_addr;
+ dtb_img_addr += hdr->page_size;
+ dtb_img_addr += ALIGN(hdr->kernel_size, hdr->page_size);
+ dtb_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
+ dtb_img_addr += ALIGN(hdr->second_size, hdr->page_size);
+ dtb_img_addr += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
+
+ *addr = dtb_img_addr;
+
+exit:
+ unmap_sysmem(hdr);
+ return ret;
+}
+
+/**
+ * android_image_get_dtb_by_index() - Get address and size of blob in DTB area.
+ * @hdr_addr: Boot image header address
+ * @index: Index of desired DTB in DTB area (starting from 0)
+ * @addr: If not NULL, will contain address to specified DTB
+ * @size: If not NULL, will contain size of specified DTB
+ *
+ * Get the address and size of DTB blob by its index in DTB area of Android
+ * Boot Image in RAM.
+ *
+ * Return: true on success or false on error.
+ */
+bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr,
+ u32 *size)
+{
+ const struct andr_img_hdr *hdr;
+ bool res;
+ ulong dtb_img_addr; /* address of DTB part in boot image */
+ u32 dtb_img_size; /* size of DTB payload in boot image */
+ ulong dtb_addr; /* address of DTB blob with specified index */
+ u32 i; /* index iterator */
+
+ res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr);
+ if (!res)
+ return false;
+
+ /* Check if DTB area of boot image is in DTBO format */
+ if (android_dt_check_header(dtb_img_addr)) {
+ return android_dt_get_fdt_by_index(dtb_img_addr, index, addr,
+ size);
+ }
+
+ /* Find out the address of DTB with specified index in concat blobs */
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ dtb_img_size = hdr->dtb_size;
+ unmap_sysmem(hdr);
+ i = 0;
+ dtb_addr = dtb_img_addr;
+ while (dtb_addr < dtb_img_addr + dtb_img_size) {
+ const struct fdt_header *fdt;
+ u32 dtb_size;
+
+ fdt = map_sysmem(dtb_addr, sizeof(*fdt));
+ if (fdt_check_header(fdt) != 0) {
+ unmap_sysmem(fdt);
+ printf("Error: Invalid FDT header for index %u\n", i);
+ return false;
+ }
+
+ dtb_size = fdt_totalsize(fdt);
+ unmap_sysmem(fdt);
+
+ if (i == index) {
+ if (size)
+ *size = dtb_size;
+ if (addr)
+ *addr = dtb_addr;
+ return true;
+ }
+
+ dtb_addr += dtb_size;
+ ++i;
+ }
+
+ printf("Error: Index is out of bounds (%u/%u)\n", index, i);
+ return false;
+}
+
+#if !defined(CONFIG_SPL_BUILD)
+/**
+ * android_print_contents - prints out the contents of the Android format image
+ * @hdr: pointer to the Android format image header
+ *
+ * android_print_contents() formats a multi line Android image contents
+ * description.
+ * The routine prints out Android image properties
+ *
+ * returns:
+ * no returned results
+ */
+void android_print_contents(const struct andr_img_hdr *hdr)
+{
+ const char * const p = IMAGE_INDENT_STRING;
+ /* os_version = ver << 11 | lvl */
+ u32 os_ver = hdr->os_version >> 11;
+ u32 os_lvl = hdr->os_version & ((1U << 11) - 1);
+
+ printf("%skernel size: %x\n", p, hdr->kernel_size);
+ printf("%skernel address: %x\n", p, hdr->kernel_addr);
+ printf("%sramdisk size: %x\n", p, hdr->ramdisk_size);
+ printf("%sramdisk address: %x\n", p, hdr->ramdisk_addr);
+ printf("%ssecond size: %x\n", p, hdr->second_size);
+ printf("%ssecond address: %x\n", p, hdr->second_addr);
+ printf("%stags address: %x\n", p, hdr->tags_addr);
+ printf("%spage size: %x\n", p, hdr->page_size);
+ /* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
+ * lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M) */
+ printf("%sos_version: %x (ver: %u.%u.%u, level: %u.%u)\n",
+ p, hdr->os_version,
+ (os_ver >> 7) & 0x7F, (os_ver >> 14) & 0x7F, os_ver & 0x7F,
+ (os_lvl >> 4) + 2000, os_lvl & 0x0F);
+ printf("%sname: %s\n", p, hdr->name);
+ printf("%scmdline: %s\n", p, hdr->cmdline);
+ printf("%sheader_version: %d\n", p, hdr->header_version);
+
+ if (hdr->header_version >= 1) {
+ printf("%srecovery dtbo size: %x\n", p,
+ hdr->recovery_dtbo_size);
+ printf("%srecovery dtbo offset: %llx\n", p,
+ hdr->recovery_dtbo_offset);
+ printf("%sheader size: %x\n", p,
+ hdr->header_size);
+ }
+
+ if (hdr->header_version >= 2) {
+ printf("%sdtb size: %x\n", p, hdr->dtb_size);
+ printf("%sdtb addr: %llx\n", p, hdr->dtb_addr);
+ }
+}
+
+/**
+ * android_image_print_dtb_info - Print info for one DTB blob in DTB area.
+ * @fdt: DTB header
+ * @index: Number of DTB blob in DTB area.
+ *
+ * Return: true on success or false on error.
+ */
+static bool android_image_print_dtb_info(const struct fdt_header *fdt,
+ u32 index)
+{
+ int root_node_off;
+ u32 fdt_size;
+ const char *model;
+ const char *compatible;
+
+ root_node_off = fdt_path_offset(fdt, "/");
+ if (root_node_off < 0) {
+ printf("Error: Root node not found\n");
+ return false;
+ }
+
+ fdt_size = fdt_totalsize(fdt);
+ compatible = fdt_getprop(fdt, root_node_off, "compatible",
+ NULL);
+ model = fdt_getprop(fdt, root_node_off, "model", NULL);
+
+ printf(" - DTB #%u:\n", index);
+ printf(" (DTB)size = %d\n", fdt_size);
+ printf(" (DTB)model = %s\n", model ? model : "(unknown)");
+ printf(" (DTB)compatible = %s\n",
+ compatible ? compatible : "(unknown)");
+
+ return true;
+}
+
+/**
+ * android_image_print_dtb_contents() - Print info for DTB blobs in DTB area.
+ * @hdr_addr: Boot image header address
+ *
+ * DTB payload in Android Boot Image v2+ can be in one of following formats:
+ * 1. Concatenated DTB blobs
+ * 2. Android DTBO format (see CONFIG_CMD_ADTIMG for details)
+ *
+ * This function does next:
+ * 1. Prints out the format used in DTB area
+ * 2. Iterates over all DTB blobs in DTB area and prints out the info for
+ * each blob.
+ *
+ * Return: true on success or false on error.
+ */
+bool android_image_print_dtb_contents(ulong hdr_addr)
+{
+ const struct andr_img_hdr *hdr;
+ bool res;
+ ulong dtb_img_addr; /* address of DTB part in boot image */
+ u32 dtb_img_size; /* size of DTB payload in boot image */
+ ulong dtb_addr; /* address of DTB blob with specified index */
+ u32 i; /* index iterator */
+
+ res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr);
+ if (!res)
+ return false;
+
+ /* Check if DTB area of boot image is in DTBO format */
+ if (android_dt_check_header(dtb_img_addr)) {
+ printf("## DTB area contents (DTBO format):\n");
+ android_dt_print_contents(dtb_img_addr);
+ return true;
+ }
+
+ printf("## DTB area contents (concat format):\n");
+
+ /* Iterate over concatenated DTB blobs */
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ dtb_img_size = hdr->dtb_size;
+ unmap_sysmem(hdr);
+ i = 0;
+ dtb_addr = dtb_img_addr;
+ while (dtb_addr < dtb_img_addr + dtb_img_size) {
+ const struct fdt_header *fdt;
+ u32 dtb_size;
+
+ fdt = map_sysmem(dtb_addr, sizeof(*fdt));
+ if (fdt_check_header(fdt) != 0) {
+ unmap_sysmem(fdt);
+ printf("Error: Invalid FDT header for index %u\n", i);
+ return false;
+ }
+
+ res = android_image_print_dtb_info(fdt, i);
+ if (!res) {
+ unmap_sysmem(fdt);
+ return false;
+ }
+
+ dtb_size = fdt_totalsize(fdt);
+ unmap_sysmem(fdt);
+ dtb_addr += dtb_size;
+ ++i;
+ }
+
+ return true;
+}
+#endif
diff --git a/roms/u-boot/common/image-cipher.c b/roms/u-boot/common/image-cipher.c
new file mode 100644
index 000000000..b90614893
--- /dev/null
+++ b/roms/u-boot/common/image-cipher.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019, Softathome
+ */
+
+#ifdef USE_HOSTCC
+#include "mkimage.h"
+#include <time.h>
+#else
+#include <common.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* !USE_HOSdTCC*/
+#include <image.h>
+#include <uboot_aes.h>
+#include <u-boot/aes.h>
+
+struct cipher_algo cipher_algos[] = {
+ {
+ .name = "aes128",
+ .key_len = AES128_KEY_LENGTH,
+ .iv_len = AES_BLOCK_LENGTH,
+#if IMAGE_ENABLE_ENCRYPT
+ .calculate_type = EVP_aes_128_cbc,
+#endif
+ .encrypt = image_aes_encrypt,
+ .decrypt = image_aes_decrypt,
+ .add_cipher_data = image_aes_add_cipher_data
+ },
+ {
+ .name = "aes192",
+ .key_len = AES192_KEY_LENGTH,
+ .iv_len = AES_BLOCK_LENGTH,
+#if IMAGE_ENABLE_ENCRYPT
+ .calculate_type = EVP_aes_192_cbc,
+#endif
+ .encrypt = image_aes_encrypt,
+ .decrypt = image_aes_decrypt,
+ .add_cipher_data = image_aes_add_cipher_data
+ },
+ {
+ .name = "aes256",
+ .key_len = AES256_KEY_LENGTH,
+ .iv_len = AES_BLOCK_LENGTH,
+#if IMAGE_ENABLE_ENCRYPT
+ .calculate_type = EVP_aes_256_cbc,
+#endif
+ .encrypt = image_aes_encrypt,
+ .decrypt = image_aes_decrypt,
+ .add_cipher_data = image_aes_add_cipher_data
+ }
+};
+
+struct cipher_algo *image_get_cipher_algo(const char *full_name)
+{
+ int i;
+ const char *name;
+
+ for (i = 0; i < ARRAY_SIZE(cipher_algos); i++) {
+ name = cipher_algos[i].name;
+ if (!strncmp(name, full_name, strlen(name)))
+ return &cipher_algos[i];
+ }
+
+ return NULL;
+}
+
+static int fit_image_setup_decrypt(struct image_cipher_info *info,
+ const void *fit, int image_noffset,
+ int cipher_noffset)
+{
+ const void *fdt = gd_fdt_blob();
+ const char *node_name;
+ char node_path[128];
+ int noffset;
+ char *algo_name;
+ int ret;
+
+ node_name = fit_get_name(fit, image_noffset, NULL);
+ if (!node_name) {
+ printf("Can't get node name\n");
+ return -1;
+ }
+
+ if (fit_image_cipher_get_algo(fit, cipher_noffset, &algo_name)) {
+ printf("Can't get algo name for cipher '%s' in image '%s'\n",
+ node_name, node_name);
+ return -1;
+ }
+
+ info->keyname = fdt_getprop(fit, cipher_noffset, FIT_KEY_HINT, NULL);
+ if (!info->keyname) {
+ printf("Can't get key name\n");
+ return -1;
+ }
+
+ info->iv = fdt_getprop(fit, cipher_noffset, "iv", NULL);
+ info->ivname = fdt_getprop(fit, cipher_noffset, "iv-name-hint", NULL);
+
+ if (!info->iv && !info->ivname) {
+ printf("Can't get IV or IV name\n");
+ return -1;
+ }
+
+ info->fit = fit;
+ info->node_noffset = image_noffset;
+ info->name = algo_name;
+ info->cipher = image_get_cipher_algo(algo_name);
+ if (!info->cipher) {
+ printf("Can't get cipher\n");
+ return -1;
+ }
+
+ ret = fit_image_get_data_size_unciphered(fit, image_noffset,
+ &info->size_unciphered);
+ if (ret) {
+ printf("Can't get size of unciphered data\n");
+ return -1;
+ }
+
+ /*
+ * Search the cipher node in the u-boot fdt
+ * the path should be: /cipher/key-<algo>-<key>-<iv>
+ */
+ if (info->ivname)
+ snprintf(node_path, sizeof(node_path), "/%s/key-%s-%s-%s",
+ FIT_CIPHER_NODENAME, algo_name, info->keyname, info->ivname);
+ else
+ snprintf(node_path, sizeof(node_path), "/%s/key-%s-%s",
+ FIT_CIPHER_NODENAME, algo_name, info->keyname);
+
+ noffset = fdt_path_offset(fdt, node_path);
+ if (noffset < 0) {
+ printf("Can't found cipher node offset\n");
+ return -1;
+ }
+
+ /* read key */
+ info->key = fdt_getprop(fdt, noffset, "key", NULL);
+ if (!info->key) {
+ printf("Can't get key in cipher node '%s'\n", node_path);
+ return -1;
+ }
+
+ /* read iv */
+ if (!info->iv) {
+ info->iv = fdt_getprop(fdt, noffset, "iv", NULL);
+ if (!info->iv) {
+ printf("Can't get IV in cipher node '%s'\n", node_path);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int fit_image_decrypt_data(const void *fit,
+ int image_noffset, int cipher_noffset,
+ const void *data_ciphered, size_t size_ciphered,
+ void **data_unciphered, size_t *size_unciphered)
+{
+ struct image_cipher_info info;
+ int ret;
+
+ ret = fit_image_setup_decrypt(&info, fit, image_noffset,
+ cipher_noffset);
+ if (ret < 0)
+ goto out;
+
+ ret = info.cipher->decrypt(&info, data_ciphered, size_ciphered,
+ data_unciphered, size_unciphered);
+
+ out:
+ return ret;
+}
diff --git a/roms/u-boot/common/image-fdt.c b/roms/u-boot/common/image-fdt.c
new file mode 100644
index 000000000..d50e1ba3f
--- /dev/null
+++ b/roms/u-boot/common/image-fdt.c
@@ -0,0 +1,634 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <common.h>
+#include <fdt_support.h>
+#include <fdtdec.h>
+#include <env.h>
+#include <errno.h>
+#include <image.h>
+#include <lmb.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <linux/libfdt.h>
+#include <mapmem.h>
+#include <asm/io.h>
+#include <tee/optee.h>
+
+#ifndef CONFIG_SYS_FDT_PAD
+#define CONFIG_SYS_FDT_PAD 0x3000
+#endif
+
+/* adding a ramdisk needs 0x44 bytes in version 2008.10 */
+#define FDT_RAMDISK_OVERHEAD 0x80
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void fdt_error(const char *msg)
+{
+ puts("ERROR: ");
+ puts(msg);
+ puts(" - must RESET the board to recover.\n");
+}
+
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+static const image_header_t *image_get_fdt(ulong fdt_addr)
+{
+ const image_header_t *fdt_hdr = map_sysmem(fdt_addr, 0);
+
+ image_print_contents(fdt_hdr);
+
+ puts(" Verifying Checksum ... ");
+ if (!image_check_hcrc(fdt_hdr)) {
+ fdt_error("fdt header checksum invalid");
+ return NULL;
+ }
+
+ if (!image_check_dcrc(fdt_hdr)) {
+ fdt_error("fdt checksum invalid");
+ return NULL;
+ }
+ puts("OK\n");
+
+ if (!image_check_type(fdt_hdr, IH_TYPE_FLATDT)) {
+ fdt_error("uImage is not a fdt");
+ return NULL;
+ }
+ if (image_get_comp(fdt_hdr) != IH_COMP_NONE) {
+ fdt_error("uImage is compressed");
+ return NULL;
+ }
+ if (fdt_check_header((void *)image_get_data(fdt_hdr)) != 0) {
+ fdt_error("uImage data is not a fdt");
+ return NULL;
+ }
+ return fdt_hdr;
+}
+#endif
+
+static void boot_fdt_reserve_region(struct lmb *lmb, uint64_t addr,
+ uint64_t size)
+{
+ long ret;
+
+ ret = lmb_reserve(lmb, addr, size);
+ if (ret >= 0) {
+ debug(" reserving fdt memory region: addr=%llx size=%llx\n",
+ (unsigned long long)addr, (unsigned long long)size);
+ } else {
+ puts("ERROR: reserving fdt memory region failed ");
+ printf("(addr=%llx size=%llx)\n",
+ (unsigned long long)addr, (unsigned long long)size);
+ }
+}
+
+/**
+ * boot_fdt_add_mem_rsv_regions - Mark the memreserve and reserved-memory
+ * sections as unusable
+ * @lmb: pointer to lmb handle, will be used for memory mgmt
+ * @fdt_blob: pointer to fdt blob base address
+ *
+ * Adds the and reserved-memorymemreserve regions in the dtb to the lmb block.
+ * Adding the memreserve regions prevents u-boot from using them to store the
+ * initrd or the fdt blob.
+ */
+void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob)
+{
+ uint64_t addr, size;
+ int i, total, ret;
+ int nodeoffset, subnode;
+ struct fdt_resource res;
+
+ if (fdt_check_header(fdt_blob) != 0)
+ return;
+
+ /* process memreserve sections */
+ total = fdt_num_mem_rsv(fdt_blob);
+ for (i = 0; i < total; i++) {
+ if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0)
+ continue;
+ boot_fdt_reserve_region(lmb, addr, size);
+ }
+
+ /* process reserved-memory */
+ nodeoffset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory");
+ if (nodeoffset >= 0) {
+ subnode = fdt_first_subnode(fdt_blob, nodeoffset);
+ while (subnode >= 0) {
+ /* check if this subnode has a reg property */
+ ret = fdt_get_resource(fdt_blob, subnode, "reg", 0,
+ &res);
+ if (!ret && fdtdec_get_is_enabled(fdt_blob, subnode)) {
+ addr = res.start;
+ size = res.end - res.start + 1;
+ boot_fdt_reserve_region(lmb, addr, size);
+ }
+
+ subnode = fdt_next_subnode(fdt_blob, subnode);
+ }
+ }
+}
+
+/**
+ * boot_relocate_fdt - relocate flat device tree
+ * @lmb: pointer to lmb handle, will be used for memory mgmt
+ * @of_flat_tree: pointer to a char* variable, will hold fdt start address
+ * @of_size: pointer to a ulong variable, will hold fdt length
+ *
+ * boot_relocate_fdt() allocates a region of memory within the bootmap and
+ * relocates the of_flat_tree into that region, even if the fdt is already in
+ * the bootmap. It also expands the size of the fdt by CONFIG_SYS_FDT_PAD
+ * bytes.
+ *
+ * of_flat_tree and of_size are set to final (after relocation) values
+ *
+ * returns:
+ * 0 - success
+ * 1 - failure
+ */
+int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
+{
+ void *fdt_blob = *of_flat_tree;
+ void *of_start = NULL;
+ char *fdt_high;
+ ulong of_len = 0;
+ int err;
+ int disable_relocation = 0;
+
+ /* nothing to do */
+ if (*of_size == 0)
+ return 0;
+
+ if (fdt_check_header(fdt_blob) != 0) {
+ fdt_error("image is not a fdt");
+ goto error;
+ }
+
+ /* position on a 4K boundary before the alloc_current */
+ /* Pad the FDT by a specified amount */
+ of_len = *of_size + CONFIG_SYS_FDT_PAD;
+
+ /* If fdt_high is set use it to select the relocation address */
+ fdt_high = env_get("fdt_high");
+ if (fdt_high) {
+ void *desired_addr = (void *)simple_strtoul(fdt_high, NULL, 16);
+
+ if (((ulong) desired_addr) == ~0UL) {
+ /* All ones means use fdt in place */
+ of_start = fdt_blob;
+ lmb_reserve(lmb, (ulong)of_start, of_len);
+ disable_relocation = 1;
+ } else if (desired_addr) {
+ of_start =
+ (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
+ (ulong)desired_addr);
+ if (of_start == NULL) {
+ puts("Failed using fdt_high value for Device Tree");
+ goto error;
+ }
+ } else {
+ of_start =
+ (void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
+ }
+ } else {
+ of_start =
+ (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
+ env_get_bootm_mapsize()
+ + env_get_bootm_low());
+ }
+
+ if (of_start == NULL) {
+ puts("device tree - allocation error\n");
+ goto error;
+ }
+
+ if (disable_relocation) {
+ /*
+ * We assume there is space after the existing fdt to use
+ * for padding
+ */
+ fdt_set_totalsize(of_start, of_len);
+ printf(" Using Device Tree in place at %p, end %p\n",
+ of_start, of_start + of_len - 1);
+ } else {
+ debug("## device tree at %p ... %p (len=%ld [0x%lX])\n",
+ fdt_blob, fdt_blob + *of_size - 1, of_len, of_len);
+
+ printf(" Loading Device Tree to %p, end %p ... ",
+ of_start, of_start + of_len - 1);
+
+ err = fdt_open_into(fdt_blob, of_start, of_len);
+ if (err != 0) {
+ fdt_error("fdt move failed");
+ goto error;
+ }
+ puts("OK\n");
+ }
+
+ *of_flat_tree = of_start;
+ *of_size = of_len;
+
+ if (CONFIG_IS_ENABLED(CMD_FDT))
+ set_working_fdt_addr(map_to_sysmem(*of_flat_tree));
+ return 0;
+
+error:
+ return 1;
+}
+
+/**
+ * boot_get_fdt - main fdt handling routine
+ * @argc: command argument count
+ * @argv: command argument list
+ * @arch: architecture (IH_ARCH_...)
+ * @images: pointer to the bootm images structure
+ * @of_flat_tree: pointer to a char* variable, will hold fdt start address
+ * @of_size: pointer to a ulong variable, will hold fdt length
+ *
+ * boot_get_fdt() is responsible for finding a valid flat device tree image.
+ * Curently supported are the following ramdisk sources:
+ * - multicomponent kernel/ramdisk image,
+ * - commandline provided address of decicated ramdisk image.
+ *
+ * returns:
+ * 0, if fdt image was found and valid, or skipped
+ * of_flat_tree and of_size are set to fdt start address and length if
+ * fdt image is found and valid
+ *
+ * 1, if fdt image is found but corrupted
+ * of_flat_tree and of_size are set to 0 if no fdt exists
+ */
+int boot_get_fdt(int flag, int argc, char *const argv[], uint8_t arch,
+ bootm_headers_t *images, char **of_flat_tree, ulong *of_size)
+{
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+ const image_header_t *fdt_hdr;
+ ulong load, load_end;
+ ulong image_start, image_data, image_end;
+#endif
+ ulong img_addr;
+ ulong fdt_addr;
+ char *fdt_blob = NULL;
+ void *buf;
+#if CONFIG_IS_ENABLED(FIT)
+ const char *fit_uname_config = images->fit_uname_cfg;
+ const char *fit_uname_fdt = NULL;
+ ulong default_addr;
+ int fdt_noffset;
+#endif
+ const char *select = NULL;
+
+ *of_flat_tree = NULL;
+ *of_size = 0;
+
+ img_addr = (argc == 0) ? image_load_addr :
+ simple_strtoul(argv[0], NULL, 16);
+ buf = map_sysmem(img_addr, 0);
+
+ if (argc > 2)
+ select = argv[2];
+ if (select || genimg_has_config(images)) {
+#if CONFIG_IS_ENABLED(FIT)
+ if (select) {
+ /*
+ * If the FDT blob comes from the FIT image and the
+ * FIT image address is omitted in the command line
+ * argument, try to use ramdisk or os FIT image
+ * address or default load address.
+ */
+ if (images->fit_uname_rd)
+ default_addr = (ulong)images->fit_hdr_rd;
+ else if (images->fit_uname_os)
+ default_addr = (ulong)images->fit_hdr_os;
+ else
+ default_addr = image_load_addr;
+
+ if (fit_parse_conf(select, default_addr,
+ &fdt_addr, &fit_uname_config)) {
+ debug("* fdt: config '%s' from image at 0x%08lx\n",
+ fit_uname_config, fdt_addr);
+ } else if (fit_parse_subimage(select, default_addr,
+ &fdt_addr, &fit_uname_fdt)) {
+ debug("* fdt: subimage '%s' from image at 0x%08lx\n",
+ fit_uname_fdt, fdt_addr);
+ } else
+#endif
+ {
+ fdt_addr = simple_strtoul(select, NULL, 16);
+ debug("* fdt: cmdline image address = 0x%08lx\n",
+ fdt_addr);
+ }
+#if CONFIG_IS_ENABLED(FIT)
+ } else {
+ /* use FIT configuration provided in first bootm
+ * command argument
+ */
+ fdt_addr = map_to_sysmem(images->fit_hdr_os);
+ fdt_noffset = fit_get_node_from_config(images,
+ FIT_FDT_PROP,
+ fdt_addr);
+ if (fdt_noffset == -ENOENT)
+ return 0;
+ else if (fdt_noffset < 0)
+ return 1;
+ }
+#endif
+ debug("## Checking for 'FDT'/'FDT Image' at %08lx\n",
+ fdt_addr);
+
+ /*
+ * Check if there is an FDT image at the
+ * address provided in the second bootm argument
+ * check image type, for FIT images get a FIT node.
+ */
+ buf = map_sysmem(fdt_addr, 0);
+ switch (genimg_get_format(buf)) {
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+ case IMAGE_FORMAT_LEGACY:
+ /* verify fdt_addr points to a valid image header */
+ printf("## Flattened Device Tree from Legacy Image at %08lx\n",
+ fdt_addr);
+ fdt_hdr = image_get_fdt(fdt_addr);
+ if (!fdt_hdr)
+ goto no_fdt;
+
+ /*
+ * move image data to the load address,
+ * make sure we don't overwrite initial image
+ */
+ image_start = (ulong)fdt_hdr;
+ image_data = (ulong)image_get_data(fdt_hdr);
+ image_end = image_get_image_end(fdt_hdr);
+
+ load = image_get_load(fdt_hdr);
+ load_end = load + image_get_data_size(fdt_hdr);
+
+ if (load == image_start ||
+ load == image_data) {
+ fdt_addr = load;
+ break;
+ }
+
+ if ((load < image_end) && (load_end > image_start)) {
+ fdt_error("fdt overwritten");
+ goto error;
+ }
+
+ debug(" Loading FDT from 0x%08lx to 0x%08lx\n",
+ image_data, load);
+
+ memmove((void *)load,
+ (void *)image_data,
+ image_get_data_size(fdt_hdr));
+
+ fdt_addr = load;
+ break;
+#endif
+ case IMAGE_FORMAT_FIT:
+ /*
+ * This case will catch both: new uImage format
+ * (libfdt based) and raw FDT blob (also libfdt
+ * based).
+ */
+#if CONFIG_IS_ENABLED(FIT)
+ /* check FDT blob vs FIT blob */
+ if (!fit_check_format(buf, IMAGE_SIZE_INVAL)) {
+ ulong load, len;
+
+ fdt_noffset = boot_get_fdt_fit(images,
+ fdt_addr, &fit_uname_fdt,
+ &fit_uname_config,
+ arch, &load, &len);
+
+ if (fdt_noffset < 0)
+ goto error;
+
+ images->fit_hdr_fdt = map_sysmem(fdt_addr, 0);
+ images->fit_uname_fdt = fit_uname_fdt;
+ images->fit_noffset_fdt = fdt_noffset;
+ fdt_addr = load;
+
+ break;
+ } else
+#endif
+ {
+ /*
+ * FDT blob
+ */
+ debug("* fdt: raw FDT blob\n");
+ printf("## Flattened Device Tree blob at %08lx\n",
+ (long)fdt_addr);
+ }
+ break;
+ default:
+ puts("ERROR: Did not find a cmdline Flattened Device Tree\n");
+ goto error;
+ }
+
+ printf(" Booting using the fdt blob at %#08lx\n", fdt_addr);
+ fdt_blob = map_sysmem(fdt_addr, 0);
+ } else if (images->legacy_hdr_valid &&
+ image_check_type(&images->legacy_hdr_os_copy,
+ IH_TYPE_MULTI)) {
+ ulong fdt_data, fdt_len;
+
+ /*
+ * Now check if we have a legacy multi-component image,
+ * get second entry data start address and len.
+ */
+ printf("## Flattened Device Tree from multi component Image at %08lX\n",
+ (ulong)images->legacy_hdr_os);
+
+ image_multi_getimg(images->legacy_hdr_os, 2, &fdt_data,
+ &fdt_len);
+ if (fdt_len) {
+ fdt_blob = (char *)fdt_data;
+ printf(" Booting using the fdt at 0x%p\n", fdt_blob);
+
+ if (fdt_check_header(fdt_blob) != 0) {
+ fdt_error("image is not a fdt");
+ goto error;
+ }
+
+ if (fdt_totalsize(fdt_blob) != fdt_len) {
+ fdt_error("fdt size != image size");
+ goto error;
+ }
+ } else {
+ debug("## No Flattened Device Tree\n");
+ goto no_fdt;
+ }
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ } else if (genimg_get_format(buf) == IMAGE_FORMAT_ANDROID) {
+ struct andr_img_hdr *hdr = buf;
+ ulong fdt_data, fdt_len;
+ u32 fdt_size, dtb_idx;
+ /*
+ * Firstly check if this android boot image has dtb field.
+ */
+ dtb_idx = (u32)env_get_ulong("adtb_idx", 10, 0);
+ if (android_image_get_dtb_by_index((ulong)hdr, dtb_idx, &fdt_addr, &fdt_size)) {
+ fdt_blob = (char *)map_sysmem(fdt_addr, 0);
+ if (fdt_check_header(fdt_blob))
+ goto no_fdt;
+
+ debug("## Using FDT in Android image dtb area with idx %u\n", dtb_idx);
+ } else if (!android_image_get_second(hdr, &fdt_data, &fdt_len) &&
+ !fdt_check_header((char *)fdt_data)) {
+ fdt_blob = (char *)fdt_data;
+ if (fdt_totalsize(fdt_blob) != fdt_len)
+ goto error;
+
+ debug("## Using FDT in Android image second area\n");
+ } else {
+ fdt_addr = env_get_hex("fdtaddr", 0);
+ if (!fdt_addr)
+ goto no_fdt;
+
+ fdt_blob = map_sysmem(fdt_addr, 0);
+ if (fdt_check_header(fdt_blob))
+ goto no_fdt;
+
+ debug("## Using FDT at ${fdtaddr}=Ox%lx\n", fdt_addr);
+ }
+#endif
+ } else {
+ debug("## No Flattened Device Tree\n");
+ goto no_fdt;
+ }
+
+ *of_flat_tree = fdt_blob;
+ *of_size = fdt_totalsize(fdt_blob);
+ debug(" of_flat_tree at 0x%08lx size 0x%08lx\n",
+ (ulong)*of_flat_tree, *of_size);
+
+ return 0;
+
+no_fdt:
+ debug("Continuing to boot without FDT\n");
+ return 0;
+error:
+ return 1;
+}
+
+/*
+ * Verify the device tree.
+ *
+ * This function is called after all device tree fix-ups have been enacted,
+ * so that the final device tree can be verified. The definition of "verified"
+ * is up to the specific implementation. However, it generally means that the
+ * addresses of some of the devices in the device tree are compared with the
+ * actual addresses at which U-Boot has placed them.
+ *
+ * Returns 1 on success, 0 on failure. If 0 is returned, U-Boot will halt the
+ * boot process.
+ */
+__weak int ft_verify_fdt(void *fdt)
+{
+ return 1;
+}
+
+__weak int arch_fixup_fdt(void *blob)
+{
+ return 0;
+}
+
+int image_setup_libfdt(bootm_headers_t *images, void *blob,
+ int of_size, struct lmb *lmb)
+{
+ ulong *initrd_start = &images->initrd_start;
+ ulong *initrd_end = &images->initrd_end;
+ int ret = -EPERM;
+ int fdt_ret;
+
+ if (fdt_root(blob) < 0) {
+ printf("ERROR: root node setup failed\n");
+ goto err;
+ }
+ if (fdt_chosen(blob) < 0) {
+ printf("ERROR: /chosen node create failed\n");
+ goto err;
+ }
+ if (arch_fixup_fdt(blob) < 0) {
+ printf("ERROR: arch-specific fdt fixup failed\n");
+ goto err;
+ }
+
+ fdt_ret = optee_copy_fdt_nodes(blob);
+ if (fdt_ret) {
+ printf("ERROR: transfer of optee nodes to new fdt failed: %s\n",
+ fdt_strerror(fdt_ret));
+ goto err;
+ }
+
+ /* Update ethernet nodes */
+ fdt_fixup_ethernet(blob);
+#if CONFIG_IS_ENABLED(CMD_PSTORE)
+ /* Append PStore configuration */
+ fdt_fixup_pstore(blob);
+#endif
+ if (IMAGE_OF_BOARD_SETUP) {
+ const char *skip_board_fixup;
+
+ skip_board_fixup = env_get("skip_board_fixup");
+ if (skip_board_fixup && ((int)simple_strtol(skip_board_fixup, NULL, 10) == 1)) {
+ printf("skip board fdt fixup\n");
+ } else {
+ fdt_ret = ft_board_setup(blob, gd->bd);
+ if (fdt_ret) {
+ printf("ERROR: board-specific fdt fixup failed: %s\n",
+ fdt_strerror(fdt_ret));
+ goto err;
+ }
+ }
+ }
+ if (IMAGE_OF_SYSTEM_SETUP) {
+ fdt_ret = ft_system_setup(blob, gd->bd);
+ if (fdt_ret) {
+ printf("ERROR: system-specific fdt fixup failed: %s\n",
+ fdt_strerror(fdt_ret));
+ goto err;
+ }
+ }
+
+ /* Delete the old LMB reservation */
+ if (lmb)
+ lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob,
+ (phys_size_t)fdt_totalsize(blob));
+
+ ret = fdt_shrink_to_minimum(blob, 0);
+ if (ret < 0)
+ goto err;
+ of_size = ret;
+
+ if (*initrd_start && *initrd_end) {
+ of_size += FDT_RAMDISK_OVERHEAD;
+ fdt_set_totalsize(blob, of_size);
+ }
+ /* Create a new LMB reservation */
+ if (lmb)
+ lmb_reserve(lmb, (ulong)blob, of_size);
+
+ fdt_initrd(blob, *initrd_start, *initrd_end);
+ if (!ft_verify_fdt(blob))
+ goto err;
+
+#if defined(CONFIG_SOC_KEYSTONE)
+ if (IMAGE_OF_BOARD_SETUP)
+ ft_board_setup_ex(blob, gd->bd);
+#endif
+
+ return 0;
+err:
+ printf(" - must RESET the board to recover.\n\n");
+
+ return ret;
+}
diff --git a/roms/u-boot/common/image-fit-sig.c b/roms/u-boot/common/image-fit-sig.c
new file mode 100644
index 000000000..55ddf1879
--- /dev/null
+++ b/roms/u-boot/common/image-fit-sig.c
@@ -0,0 +1,483 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013, Google Inc.
+ */
+
+#ifdef USE_HOSTCC
+#include "mkimage.h"
+#include <time.h>
+#else
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* !USE_HOSTCC*/
+#include <fdt_region.h>
+#include <image.h>
+#include <u-boot/rsa.h>
+#include <u-boot/hash-checksum.h>
+
+#define IMAGE_MAX_HASHED_NODES 100
+
+/**
+ * fit_region_make_list() - Make a list of image regions
+ *
+ * Given a list of fdt_regions, create a list of image_regions. This is a
+ * simple conversion routine since the FDT and image code use different
+ * structures.
+ *
+ * @fit: FIT image
+ * @fdt_regions: Pointer to FDT regions
+ * @count: Number of FDT regions
+ * @region: Pointer to image regions, which must hold @count records. If
+ * region is NULL, then (except for an SPL build) the array will be
+ * allocated.
+ * @return: Pointer to image regions
+ */
+struct image_region *fit_region_make_list(const void *fit,
+ struct fdt_region *fdt_regions,
+ int count,
+ struct image_region *region)
+{
+ int i;
+
+ debug("Hash regions:\n");
+ debug("%10s %10s\n", "Offset", "Size");
+
+ /*
+ * Use malloc() except in SPL (to save code size). In SPL the caller
+ * must allocate the array.
+ */
+#ifndef CONFIG_SPL_BUILD
+ if (!region)
+ region = calloc(sizeof(*region), count);
+#endif
+ if (!region)
+ return NULL;
+ for (i = 0; i < count; i++) {
+ debug("%10x %10x\n", fdt_regions[i].offset,
+ fdt_regions[i].size);
+ region[i].data = fit + fdt_regions[i].offset;
+ region[i].size = fdt_regions[i].size;
+ }
+
+ return region;
+}
+
+static int fit_image_setup_verify(struct image_sign_info *info,
+ const void *fit, int noffset,
+ int required_keynode, char **err_msgp)
+{
+ char *algo_name;
+ const char *padding_name;
+
+ if (fdt_totalsize(fit) > CONFIG_FIT_SIGNATURE_MAX_SIZE) {
+ *err_msgp = "Total size too large";
+ return 1;
+ }
+
+ if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
+ *err_msgp = "Can't get hash algo property";
+ return -1;
+ }
+
+ padding_name = fdt_getprop(fit, noffset, "padding", NULL);
+ if (!padding_name)
+ padding_name = RSA_DEFAULT_PADDING_NAME;
+
+ memset(info, '\0', sizeof(*info));
+ info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
+ info->fit = (void *)fit;
+ info->node_offset = noffset;
+ info->name = algo_name;
+ info->checksum = image_get_checksum_algo(algo_name);
+ info->crypto = image_get_crypto_algo(algo_name);
+ info->padding = image_get_padding_algo(padding_name);
+ info->fdt_blob = gd_fdt_blob();
+ info->required_keynode = required_keynode;
+ printf("%s:%s", algo_name, info->keyname);
+
+ if (!info->checksum || !info->crypto || !info->padding) {
+ *err_msgp = "Unknown signature algorithm";
+ return -1;
+ }
+
+ return 0;
+}
+
+int fit_image_check_sig(const void *fit, int noffset, const void *data,
+ size_t size, int required_keynode, char **err_msgp)
+{
+ struct image_sign_info info;
+ struct image_region region;
+ uint8_t *fit_value;
+ int fit_value_len;
+
+ *err_msgp = NULL;
+ if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
+ err_msgp))
+ return -1;
+
+ if (fit_image_hash_get_value(fit, noffset, &fit_value,
+ &fit_value_len)) {
+ *err_msgp = "Can't get hash value property";
+ return -1;
+ }
+
+ region.data = data;
+ region.size = size;
+
+ if (info.crypto->verify(&info, &region, 1, fit_value, fit_value_len)) {
+ *err_msgp = "Verification failed";
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fit_image_verify_sig(const void *fit, int image_noffset,
+ const char *data, size_t size,
+ const void *sig_blob, int sig_offset)
+{
+ int noffset;
+ char *err_msg = "";
+ int verified = 0;
+ int ret;
+
+ /* Process all hash subnodes of the component image node */
+ fdt_for_each_subnode(noffset, fit, image_noffset) {
+ const char *name = fit_get_name(fit, noffset, NULL);
+
+ /*
+ * We don't support this since libfdt considers names with the
+ * name root but different @ suffix to be equal
+ */
+ if (strchr(name, '@')) {
+ err_msg = "Node name contains @";
+ goto error;
+ }
+ if (!strncmp(name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_image_check_sig(fit, noffset, data,
+ size, -1, &err_msg);
+ if (ret) {
+ puts("- ");
+ } else {
+ puts("+ ");
+ verified = 1;
+ break;
+ }
+ }
+ }
+
+ if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
+ err_msg = "Corrupted or truncated tree";
+ goto error;
+ }
+
+ return verified ? 0 : -EPERM;
+
+error:
+ printf(" error!\n%s for '%s' hash node in '%s' image node\n",
+ err_msg, fit_get_name(fit, noffset, NULL),
+ fit_get_name(fit, image_noffset, NULL));
+ return -1;
+}
+
+int fit_image_verify_required_sigs(const void *fit, int image_noffset,
+ const char *data, size_t size,
+ const void *sig_blob, int *no_sigsp)
+{
+ int verify_count = 0;
+ int noffset;
+ int sig_node;
+
+ /* Work out what we need to verify */
+ *no_sigsp = 1;
+ sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
+ if (sig_node < 0) {
+ debug("%s: No signature node found: %s\n", __func__,
+ fdt_strerror(sig_node));
+ return 0;
+ }
+
+ fdt_for_each_subnode(noffset, sig_blob, sig_node) {
+ const char *required;
+ int ret;
+
+ required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
+ NULL);
+ if (!required || strcmp(required, "image"))
+ continue;
+ ret = fit_image_verify_sig(fit, image_noffset, data, size,
+ sig_blob, noffset);
+ if (ret) {
+ printf("Failed to verify required signature '%s'\n",
+ fit_get_name(sig_blob, noffset, NULL));
+ return ret;
+ }
+ verify_count++;
+ }
+
+ if (verify_count)
+ *no_sigsp = 0;
+
+ return 0;
+}
+
+/**
+ * fit_config_check_sig() - Check the signature of a config
+ *
+ * @fit: FIT to check
+ * @noffset: Offset of configuration node (e.g. /configurations/conf-1)
+ * @required_keynode: Offset in the control FDT of the required key node,
+ * if any. If this is given, then the configuration wil not
+ * pass verification unless that key is used. If this is
+ * -1 then any signature will do.
+ * @conf_noffset: Offset of the configuration subnode being checked (e.g.
+ * /configurations/conf-1/kernel)
+ * @err_msgp: In the event of an error, this will be pointed to a
+ * help error string to display to the user.
+ * @return 0 if all verified ok, <0 on error
+ */
+static int fit_config_check_sig(const void *fit, int noffset,
+ int required_keynode, int conf_noffset,
+ char **err_msgp)
+{
+ char * const exc_prop[] = {"data", "data-size", "data-position"};
+ const char *prop, *end, *name;
+ struct image_sign_info info;
+ const uint32_t *strings;
+ const char *config_name;
+ uint8_t *fit_value;
+ int fit_value_len;
+ bool found_config;
+ int max_regions;
+ int i, prop_len;
+ char path[200];
+ int count;
+
+ config_name = fit_get_name(fit, conf_noffset, NULL);
+ debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(),
+ fit_get_name(fit, noffset, NULL),
+ fit_get_name(gd_fdt_blob(), required_keynode, NULL));
+ *err_msgp = NULL;
+ if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
+ err_msgp))
+ return -1;
+
+ if (fit_image_hash_get_value(fit, noffset, &fit_value,
+ &fit_value_len)) {
+ *err_msgp = "Can't get hash value property";
+ return -1;
+ }
+
+ /* Count the number of strings in the property */
+ prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len);
+ end = prop ? prop + prop_len : prop;
+ for (name = prop, count = 0; name < end; name++)
+ if (!*name)
+ count++;
+ if (!count) {
+ *err_msgp = "Can't get hashed-nodes property";
+ return -1;
+ }
+
+ if (prop && prop_len > 0 && prop[prop_len - 1] != '\0') {
+ *err_msgp = "hashed-nodes property must be null-terminated";
+ return -1;
+ }
+
+ /* Add a sanity check here since we are using the stack */
+ if (count > IMAGE_MAX_HASHED_NODES) {
+ *err_msgp = "Number of hashed nodes exceeds maximum";
+ return -1;
+ }
+
+ /* Create a list of node names from those strings */
+ char *node_inc[count];
+
+ debug("Hash nodes (%d):\n", count);
+ found_config = false;
+ for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) {
+ debug(" '%s'\n", name);
+ node_inc[i] = (char *)name;
+ if (!strncmp(FIT_CONFS_PATH, name, strlen(FIT_CONFS_PATH)) &&
+ name[sizeof(FIT_CONFS_PATH) - 1] == '/' &&
+ !strcmp(name + sizeof(FIT_CONFS_PATH), config_name)) {
+ debug(" (found config node %s)", config_name);
+ found_config = true;
+ }
+ }
+ if (!found_config) {
+ *err_msgp = "Selected config not in hashed nodes";
+ return -1;
+ }
+
+ /*
+ * Each node can generate one region for each sub-node. Allow for
+ * 7 sub-nodes (hash-1, signature-1, etc.) and some extra.
+ */
+ max_regions = 20 + count * 7;
+ struct fdt_region fdt_regions[max_regions];
+
+ /* Get a list of regions to hash */
+ count = fdt_find_regions(fit, node_inc, count,
+ exc_prop, ARRAY_SIZE(exc_prop),
+ fdt_regions, max_regions - 1,
+ path, sizeof(path), 0);
+ if (count < 0) {
+ *err_msgp = "Failed to hash configuration";
+ return -1;
+ }
+ if (count == 0) {
+ *err_msgp = "No data to hash";
+ return -1;
+ }
+ if (count >= max_regions - 1) {
+ *err_msgp = "Too many hash regions";
+ return -1;
+ }
+
+ /* Add the strings */
+ strings = fdt_getprop(fit, noffset, "hashed-strings", NULL);
+ if (strings) {
+ /*
+ * The strings region offset must be a static 0x0.
+ * This is set in tool/image-host.c
+ */
+ fdt_regions[count].offset = fdt_off_dt_strings(fit);
+ fdt_regions[count].size = fdt32_to_cpu(strings[1]);
+ count++;
+ }
+
+ /* Allocate the region list on the stack */
+ struct image_region region[count];
+
+ fit_region_make_list(fit, fdt_regions, count, region);
+ if (info.crypto->verify(&info, region, count, fit_value,
+ fit_value_len)) {
+ *err_msgp = "Verification failed";
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fit_config_verify_sig(const void *fit, int conf_noffset,
+ const void *sig_blob, int sig_offset)
+{
+ int noffset;
+ char *err_msg = "No 'signature' subnode found";
+ int verified = 0;
+ int ret;
+
+ /* Process all hash subnodes of the component conf node */
+ fdt_for_each_subnode(noffset, fit, conf_noffset) {
+ const char *name = fit_get_name(fit, noffset, NULL);
+
+ if (!strncmp(name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_config_check_sig(fit, noffset, sig_offset,
+ conf_noffset, &err_msg);
+ if (ret) {
+ puts("- ");
+ } else {
+ puts("+ ");
+ verified = 1;
+ break;
+ }
+ }
+ }
+
+ if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
+ err_msg = "Corrupted or truncated tree";
+ goto error;
+ }
+
+ if (verified)
+ return 0;
+
+error:
+ printf(" error!\n%s for '%s' hash node in '%s' config node\n",
+ err_msg, fit_get_name(fit, noffset, NULL),
+ fit_get_name(fit, conf_noffset, NULL));
+ return -EPERM;
+}
+
+static int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
+ const void *sig_blob)
+{
+ const char *name = fit_get_name(fit, conf_noffset, NULL);
+ int noffset;
+ int sig_node;
+ int verified = 0;
+ int reqd_sigs = 0;
+ bool reqd_policy_all = true;
+ const char *reqd_mode;
+
+ /*
+ * We don't support this since libfdt considers names with the
+ * name root but different @ suffix to be equal
+ */
+ if (strchr(name, '@')) {
+ printf("Configuration node '%s' contains '@'\n", name);
+ return -EPERM;
+ }
+
+ /* Work out what we need to verify */
+ sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
+ if (sig_node < 0) {
+ debug("%s: No signature node found: %s\n", __func__,
+ fdt_strerror(sig_node));
+ return 0;
+ }
+
+ /* Get required-mode policy property from DTB */
+ reqd_mode = fdt_getprop(sig_blob, sig_node, "required-mode", NULL);
+ if (reqd_mode && !strcmp(reqd_mode, "any"))
+ reqd_policy_all = false;
+
+ debug("%s: required-mode policy set to '%s'\n", __func__,
+ reqd_policy_all ? "all" : "any");
+
+ fdt_for_each_subnode(noffset, sig_blob, sig_node) {
+ const char *required;
+ int ret;
+
+ required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
+ NULL);
+ if (!required || strcmp(required, "conf"))
+ continue;
+
+ reqd_sigs++;
+
+ ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
+ noffset);
+ if (ret) {
+ if (reqd_policy_all) {
+ printf("Failed to verify required signature '%s'\n",
+ fit_get_name(sig_blob, noffset, NULL));
+ return ret;
+ }
+ } else {
+ verified++;
+ if (!reqd_policy_all)
+ break;
+ }
+ }
+
+ if (reqd_sigs && !verified) {
+ printf("Failed to verify 'any' of the required signature(s)\n");
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+int fit_config_verify(const void *fit, int conf_noffset)
+{
+ return fit_config_verify_required_sigs(fit, conf_noffset,
+ gd_fdt_blob());
+}
diff --git a/roms/u-boot/common/image-fit.c b/roms/u-boot/common/image-fit.c
new file mode 100644
index 000000000..e614643fe
--- /dev/null
+++ b/roms/u-boot/common/image-fit.c
@@ -0,0 +1,2407 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#define LOG_CATEGORY LOGC_BOOT
+
+#ifdef USE_HOSTCC
+#include "mkimage.h"
+#include <time.h>
+#include <linux/libfdt.h>
+#include <u-boot/crc.h>
+#else
+#include <linux/compiler.h>
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <mapmem.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* !USE_HOSTCC*/
+
+#include <bootm.h>
+#include <image.h>
+#include <bootstage.h>
+#include <linux/kconfig.h>
+#include <u-boot/crc.h>
+#include <u-boot/md5.h>
+#include <u-boot/sha1.h>
+#include <u-boot/sha256.h>
+#include <u-boot/sha512.h>
+
+/*****************************************************************************/
+/* New uImage format routines */
+/*****************************************************************************/
+#ifndef USE_HOSTCC
+static int fit_parse_spec(const char *spec, char sepc, ulong addr_curr,
+ ulong *addr, const char **name)
+{
+ const char *sep;
+
+ *addr = addr_curr;
+ *name = NULL;
+
+ sep = strchr(spec, sepc);
+ if (sep) {
+ if (sep - spec > 0)
+ *addr = simple_strtoul(spec, NULL, 16);
+
+ *name = sep + 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_parse_conf - parse FIT configuration spec
+ * @spec: input string, containing configuration spec
+ * @add_curr: current image address (to be used as a possible default)
+ * @addr: pointer to a ulong variable, will hold FIT image address of a given
+ * configuration
+ * @conf_name double pointer to a char, will hold pointer to a configuration
+ * unit name
+ *
+ * fit_parse_conf() expects configuration spec in the form of [<addr>]#<conf>,
+ * where <addr> is a FIT image address that contains configuration
+ * with a <conf> unit name.
+ *
+ * Address part is optional, and if omitted default add_curr will
+ * be used instead.
+ *
+ * returns:
+ * 1 if spec is a valid configuration string,
+ * addr and conf_name are set accordingly
+ * 0 otherwise
+ */
+int fit_parse_conf(const char *spec, ulong addr_curr,
+ ulong *addr, const char **conf_name)
+{
+ return fit_parse_spec(spec, '#', addr_curr, addr, conf_name);
+}
+
+/**
+ * fit_parse_subimage - parse FIT subimage spec
+ * @spec: input string, containing subimage spec
+ * @add_curr: current image address (to be used as a possible default)
+ * @addr: pointer to a ulong variable, will hold FIT image address of a given
+ * subimage
+ * @image_name: double pointer to a char, will hold pointer to a subimage name
+ *
+ * fit_parse_subimage() expects subimage spec in the form of
+ * [<addr>]:<subimage>, where <addr> is a FIT image address that contains
+ * subimage with a <subimg> unit name.
+ *
+ * Address part is optional, and if omitted default add_curr will
+ * be used instead.
+ *
+ * returns:
+ * 1 if spec is a valid subimage string,
+ * addr and image_name are set accordingly
+ * 0 otherwise
+ */
+int fit_parse_subimage(const char *spec, ulong addr_curr,
+ ulong *addr, const char **image_name)
+{
+ return fit_parse_spec(spec, ':', addr_curr, addr, image_name);
+}
+#endif /* !USE_HOSTCC */
+
+#ifdef USE_HOSTCC
+/* Host tools use these implementations for Cipher and Signature support */
+static void *host_blob;
+
+void image_set_host_blob(void *blob)
+{
+ host_blob = blob;
+}
+
+void *image_get_host_blob(void)
+{
+ return host_blob;
+}
+#endif /* USE_HOSTCC */
+
+static void fit_get_debug(const void *fit, int noffset,
+ char *prop_name, int err)
+{
+ debug("Can't get '%s' property from FIT 0x%08lx, node: offset %d, name %s (%s)\n",
+ prop_name, (ulong)fit, noffset, fit_get_name(fit, noffset, NULL),
+ fdt_strerror(err));
+}
+
+/**
+ * fit_get_subimage_count - get component (sub-image) count
+ * @fit: pointer to the FIT format image header
+ * @images_noffset: offset of images node
+ *
+ * returns:
+ * number of image components
+ */
+int fit_get_subimage_count(const void *fit, int images_noffset)
+{
+ int noffset;
+ int ndepth;
+ int count = 0;
+
+ /* Process its subnodes, print out component images details */
+ for (ndepth = 0, count = 0,
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+#if CONFIG_IS_ENABLED(FIT_PRINT) || CONFIG_IS_ENABLED(SPL_FIT_PRINT)
+/**
+ * fit_image_print_data() - prints out the hash node details
+ * @fit: pointer to the FIT format image header
+ * @noffset: offset of the hash node
+ * @p: pointer to prefix string
+ * @type: Type of information to print ("hash" or "sign")
+ *
+ * fit_image_print_data() lists properties for the processed hash node
+ *
+ * This function avoid using puts() since it prints a newline on the host
+ * but does not in U-Boot.
+ *
+ * returns:
+ * no returned results
+ */
+static void fit_image_print_data(const void *fit, int noffset, const char *p,
+ const char *type)
+{
+ const char *keyname;
+ uint8_t *value;
+ int value_len;
+ char *algo;
+ const char *padding;
+ bool required;
+ int ret, i;
+
+ debug("%s %s node: '%s'\n", p, type,
+ fit_get_name(fit, noffset, NULL));
+ printf("%s %s algo: ", p, type);
+ if (fit_image_hash_get_algo(fit, noffset, &algo)) {
+ printf("invalid/unsupported\n");
+ return;
+ }
+ printf("%s", algo);
+ keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
+ required = fdt_getprop(fit, noffset, FIT_KEY_REQUIRED, NULL) != NULL;
+ if (keyname)
+ printf(":%s", keyname);
+ if (required)
+ printf(" (required)");
+ printf("\n");
+
+ padding = fdt_getprop(fit, noffset, "padding", NULL);
+ if (padding)
+ printf("%s %s padding: %s\n", p, type, padding);
+
+ ret = fit_image_hash_get_value(fit, noffset, &value,
+ &value_len);
+ printf("%s %s value: ", p, type);
+ if (ret) {
+ printf("unavailable\n");
+ } else {
+ for (i = 0; i < value_len; i++)
+ printf("%02x", value[i]);
+ printf("\n");
+ }
+
+ debug("%s %s len: %d\n", p, type, value_len);
+
+ /* Signatures have a time stamp */
+ if (IMAGE_ENABLE_TIMESTAMP && keyname) {
+ time_t timestamp;
+
+ printf("%s Timestamp: ", p);
+ if (fit_get_timestamp(fit, noffset, &timestamp))
+ printf("unavailable\n");
+ else
+ genimg_print_time(timestamp);
+ }
+}
+
+/**
+ * fit_image_print_verification_data() - prints out the hash/signature details
+ * @fit: pointer to the FIT format image header
+ * @noffset: offset of the hash or signature node
+ * @p: pointer to prefix string
+ *
+ * This lists properties for the processed hash node
+ *
+ * returns:
+ * no returned results
+ */
+static void fit_image_print_verification_data(const void *fit, int noffset,
+ const char *p)
+{
+ const char *name;
+
+ /*
+ * Check subnode name, must be equal to "hash" or "signature".
+ * Multiple hash/signature nodes require unique unit node
+ * names, e.g. hash-1, hash-2, signature-1, signature-2, etc.
+ */
+ name = fit_get_name(fit, noffset, NULL);
+ if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) {
+ fit_image_print_data(fit, noffset, p, "Hash");
+ } else if (!strncmp(name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ fit_image_print_data(fit, noffset, p, "Sign");
+ }
+}
+
+/**
+ * fit_conf_print - prints out the FIT configuration details
+ * @fit: pointer to the FIT format image header
+ * @noffset: offset of the configuration node
+ * @p: pointer to prefix string
+ *
+ * fit_conf_print() lists all mandatory properties for the processed
+ * configuration node.
+ *
+ * returns:
+ * no returned results
+ */
+static void fit_conf_print(const void *fit, int noffset, const char *p)
+{
+ char *desc;
+ const char *uname;
+ int ret;
+ int fdt_index, loadables_index;
+ int ndepth;
+
+ /* Mandatory properties */
+ ret = fit_get_desc(fit, noffset, &desc);
+ printf("%s Description: ", p);
+ if (ret)
+ printf("unavailable\n");
+ else
+ printf("%s\n", desc);
+
+ uname = fdt_getprop(fit, noffset, FIT_KERNEL_PROP, NULL);
+ printf("%s Kernel: ", p);
+ if (!uname)
+ printf("unavailable\n");
+ else
+ printf("%s\n", uname);
+
+ /* Optional properties */
+ uname = fdt_getprop(fit, noffset, FIT_RAMDISK_PROP, NULL);
+ if (uname)
+ printf("%s Init Ramdisk: %s\n", p, uname);
+
+ uname = fdt_getprop(fit, noffset, FIT_FIRMWARE_PROP, NULL);
+ if (uname)
+ printf("%s Firmware: %s\n", p, uname);
+
+ for (fdt_index = 0;
+ uname = fdt_stringlist_get(fit, noffset, FIT_FDT_PROP,
+ fdt_index, NULL), uname;
+ fdt_index++) {
+ if (fdt_index == 0)
+ printf("%s FDT: ", p);
+ else
+ printf("%s ", p);
+ printf("%s\n", uname);
+ }
+
+ uname = fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL);
+ if (uname)
+ printf("%s FPGA: %s\n", p, uname);
+
+ /* Print out all of the specified loadables */
+ for (loadables_index = 0;
+ uname = fdt_stringlist_get(fit, noffset, FIT_LOADABLE_PROP,
+ loadables_index, NULL), uname;
+ loadables_index++) {
+ if (loadables_index == 0) {
+ printf("%s Loadables: ", p);
+ } else {
+ printf("%s ", p);
+ }
+ printf("%s\n", uname);
+ }
+
+ /* Process all hash subnodes of the component configuration node */
+ for (ndepth = 0, noffset = fdt_next_node(fit, noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /* Direct child node of the component configuration node */
+ fit_image_print_verification_data(fit, noffset, p);
+ }
+ }
+}
+
+/**
+ * fit_print_contents - prints out the contents of the FIT format image
+ * @fit: pointer to the FIT format image header
+ * @p: pointer to prefix string
+ *
+ * fit_print_contents() formats a multi line FIT image contents description.
+ * The routine prints out FIT image properties (root node level) followed by
+ * the details of each component image.
+ *
+ * returns:
+ * no returned results
+ */
+void fit_print_contents(const void *fit)
+{
+ char *desc;
+ char *uname;
+ int images_noffset;
+ int confs_noffset;
+ int noffset;
+ int ndepth;
+ int count = 0;
+ int ret;
+ const char *p;
+ time_t timestamp;
+
+ /* Indent string is defined in header image.h */
+ p = IMAGE_INDENT_STRING;
+
+ /* Root node properties */
+ ret = fit_get_desc(fit, 0, &desc);
+ printf("%sFIT description: ", p);
+ if (ret)
+ printf("unavailable\n");
+ else
+ printf("%s\n", desc);
+
+ if (IMAGE_ENABLE_TIMESTAMP) {
+ ret = fit_get_timestamp(fit, 0, &timestamp);
+ printf("%sCreated: ", p);
+ if (ret)
+ printf("unavailable\n");
+ else
+ genimg_print_time(timestamp);
+ }
+
+ /* Find images parent node offset */
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ printf("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror(images_noffset));
+ return;
+ }
+
+ /* Process its subnodes, print out component images details */
+ for (ndepth = 0, count = 0,
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /*
+ * Direct child node of the images parent node,
+ * i.e. component image node.
+ */
+ printf("%s Image %u (%s)\n", p, count++,
+ fit_get_name(fit, noffset, NULL));
+
+ fit_image_print(fit, noffset, p);
+ }
+ }
+
+ /* Find configurations parent node offset */
+ confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
+ if (confs_noffset < 0) {
+ debug("Can't get configurations parent node '%s' (%s)\n",
+ FIT_CONFS_PATH, fdt_strerror(confs_noffset));
+ return;
+ }
+
+ /* get default configuration unit name from default property */
+ uname = (char *)fdt_getprop(fit, noffset, FIT_DEFAULT_PROP, NULL);
+ if (uname)
+ printf("%s Default Configuration: '%s'\n", p, uname);
+
+ /* Process its subnodes, print out configurations details */
+ for (ndepth = 0, count = 0,
+ noffset = fdt_next_node(fit, confs_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /*
+ * Direct child node of the configurations parent node,
+ * i.e. configuration node.
+ */
+ printf("%s Configuration %u (%s)\n", p, count++,
+ fit_get_name(fit, noffset, NULL));
+
+ fit_conf_print(fit, noffset, p);
+ }
+ }
+}
+
+/**
+ * fit_image_print - prints out the FIT component image details
+ * @fit: pointer to the FIT format image header
+ * @image_noffset: offset of the component image node
+ * @p: pointer to prefix string
+ *
+ * fit_image_print() lists all mandatory properties for the processed component
+ * image. If present, hash nodes are printed out as well. Load
+ * address for images of type firmware is also printed out. Since the load
+ * address is not mandatory for firmware images, it will be output as
+ * "unavailable" when not present.
+ *
+ * returns:
+ * no returned results
+ */
+void fit_image_print(const void *fit, int image_noffset, const char *p)
+{
+ char *desc;
+ uint8_t type, arch, os, comp;
+ size_t size;
+ ulong load, entry;
+ const void *data;
+ int noffset;
+ int ndepth;
+ int ret;
+
+ /* Mandatory properties */
+ ret = fit_get_desc(fit, image_noffset, &desc);
+ printf("%s Description: ", p);
+ if (ret)
+ printf("unavailable\n");
+ else
+ printf("%s\n", desc);
+
+ if (IMAGE_ENABLE_TIMESTAMP) {
+ time_t timestamp;
+
+ ret = fit_get_timestamp(fit, 0, &timestamp);
+ printf("%s Created: ", p);
+ if (ret)
+ printf("unavailable\n");
+ else
+ genimg_print_time(timestamp);
+ }
+
+ fit_image_get_type(fit, image_noffset, &type);
+ printf("%s Type: %s\n", p, genimg_get_type_name(type));
+
+ fit_image_get_comp(fit, image_noffset, &comp);
+ printf("%s Compression: %s\n", p, genimg_get_comp_name(comp));
+
+ ret = fit_image_get_data_and_size(fit, image_noffset, &data, &size);
+
+ if (!host_build()) {
+ printf("%s Data Start: ", p);
+ if (ret) {
+ printf("unavailable\n");
+ } else {
+ void *vdata = (void *)data;
+
+ printf("0x%08lx\n", (ulong)map_to_sysmem(vdata));
+ }
+ }
+
+ printf("%s Data Size: ", p);
+ if (ret)
+ printf("unavailable\n");
+ else
+ genimg_print_size(size);
+
+ /* Remaining, type dependent properties */
+ if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
+ (type == IH_TYPE_RAMDISK) || (type == IH_TYPE_FIRMWARE) ||
+ (type == IH_TYPE_FLATDT)) {
+ fit_image_get_arch(fit, image_noffset, &arch);
+ printf("%s Architecture: %s\n", p, genimg_get_arch_name(arch));
+ }
+
+ if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_RAMDISK) ||
+ (type == IH_TYPE_FIRMWARE)) {
+ fit_image_get_os(fit, image_noffset, &os);
+ printf("%s OS: %s\n", p, genimg_get_os_name(os));
+ }
+
+ if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
+ (type == IH_TYPE_FIRMWARE) || (type == IH_TYPE_RAMDISK) ||
+ (type == IH_TYPE_FPGA)) {
+ ret = fit_image_get_load(fit, image_noffset, &load);
+ printf("%s Load Address: ", p);
+ if (ret)
+ printf("unavailable\n");
+ else
+ printf("0x%08lx\n", load);
+ }
+
+ /* optional load address for FDT */
+ if (type == IH_TYPE_FLATDT && !fit_image_get_load(fit, image_noffset, &load))
+ printf("%s Load Address: 0x%08lx\n", p, load);
+
+ if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
+ (type == IH_TYPE_RAMDISK)) {
+ ret = fit_image_get_entry(fit, image_noffset, &entry);
+ printf("%s Entry Point: ", p);
+ if (ret)
+ printf("unavailable\n");
+ else
+ printf("0x%08lx\n", entry);
+ }
+
+ /* Process all hash subnodes of the component image node */
+ for (ndepth = 0, noffset = fdt_next_node(fit, image_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /* Direct child node of the component image node */
+ fit_image_print_verification_data(fit, noffset, p);
+ }
+ }
+}
+#else
+void fit_print_contents(const void *fit) { }
+void fit_image_print(const void *fit, int image_noffset, const char *p) { }
+#endif /* CONFIG_IS_ENABLED(FIR_PRINT) || CONFIG_IS_ENABLED(SPL_FIT_PRINT) */
+
+/**
+ * fit_get_desc - get node description property
+ * @fit: pointer to the FIT format image header
+ * @noffset: node offset
+ * @desc: double pointer to the char, will hold pointer to the description
+ *
+ * fit_get_desc() reads description property from a given node, if
+ * description is found pointer to it is returned in third call argument.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_get_desc(const void *fit, int noffset, char **desc)
+{
+ int len;
+
+ *desc = (char *)fdt_getprop(fit, noffset, FIT_DESC_PROP, &len);
+ if (*desc == NULL) {
+ fit_get_debug(fit, noffset, FIT_DESC_PROP, len);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_get_timestamp - get node timestamp property
+ * @fit: pointer to the FIT format image header
+ * @noffset: node offset
+ * @timestamp: pointer to the time_t, will hold read timestamp
+ *
+ * fit_get_timestamp() reads timestamp property from given node, if timestamp
+ * is found and has a correct size its value is returned in third call
+ * argument.
+ *
+ * returns:
+ * 0, on success
+ * -1, on property read failure
+ * -2, on wrong timestamp size
+ */
+int fit_get_timestamp(const void *fit, int noffset, time_t *timestamp)
+{
+ int len;
+ const void *data;
+
+ data = fdt_getprop(fit, noffset, FIT_TIMESTAMP_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug(fit, noffset, FIT_TIMESTAMP_PROP, len);
+ return -1;
+ }
+ if (len != sizeof(uint32_t)) {
+ debug("FIT timestamp with incorrect size of (%u)\n", len);
+ return -2;
+ }
+
+ *timestamp = uimage_to_cpu(*((uint32_t *)data));
+ return 0;
+}
+
+/**
+ * fit_image_get_node - get node offset for component image of a given unit name
+ * @fit: pointer to the FIT format image header
+ * @image_uname: component image node unit name
+ *
+ * fit_image_get_node() finds a component image (within the '/images'
+ * node) of a provided unit name. If image is found its node offset is
+ * returned to the caller.
+ *
+ * returns:
+ * image node offset when found (>=0)
+ * negative number on failure (FDT_ERR_* code)
+ */
+int fit_image_get_node(const void *fit, const char *image_uname)
+{
+ int noffset, images_noffset;
+
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ debug("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror(images_noffset));
+ return images_noffset;
+ }
+
+ noffset = fdt_subnode_offset(fit, images_noffset, image_uname);
+ if (noffset < 0) {
+ debug("Can't get node offset for image unit name: '%s' (%s)\n",
+ image_uname, fdt_strerror(noffset));
+ }
+
+ return noffset;
+}
+
+/**
+ * fit_image_get_os - get os id for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @os: pointer to the uint8_t, will hold os numeric id
+ *
+ * fit_image_get_os() finds os property in a given component image node.
+ * If the property is found, its (string) value is translated to the numeric
+ * id which is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_os(const void *fit, int noffset, uint8_t *os)
+{
+ int len;
+ const void *data;
+
+ /* Get OS name from property data */
+ data = fdt_getprop(fit, noffset, FIT_OS_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug(fit, noffset, FIT_OS_PROP, len);
+ *os = -1;
+ return -1;
+ }
+
+ /* Translate OS name to id */
+ *os = genimg_get_os_id(data);
+ return 0;
+}
+
+/**
+ * fit_image_get_arch - get arch id for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @arch: pointer to the uint8_t, will hold arch numeric id
+ *
+ * fit_image_get_arch() finds arch property in a given component image node.
+ * If the property is found, its (string) value is translated to the numeric
+ * id which is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_arch(const void *fit, int noffset, uint8_t *arch)
+{
+ int len;
+ const void *data;
+
+ /* Get architecture name from property data */
+ data = fdt_getprop(fit, noffset, FIT_ARCH_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug(fit, noffset, FIT_ARCH_PROP, len);
+ *arch = -1;
+ return -1;
+ }
+
+ /* Translate architecture name to id */
+ *arch = genimg_get_arch_id(data);
+ return 0;
+}
+
+/**
+ * fit_image_get_type - get type id for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @type: pointer to the uint8_t, will hold type numeric id
+ *
+ * fit_image_get_type() finds type property in a given component image node.
+ * If the property is found, its (string) value is translated to the numeric
+ * id which is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_type(const void *fit, int noffset, uint8_t *type)
+{
+ int len;
+ const void *data;
+
+ /* Get image type name from property data */
+ data = fdt_getprop(fit, noffset, FIT_TYPE_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug(fit, noffset, FIT_TYPE_PROP, len);
+ *type = -1;
+ return -1;
+ }
+
+ /* Translate image type name to id */
+ *type = genimg_get_type_id(data);
+ return 0;
+}
+
+/**
+ * fit_image_get_comp - get comp id for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @comp: pointer to the uint8_t, will hold comp numeric id
+ *
+ * fit_image_get_comp() finds comp property in a given component image node.
+ * If the property is found, its (string) value is translated to the numeric
+ * id which is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_comp(const void *fit, int noffset, uint8_t *comp)
+{
+ int len;
+ const void *data;
+
+ /* Get compression name from property data */
+ data = fdt_getprop(fit, noffset, FIT_COMP_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug(fit, noffset, FIT_COMP_PROP, len);
+ *comp = -1;
+ return -1;
+ }
+
+ /* Translate compression name to id */
+ *comp = genimg_get_comp_id(data);
+ return 0;
+}
+
+static int fit_image_get_address(const void *fit, int noffset, char *name,
+ ulong *load)
+{
+ int len, cell_len;
+ const fdt32_t *cell;
+ uint64_t load64 = 0;
+
+ cell = fdt_getprop(fit, noffset, name, &len);
+ if (cell == NULL) {
+ fit_get_debug(fit, noffset, name, len);
+ return -1;
+ }
+
+ cell_len = len >> 2;
+ /* Use load64 to avoid compiling warning for 32-bit target */
+ while (cell_len--) {
+ load64 = (load64 << 32) | uimage_to_cpu(*cell);
+ cell++;
+ }
+
+ if (len > sizeof(ulong) && (uint32_t)(load64 >> 32)) {
+ printf("Unsupported %s address size\n", name);
+ return -1;
+ }
+
+ *load = (ulong)load64;
+
+ return 0;
+}
+/**
+ * fit_image_get_load() - get load addr property for given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @load: pointer to the uint32_t, will hold load address
+ *
+ * fit_image_get_load() finds load address property in a given component
+ * image node. If the property is found, its value is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_load(const void *fit, int noffset, ulong *load)
+{
+ return fit_image_get_address(fit, noffset, FIT_LOAD_PROP, load);
+}
+
+/**
+ * fit_image_get_entry() - get entry point address property
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @entry: pointer to the uint32_t, will hold entry point address
+ *
+ * This gets the entry point address property for a given component image
+ * node.
+ *
+ * fit_image_get_entry() finds entry point address property in a given
+ * component image node. If the property is found, its value is returned
+ * to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_entry(const void *fit, int noffset, ulong *entry)
+{
+ return fit_image_get_address(fit, noffset, FIT_ENTRY_PROP, entry);
+}
+
+/**
+ * fit_image_get_data - get data property and its size for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @data: double pointer to void, will hold data property's data address
+ * @size: pointer to size_t, will hold data property's data size
+ *
+ * fit_image_get_data() finds data property in a given component image node.
+ * If the property is found its data start address and size are returned to
+ * the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_data(const void *fit, int noffset,
+ const void **data, size_t *size)
+{
+ int len;
+
+ *data = fdt_getprop(fit, noffset, FIT_DATA_PROP, &len);
+ if (*data == NULL) {
+ fit_get_debug(fit, noffset, FIT_DATA_PROP, len);
+ *size = 0;
+ return -1;
+ }
+
+ *size = len;
+ return 0;
+}
+
+/**
+ * Get 'data-offset' property from a given image node.
+ *
+ * @fit: pointer to the FIT image header
+ * @noffset: component image node offset
+ * @data_offset: holds the data-offset property
+ *
+ * returns:
+ * 0, on success
+ * -ENOENT if the property could not be found
+ */
+int fit_image_get_data_offset(const void *fit, int noffset, int *data_offset)
+{
+ const fdt32_t *val;
+
+ val = fdt_getprop(fit, noffset, FIT_DATA_OFFSET_PROP, NULL);
+ if (!val)
+ return -ENOENT;
+
+ *data_offset = fdt32_to_cpu(*val);
+
+ return 0;
+}
+
+/**
+ * Get 'data-position' property from a given image node.
+ *
+ * @fit: pointer to the FIT image header
+ * @noffset: component image node offset
+ * @data_position: holds the data-position property
+ *
+ * returns:
+ * 0, on success
+ * -ENOENT if the property could not be found
+ */
+int fit_image_get_data_position(const void *fit, int noffset,
+ int *data_position)
+{
+ const fdt32_t *val;
+
+ val = fdt_getprop(fit, noffset, FIT_DATA_POSITION_PROP, NULL);
+ if (!val)
+ return -ENOENT;
+
+ *data_position = fdt32_to_cpu(*val);
+
+ return 0;
+}
+
+/**
+ * Get 'data-size' property from a given image node.
+ *
+ * @fit: pointer to the FIT image header
+ * @noffset: component image node offset
+ * @data_size: holds the data-size property
+ *
+ * returns:
+ * 0, on success
+ * -ENOENT if the property could not be found
+ */
+int fit_image_get_data_size(const void *fit, int noffset, int *data_size)
+{
+ const fdt32_t *val;
+
+ val = fdt_getprop(fit, noffset, FIT_DATA_SIZE_PROP, NULL);
+ if (!val)
+ return -ENOENT;
+
+ *data_size = fdt32_to_cpu(*val);
+
+ return 0;
+}
+
+/**
+ * Get 'data-size-unciphered' property from a given image node.
+ *
+ * @fit: pointer to the FIT image header
+ * @noffset: component image node offset
+ * @data_size: holds the data-size property
+ *
+ * returns:
+ * 0, on success
+ * -ENOENT if the property could not be found
+ */
+int fit_image_get_data_size_unciphered(const void *fit, int noffset,
+ size_t *data_size)
+{
+ const fdt32_t *val;
+
+ val = fdt_getprop(fit, noffset, "data-size-unciphered", NULL);
+ if (!val)
+ return -ENOENT;
+
+ *data_size = (size_t)fdt32_to_cpu(*val);
+
+ return 0;
+}
+
+/**
+ * fit_image_get_data_and_size - get data and its size including
+ * both embedded and external data
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @data: double pointer to void, will hold data property's data address
+ * @size: pointer to size_t, will hold data property's data size
+ *
+ * fit_image_get_data_and_size() finds data and its size including
+ * both embedded and external data. If the property is found
+ * its data start address and size are returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * otherwise, on failure
+ */
+int fit_image_get_data_and_size(const void *fit, int noffset,
+ const void **data, size_t *size)
+{
+ bool external_data = false;
+ int offset;
+ int len;
+ int ret;
+
+ if (!fit_image_get_data_position(fit, noffset, &offset)) {
+ external_data = true;
+ } else if (!fit_image_get_data_offset(fit, noffset, &offset)) {
+ external_data = true;
+ /*
+ * For FIT with external data, figure out where
+ * the external images start. This is the base
+ * for the data-offset properties in each image.
+ */
+ offset += ((fdt_totalsize(fit) + 3) & ~3);
+ }
+
+ if (external_data) {
+ debug("External Data\n");
+ ret = fit_image_get_data_size(fit, noffset, &len);
+ if (!ret) {
+ *data = fit + offset;
+ *size = len;
+ }
+ } else {
+ ret = fit_image_get_data(fit, noffset, data, size);
+ }
+
+ return ret;
+}
+
+/**
+ * fit_image_hash_get_algo - get hash algorithm name
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @algo: double pointer to char, will hold pointer to the algorithm name
+ *
+ * fit_image_hash_get_algo() finds hash algorithm property in a given hash node.
+ * If the property is found its data start address is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_hash_get_algo(const void *fit, int noffset, char **algo)
+{
+ int len;
+
+ *algo = (char *)fdt_getprop(fit, noffset, FIT_ALGO_PROP, &len);
+ if (*algo == NULL) {
+ fit_get_debug(fit, noffset, FIT_ALGO_PROP, len);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_hash_get_value - get hash value and length
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @value: double pointer to uint8_t, will hold address of a hash value data
+ * @value_len: pointer to an int, will hold hash data length
+ *
+ * fit_image_hash_get_value() finds hash value property in a given hash node.
+ * If the property is found its data start address and size are returned to
+ * the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,
+ int *value_len)
+{
+ int len;
+
+ *value = (uint8_t *)fdt_getprop(fit, noffset, FIT_VALUE_PROP, &len);
+ if (*value == NULL) {
+ fit_get_debug(fit, noffset, FIT_VALUE_PROP, len);
+ *value_len = 0;
+ return -1;
+ }
+
+ *value_len = len;
+ return 0;
+}
+
+/**
+ * fit_image_hash_get_ignore - get hash ignore flag
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @ignore: pointer to an int, will hold hash ignore flag
+ *
+ * fit_image_hash_get_ignore() finds hash ignore property in a given hash node.
+ * If the property is found and non-zero, the hash algorithm is not verified by
+ * u-boot automatically.
+ *
+ * returns:
+ * 0, on ignore not found
+ * value, on ignore found
+ */
+static int fit_image_hash_get_ignore(const void *fit, int noffset, int *ignore)
+{
+ int len;
+ int *value;
+
+ value = (int *)fdt_getprop(fit, noffset, FIT_IGNORE_PROP, &len);
+ if (value == NULL || len != sizeof(int))
+ *ignore = 0;
+ else
+ *ignore = *value;
+
+ return 0;
+}
+
+/**
+ * fit_image_cipher_get_algo - get cipher algorithm name
+ * @fit: pointer to the FIT format image header
+ * @noffset: cipher node offset
+ * @algo: double pointer to char, will hold pointer to the algorithm name
+ *
+ * fit_image_cipher_get_algo() finds cipher algorithm property in a given
+ * cipher node. If the property is found its data start address is returned
+ * to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_cipher_get_algo(const void *fit, int noffset, char **algo)
+{
+ int len;
+
+ *algo = (char *)fdt_getprop(fit, noffset, FIT_ALGO_PROP, &len);
+ if (!*algo) {
+ fit_get_debug(fit, noffset, FIT_ALGO_PROP, len);
+ return -1;
+ }
+
+ return 0;
+}
+
+ulong fit_get_end(const void *fit)
+{
+ return map_to_sysmem((void *)(fit + fdt_totalsize(fit)));
+}
+
+/**
+ * fit_set_timestamp - set node timestamp property
+ * @fit: pointer to the FIT format image header
+ * @noffset: node offset
+ * @timestamp: timestamp value to be set
+ *
+ * fit_set_timestamp() attempts to set timestamp property in the requested
+ * node and returns operation status to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -ENOSPC if no space in device tree, -1 for other error
+ */
+int fit_set_timestamp(void *fit, int noffset, time_t timestamp)
+{
+ uint32_t t;
+ int ret;
+
+ t = cpu_to_uimage(timestamp);
+ ret = fdt_setprop(fit, noffset, FIT_TIMESTAMP_PROP, &t,
+ sizeof(uint32_t));
+ if (ret) {
+ debug("Can't set '%s' property for '%s' node (%s)\n",
+ FIT_TIMESTAMP_PROP, fit_get_name(fit, noffset, NULL),
+ fdt_strerror(ret));
+ return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -1;
+ }
+
+ return 0;
+}
+
+/**
+ * calculate_hash - calculate and return hash for provided input data
+ * @data: pointer to the input data
+ * @data_len: data length
+ * @algo: requested hash algorithm
+ * @value: pointer to the char, will hold hash value data (caller must
+ * allocate enough free space)
+ * value_len: length of the calculated hash
+ *
+ * calculate_hash() computes input data hash according to the requested
+ * algorithm.
+ * Resulting hash value is placed in caller provided 'value' buffer, length
+ * of the calculated hash is returned via value_len pointer argument.
+ *
+ * returns:
+ * 0, on success
+ * -1, when algo is unsupported
+ */
+int calculate_hash(const void *data, int data_len, const char *algo,
+ uint8_t *value, int *value_len)
+{
+ if (IMAGE_ENABLE_CRC32 && strcmp(algo, "crc32") == 0) {
+ *((uint32_t *)value) = crc32_wd(0, data, data_len,
+ CHUNKSZ_CRC32);
+ *((uint32_t *)value) = cpu_to_uimage(*((uint32_t *)value));
+ *value_len = 4;
+ } else if (IMAGE_ENABLE_SHA1 && strcmp(algo, "sha1") == 0) {
+ sha1_csum_wd((unsigned char *)data, data_len,
+ (unsigned char *)value, CHUNKSZ_SHA1);
+ *value_len = 20;
+ } else if (IMAGE_ENABLE_SHA256 && strcmp(algo, "sha256") == 0) {
+ sha256_csum_wd((unsigned char *)data, data_len,
+ (unsigned char *)value, CHUNKSZ_SHA256);
+ *value_len = SHA256_SUM_LEN;
+ } else if (IMAGE_ENABLE_SHA384 && strcmp(algo, "sha384") == 0) {
+ sha384_csum_wd((unsigned char *)data, data_len,
+ (unsigned char *)value, CHUNKSZ_SHA384);
+ *value_len = SHA384_SUM_LEN;
+ } else if (IMAGE_ENABLE_SHA512 && strcmp(algo, "sha512") == 0) {
+ sha512_csum_wd((unsigned char *)data, data_len,
+ (unsigned char *)value, CHUNKSZ_SHA512);
+ *value_len = SHA512_SUM_LEN;
+ } else if (IMAGE_ENABLE_MD5 && strcmp(algo, "md5") == 0) {
+ md5_wd((unsigned char *)data, data_len, value, CHUNKSZ_MD5);
+ *value_len = 16;
+ } else {
+ debug("Unsupported hash alogrithm\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int fit_image_check_hash(const void *fit, int noffset, const void *data,
+ size_t size, char **err_msgp)
+{
+ uint8_t value[FIT_MAX_HASH_LEN];
+ int value_len;
+ char *algo;
+ uint8_t *fit_value;
+ int fit_value_len;
+ int ignore;
+
+ *err_msgp = NULL;
+
+ if (fit_image_hash_get_algo(fit, noffset, &algo)) {
+ *err_msgp = "Can't get hash algo property";
+ return -1;
+ }
+ printf("%s", algo);
+
+ if (IMAGE_ENABLE_IGNORE) {
+ fit_image_hash_get_ignore(fit, noffset, &ignore);
+ if (ignore) {
+ printf("-skipped ");
+ return 0;
+ }
+ }
+
+ if (fit_image_hash_get_value(fit, noffset, &fit_value,
+ &fit_value_len)) {
+ *err_msgp = "Can't get hash value property";
+ return -1;
+ }
+
+ if (calculate_hash(data, size, algo, value, &value_len)) {
+ *err_msgp = "Unsupported hash algorithm";
+ return -1;
+ }
+
+ if (value_len != fit_value_len) {
+ *err_msgp = "Bad hash value len";
+ return -1;
+ } else if (memcmp(value, fit_value, value_len) != 0) {
+ *err_msgp = "Bad hash value";
+ return -1;
+ }
+
+ return 0;
+}
+
+int fit_image_verify_with_data(const void *fit, int image_noffset,
+ const void *data, size_t size)
+{
+ int noffset = 0;
+ char *err_msg = "";
+ int verify_all = 1;
+ int ret;
+
+ /* Verify all required signatures */
+ if (FIT_IMAGE_ENABLE_VERIFY &&
+ fit_image_verify_required_sigs(fit, image_noffset, data, size,
+ gd_fdt_blob(), &verify_all)) {
+ err_msg = "Unable to verify required signature";
+ goto error;
+ }
+
+ /* Process all hash subnodes of the component image node */
+ fdt_for_each_subnode(noffset, fit, image_noffset) {
+ const char *name = fit_get_name(fit, noffset, NULL);
+
+ /*
+ * Check subnode name, must be equal to "hash".
+ * Multiple hash nodes require unique unit node
+ * names, e.g. hash-1, hash-2, etc.
+ */
+ if (!strncmp(name, FIT_HASH_NODENAME,
+ strlen(FIT_HASH_NODENAME))) {
+ if (fit_image_check_hash(fit, noffset, data, size,
+ &err_msg))
+ goto error;
+ puts("+ ");
+ } else if (FIT_IMAGE_ENABLE_VERIFY && verify_all &&
+ !strncmp(name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_image_check_sig(fit, noffset, data,
+ size, -1, &err_msg);
+
+ /*
+ * Show an indication on failure, but do not return
+ * an error. Only keys marked 'required' can cause
+ * an image validation failure. See the call to
+ * fit_image_verify_required_sigs() above.
+ */
+ if (ret)
+ puts("- ");
+ else
+ puts("+ ");
+ }
+ }
+
+ if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
+ err_msg = "Corrupted or truncated tree";
+ goto error;
+ }
+
+ return 1;
+
+error:
+ printf(" error!\n%s for '%s' hash node in '%s' image node\n",
+ err_msg, fit_get_name(fit, noffset, NULL),
+ fit_get_name(fit, image_noffset, NULL));
+ return 0;
+}
+
+/**
+ * fit_image_verify - verify data integrity
+ * @fit: pointer to the FIT format image header
+ * @image_noffset: component image node offset
+ *
+ * fit_image_verify() goes over component image hash nodes,
+ * re-calculates each data hash and compares with the value stored in hash
+ * node.
+ *
+ * returns:
+ * 1, if all hashes are valid
+ * 0, otherwise (or on error)
+ */
+int fit_image_verify(const void *fit, int image_noffset)
+{
+ const char *name = fit_get_name(fit, image_noffset, NULL);
+ const void *data;
+ size_t size;
+ char *err_msg = "";
+
+ if (strchr(name, '@')) {
+ /*
+ * We don't support this since libfdt considers names with the
+ * name root but different @ suffix to be equal
+ */
+ err_msg = "Node name contains @";
+ goto err;
+ }
+ /* Get image data and data length */
+ if (fit_image_get_data_and_size(fit, image_noffset, &data, &size)) {
+ err_msg = "Can't get image data/size";
+ goto err;
+ }
+
+ return fit_image_verify_with_data(fit, image_noffset, data, size);
+
+err:
+ printf("error!\n%s in '%s' image node\n", err_msg,
+ fit_get_name(fit, image_noffset, NULL));
+ return 0;
+}
+
+/**
+ * fit_all_image_verify - verify data integrity for all images
+ * @fit: pointer to the FIT format image header
+ *
+ * fit_all_image_verify() goes over all images in the FIT and
+ * for every images checks if all it's hashes are valid.
+ *
+ * returns:
+ * 1, if all hashes of all images are valid
+ * 0, otherwise (or on error)
+ */
+int fit_all_image_verify(const void *fit)
+{
+ int images_noffset;
+ int noffset;
+ int ndepth;
+ int count;
+
+ /* Find images parent node offset */
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ printf("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror(images_noffset));
+ return 0;
+ }
+
+ /* Process all image subnodes, check hashes for each */
+ printf("## Checking hash(es) for FIT Image at %08lx ...\n",
+ (ulong)fit);
+ for (ndepth = 0, count = 0,
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /*
+ * Direct child node of the images parent node,
+ * i.e. component image node.
+ */
+ printf(" Hash(es) for Image %u (%s): ", count,
+ fit_get_name(fit, noffset, NULL));
+ count++;
+
+ if (!fit_image_verify(fit, noffset))
+ return 0;
+ printf("\n");
+ }
+ }
+ return 1;
+}
+
+static int fit_image_uncipher(const void *fit, int image_noffset,
+ void **data, size_t *size)
+{
+ int cipher_noffset, ret;
+ void *dst;
+ size_t size_dst;
+
+ cipher_noffset = fdt_subnode_offset(fit, image_noffset,
+ FIT_CIPHER_NODENAME);
+ if (cipher_noffset < 0)
+ return 0;
+
+ ret = fit_image_decrypt_data(fit, image_noffset, cipher_noffset,
+ *data, *size, &dst, &size_dst);
+ if (ret)
+ goto out;
+
+ *data = dst;
+ *size = size_dst;
+
+ out:
+ return ret;
+}
+
+/**
+ * fit_image_check_os - check whether image node is of a given os type
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @os: requested image os
+ *
+ * fit_image_check_os() reads image os property and compares its numeric
+ * id with the requested os. Comparison result is returned to the caller.
+ *
+ * returns:
+ * 1 if image is of given os type
+ * 0 otherwise (or on error)
+ */
+int fit_image_check_os(const void *fit, int noffset, uint8_t os)
+{
+ uint8_t image_os;
+
+ if (fit_image_get_os(fit, noffset, &image_os))
+ return 0;
+ return (os == image_os);
+}
+
+/**
+ * fit_image_check_arch - check whether image node is of a given arch
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @arch: requested imagearch
+ *
+ * fit_image_check_arch() reads image arch property and compares its numeric
+ * id with the requested arch. Comparison result is returned to the caller.
+ *
+ * returns:
+ * 1 if image is of given arch
+ * 0 otherwise (or on error)
+ */
+int fit_image_check_arch(const void *fit, int noffset, uint8_t arch)
+{
+ uint8_t image_arch;
+ int aarch32_support = 0;
+
+ /* Let's assume that sandbox can load any architecture */
+ if (IS_ENABLED(CONFIG_SANDBOX))
+ return true;
+
+ if (IS_ENABLED(CONFIG_ARM64_SUPPORT_AARCH32))
+ aarch32_support = 1;
+
+ if (fit_image_get_arch(fit, noffset, &image_arch))
+ return 0;
+ return (arch == image_arch) ||
+ (arch == IH_ARCH_I386 && image_arch == IH_ARCH_X86_64) ||
+ (arch == IH_ARCH_ARM64 && image_arch == IH_ARCH_ARM &&
+ aarch32_support);
+}
+
+/**
+ * fit_image_check_type - check whether image node is of a given type
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @type: requested image type
+ *
+ * fit_image_check_type() reads image type property and compares its numeric
+ * id with the requested type. Comparison result is returned to the caller.
+ *
+ * returns:
+ * 1 if image is of given type
+ * 0 otherwise (or on error)
+ */
+int fit_image_check_type(const void *fit, int noffset, uint8_t type)
+{
+ uint8_t image_type;
+
+ if (fit_image_get_type(fit, noffset, &image_type))
+ return 0;
+ return (type == image_type);
+}
+
+/**
+ * fit_image_check_comp - check whether image node uses given compression
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @comp: requested image compression type
+ *
+ * fit_image_check_comp() reads image compression property and compares its
+ * numeric id with the requested compression type. Comparison result is
+ * returned to the caller.
+ *
+ * returns:
+ * 1 if image uses requested compression
+ * 0 otherwise (or on error)
+ */
+int fit_image_check_comp(const void *fit, int noffset, uint8_t comp)
+{
+ uint8_t image_comp;
+
+ if (fit_image_get_comp(fit, noffset, &image_comp))
+ return 0;
+ return (comp == image_comp);
+}
+
+/**
+ * fdt_check_no_at() - Check for nodes whose names contain '@'
+ *
+ * This checks the parent node and all subnodes recursively
+ *
+ * @fit: FIT to check
+ * @parent: Parent node to check
+ * @return 0 if OK, -EADDRNOTAVAIL is a node has a name containing '@'
+ */
+static int fdt_check_no_at(const void *fit, int parent)
+{
+ const char *name;
+ int node;
+ int ret;
+
+ name = fdt_get_name(fit, parent, NULL);
+ if (!name || strchr(name, '@'))
+ return -EADDRNOTAVAIL;
+
+ fdt_for_each_subnode(node, fit, parent) {
+ ret = fdt_check_no_at(fit, node);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int fit_check_format(const void *fit, ulong size)
+{
+ int ret;
+
+ /* A FIT image must be a valid FDT */
+ ret = fdt_check_header(fit);
+ if (ret) {
+ log_debug("Wrong FIT format: not a flattened device tree (err=%d)\n",
+ ret);
+ return -ENOEXEC;
+ }
+
+ if (CONFIG_IS_ENABLED(FIT_FULL_CHECK)) {
+ /*
+ * If we are not given the size, make do wtih calculating it.
+ * This is not as secure, so we should consider a flag to
+ * control this.
+ */
+ if (size == IMAGE_SIZE_INVAL)
+ size = fdt_totalsize(fit);
+ ret = fdt_check_full(fit, size);
+ if (ret)
+ ret = -EINVAL;
+
+ /*
+ * U-Boot stopped using unit addressed in 2017. Since libfdt
+ * can match nodes ignoring any unit address, signature
+ * verification can see the wrong node if one is inserted with
+ * the same name as a valid node but with a unit address
+ * attached. Protect against this by disallowing unit addresses.
+ */
+ if (!ret && CONFIG_IS_ENABLED(FIT_SIGNATURE)) {
+ ret = fdt_check_no_at(fit, 0);
+
+ if (ret) {
+ log_debug("FIT check error %d\n", ret);
+ return ret;
+ }
+ }
+ if (ret) {
+ log_debug("FIT check error %d\n", ret);
+ return ret;
+ }
+ }
+
+ /* mandatory / node 'description' property */
+ if (!fdt_getprop(fit, 0, FIT_DESC_PROP, NULL)) {
+ log_debug("Wrong FIT format: no description\n");
+ return -ENOMSG;
+ }
+
+ if (IMAGE_ENABLE_TIMESTAMP) {
+ /* mandatory / node 'timestamp' property */
+ if (!fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL)) {
+ log_debug("Wrong FIT format: no timestamp\n");
+ return -EBADMSG;
+ }
+ }
+
+ /* mandatory subimages parent '/images' node */
+ if (fdt_path_offset(fit, FIT_IMAGES_PATH) < 0) {
+ log_debug("Wrong FIT format: no images parent node\n");
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_conf_find_compat
+ * @fit: pointer to the FIT format image header
+ * @fdt: pointer to the device tree to compare against
+ *
+ * fit_conf_find_compat() attempts to find the configuration whose fdt is the
+ * most compatible with the passed in device tree.
+ *
+ * Example:
+ *
+ * / o image-tree
+ * |-o images
+ * | |-o fdt-1
+ * | |-o fdt-2
+ * |
+ * |-o configurations
+ * |-o config-1
+ * | |-fdt = fdt-1
+ * |
+ * |-o config-2
+ * |-fdt = fdt-2
+ *
+ * / o U-Boot fdt
+ * |-compatible = "foo,bar", "bim,bam"
+ *
+ * / o kernel fdt1
+ * |-compatible = "foo,bar",
+ *
+ * / o kernel fdt2
+ * |-compatible = "bim,bam", "baz,biz"
+ *
+ * Configuration 1 would be picked because the first string in U-Boot's
+ * compatible list, "foo,bar", matches a compatible string in the root of fdt1.
+ * "bim,bam" in fdt2 matches the second string which isn't as good as fdt1.
+ *
+ * As an optimization, the compatible property from the FDT's root node can be
+ * copied into the configuration node in the FIT image. This is required to
+ * match configurations with compressed FDTs.
+ *
+ * returns:
+ * offset to the configuration to use if one was found
+ * -1 otherwise
+ */
+int fit_conf_find_compat(const void *fit, const void *fdt)
+{
+ int ndepth = 0;
+ int noffset, confs_noffset, images_noffset;
+ const void *fdt_compat;
+ int fdt_compat_len;
+ int best_match_offset = 0;
+ int best_match_pos = 0;
+
+ confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (confs_noffset < 0 || images_noffset < 0) {
+ debug("Can't find configurations or images nodes.\n");
+ return -1;
+ }
+
+ fdt_compat = fdt_getprop(fdt, 0, "compatible", &fdt_compat_len);
+ if (!fdt_compat) {
+ debug("Fdt for comparison has no \"compatible\" property.\n");
+ return -1;
+ }
+
+ /*
+ * Loop over the configurations in the FIT image.
+ */
+ for (noffset = fdt_next_node(fit, confs_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ const void *fdt;
+ const char *kfdt_name;
+ int kfdt_noffset, compat_noffset;
+ const char *cur_fdt_compat;
+ int len;
+ size_t sz;
+ int i;
+
+ if (ndepth > 1)
+ continue;
+
+ /* If there's a compat property in the config node, use that. */
+ if (fdt_getprop(fit, noffset, "compatible", NULL)) {
+ fdt = fit; /* search in FIT image */
+ compat_noffset = noffset; /* search under config node */
+ } else { /* Otherwise extract it from the kernel FDT. */
+ kfdt_name = fdt_getprop(fit, noffset, "fdt", &len);
+ if (!kfdt_name) {
+ debug("No fdt property found.\n");
+ continue;
+ }
+ kfdt_noffset = fdt_subnode_offset(fit, images_noffset,
+ kfdt_name);
+ if (kfdt_noffset < 0) {
+ debug("No image node named \"%s\" found.\n",
+ kfdt_name);
+ continue;
+ }
+
+ if (!fit_image_check_comp(fit, kfdt_noffset,
+ IH_COMP_NONE)) {
+ debug("Can't extract compat from \"%s\" "
+ "(compressed)\n", kfdt_name);
+ continue;
+ }
+
+ /* search in this config's kernel FDT */
+ if (fit_image_get_data(fit, kfdt_noffset, &fdt, &sz)) {
+ debug("Failed to get fdt \"%s\".\n", kfdt_name);
+ continue;
+ }
+
+ compat_noffset = 0; /* search kFDT under root node */
+ }
+
+ len = fdt_compat_len;
+ cur_fdt_compat = fdt_compat;
+ /*
+ * Look for a match for each U-Boot compatibility string in
+ * turn in the compat string property.
+ */
+ for (i = 0; len > 0 &&
+ (!best_match_offset || best_match_pos > i); i++) {
+ int cur_len = strlen(cur_fdt_compat) + 1;
+
+ if (!fdt_node_check_compatible(fdt, compat_noffset,
+ cur_fdt_compat)) {
+ best_match_offset = noffset;
+ best_match_pos = i;
+ break;
+ }
+ len -= cur_len;
+ cur_fdt_compat += cur_len;
+ }
+ }
+ if (!best_match_offset) {
+ debug("No match found.\n");
+ return -1;
+ }
+
+ return best_match_offset;
+}
+
+int fit_conf_get_node(const void *fit, const char *conf_uname)
+{
+ int noffset, confs_noffset;
+ int len;
+ const char *s;
+ char *conf_uname_copy = NULL;
+
+ confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
+ if (confs_noffset < 0) {
+ debug("Can't find configurations parent node '%s' (%s)\n",
+ FIT_CONFS_PATH, fdt_strerror(confs_noffset));
+ return confs_noffset;
+ }
+
+ if (conf_uname == NULL) {
+ /* get configuration unit name from the default property */
+ debug("No configuration specified, trying default...\n");
+ if (!host_build() && IS_ENABLED(CONFIG_MULTI_DTB_FIT)) {
+ noffset = fit_find_config_node(fit);
+ if (noffset < 0)
+ return noffset;
+ conf_uname = fdt_get_name(fit, noffset, NULL);
+ } else {
+ conf_uname = (char *)fdt_getprop(fit, confs_noffset,
+ FIT_DEFAULT_PROP, &len);
+ if (conf_uname == NULL) {
+ fit_get_debug(fit, confs_noffset, FIT_DEFAULT_PROP,
+ len);
+ return len;
+ }
+ }
+ debug("Found default configuration: '%s'\n", conf_uname);
+ }
+
+ s = strchr(conf_uname, '#');
+ if (s) {
+ len = s - conf_uname;
+ conf_uname_copy = malloc(len + 1);
+ if (!conf_uname_copy) {
+ debug("Can't allocate uname copy: '%s'\n",
+ conf_uname);
+ return -ENOMEM;
+ }
+ memcpy(conf_uname_copy, conf_uname, len);
+ conf_uname_copy[len] = '\0';
+ conf_uname = conf_uname_copy;
+ }
+
+ noffset = fdt_subnode_offset(fit, confs_noffset, conf_uname);
+ if (noffset < 0) {
+ debug("Can't get node offset for configuration unit name: '%s' (%s)\n",
+ conf_uname, fdt_strerror(noffset));
+ }
+
+ if (conf_uname_copy)
+ free(conf_uname_copy);
+
+ return noffset;
+}
+
+int fit_conf_get_prop_node_count(const void *fit, int noffset,
+ const char *prop_name)
+{
+ return fdt_stringlist_count(fit, noffset, prop_name);
+}
+
+int fit_conf_get_prop_node_index(const void *fit, int noffset,
+ const char *prop_name, int index)
+{
+ const char *uname;
+ int len;
+
+ /* get kernel image unit name from configuration kernel property */
+ uname = fdt_stringlist_get(fit, noffset, prop_name, index, &len);
+ if (uname == NULL)
+ return len;
+
+ return fit_image_get_node(fit, uname);
+}
+
+int fit_conf_get_prop_node(const void *fit, int noffset,
+ const char *prop_name)
+{
+ return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0);
+}
+
+static int fit_image_select(const void *fit, int rd_noffset, int verify)
+{
+ fit_image_print(fit, rd_noffset, " ");
+
+ if (verify) {
+ puts(" Verifying Hash Integrity ... ");
+ if (!fit_image_verify(fit, rd_noffset)) {
+ puts("Bad Data Hash\n");
+ return -EACCES;
+ }
+ puts("OK\n");
+ }
+
+ return 0;
+}
+
+int fit_get_node_from_config(bootm_headers_t *images, const char *prop_name,
+ ulong addr)
+{
+ int cfg_noffset;
+ void *fit_hdr;
+ int noffset;
+
+ debug("* %s: using config '%s' from image at 0x%08lx\n",
+ prop_name, images->fit_uname_cfg, addr);
+
+ /* Check whether configuration has this property defined */
+ fit_hdr = map_sysmem(addr, 0);
+ cfg_noffset = fit_conf_get_node(fit_hdr, images->fit_uname_cfg);
+ if (cfg_noffset < 0) {
+ debug("* %s: no such config\n", prop_name);
+ return -EINVAL;
+ }
+
+ noffset = fit_conf_get_prop_node(fit_hdr, cfg_noffset, prop_name);
+ if (noffset < 0) {
+ debug("* %s: no '%s' in config\n", prop_name, prop_name);
+ return -ENOENT;
+ }
+
+ return noffset;
+}
+
+/**
+ * fit_get_image_type_property() - get property name for IH_TYPE_...
+ *
+ * @return the properly name where we expect to find the image in the
+ * config node
+ */
+static const char *fit_get_image_type_property(int type)
+{
+ /*
+ * This is sort-of available in the uimage_type[] table in image.c
+ * but we don't have access to the short name, and "fdt" is different
+ * anyway. So let's just keep it here.
+ */
+ switch (type) {
+ case IH_TYPE_FLATDT:
+ return FIT_FDT_PROP;
+ case IH_TYPE_KERNEL:
+ return FIT_KERNEL_PROP;
+ case IH_TYPE_FIRMWARE:
+ return FIT_FIRMWARE_PROP;
+ case IH_TYPE_RAMDISK:
+ return FIT_RAMDISK_PROP;
+ case IH_TYPE_X86_SETUP:
+ return FIT_SETUP_PROP;
+ case IH_TYPE_LOADABLE:
+ return FIT_LOADABLE_PROP;
+ case IH_TYPE_FPGA:
+ return FIT_FPGA_PROP;
+ case IH_TYPE_STANDALONE:
+ return FIT_STANDALONE_PROP;
+ }
+
+ return "unknown";
+}
+
+int fit_image_load(bootm_headers_t *images, ulong addr,
+ const char **fit_unamep, const char **fit_uname_configp,
+ int arch, int image_type, int bootstage_id,
+ enum fit_load_op load_op, ulong *datap, ulong *lenp)
+{
+ int cfg_noffset, noffset;
+ const char *fit_uname;
+ const char *fit_uname_config;
+ const char *fit_base_uname_config;
+ const void *fit;
+ void *buf;
+ void *loadbuf;
+ size_t size;
+ int type_ok, os_ok;
+ ulong load, load_end, data, len;
+ uint8_t os, comp;
+#ifndef USE_HOSTCC
+ uint8_t os_arch;
+#endif
+ const char *prop_name;
+ int ret;
+
+ fit = map_sysmem(addr, 0);
+ fit_uname = fit_unamep ? *fit_unamep : NULL;
+ fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL;
+ fit_base_uname_config = NULL;
+ prop_name = fit_get_image_type_property(image_type);
+ printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
+
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT);
+ ret = fit_check_format(fit, IMAGE_SIZE_INVAL);
+ if (ret) {
+ printf("Bad FIT %s image format! (err=%d)\n", prop_name, ret);
+ if (CONFIG_IS_ENABLED(FIT_SIGNATURE) && ret == -EADDRNOTAVAIL)
+ printf("Signature checking prevents use of unit addresses (@) in nodes\n");
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT);
+ return ret;
+ }
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT_OK);
+ if (fit_uname) {
+ /* get FIT component image node offset */
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_UNIT_NAME);
+ noffset = fit_image_get_node(fit, fit_uname);
+ } else {
+ /*
+ * no image node unit name, try to get config
+ * node first. If config unit node name is NULL
+ * fit_conf_get_node() will try to find default config node
+ */
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_NO_UNIT_NAME);
+ if (IMAGE_ENABLE_BEST_MATCH && !fit_uname_config) {
+ cfg_noffset = fit_conf_find_compat(fit, gd_fdt_blob());
+ } else {
+ cfg_noffset = fit_conf_get_node(fit,
+ fit_uname_config);
+ }
+ if (cfg_noffset < 0) {
+ puts("Could not find configuration node\n");
+ bootstage_error(bootstage_id +
+ BOOTSTAGE_SUB_NO_UNIT_NAME);
+ return -ENOENT;
+ }
+
+ fit_base_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
+ printf(" Using '%s' configuration\n", fit_base_uname_config);
+ /* Remember this config */
+ if (image_type == IH_TYPE_KERNEL)
+ images->fit_uname_cfg = fit_base_uname_config;
+
+ if (FIT_IMAGE_ENABLE_VERIFY && images->verify) {
+ puts(" Verifying Hash Integrity ... ");
+ if (fit_config_verify(fit, cfg_noffset)) {
+ puts("Bad Data Hash\n");
+ bootstage_error(bootstage_id +
+ BOOTSTAGE_SUB_HASH);
+ return -EACCES;
+ }
+ puts("OK\n");
+ }
+
+ bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG);
+
+ noffset = fit_conf_get_prop_node(fit, cfg_noffset,
+ prop_name);
+ fit_uname = fit_get_name(fit, noffset, NULL);
+ }
+ if (noffset < 0) {
+ printf("Could not find subimage node type '%s'\n", prop_name);
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_SUBNODE);
+ return -ENOENT;
+ }
+
+ printf(" Trying '%s' %s subimage\n", fit_uname, prop_name);
+
+ ret = fit_image_select(fit, noffset, images->verify);
+ if (ret) {
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_HASH);
+ return ret;
+ }
+
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
+ if (!host_build() && IS_ENABLED(CONFIG_SANDBOX)) {
+ if (!fit_image_check_target_arch(fit, noffset)) {
+ puts("Unsupported Architecture\n");
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
+ return -ENOEXEC;
+ }
+ }
+
+#ifndef USE_HOSTCC
+ fit_image_get_arch(fit, noffset, &os_arch);
+ images->os.arch = os_arch;
+#endif
+
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
+ type_ok = fit_image_check_type(fit, noffset, image_type) ||
+ fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE) ||
+ fit_image_check_type(fit, noffset, IH_TYPE_TEE) ||
+ (image_type == IH_TYPE_KERNEL &&
+ fit_image_check_type(fit, noffset, IH_TYPE_KERNEL_NOLOAD));
+
+ os_ok = image_type == IH_TYPE_FLATDT ||
+ image_type == IH_TYPE_FPGA ||
+ fit_image_check_os(fit, noffset, IH_OS_LINUX) ||
+ fit_image_check_os(fit, noffset, IH_OS_U_BOOT) ||
+ fit_image_check_os(fit, noffset, IH_OS_TEE) ||
+ fit_image_check_os(fit, noffset, IH_OS_OPENRTOS) ||
+ fit_image_check_os(fit, noffset, IH_OS_EFI) ||
+ fit_image_check_os(fit, noffset, IH_OS_VXWORKS);
+
+ /*
+ * If either of the checks fail, we should report an error, but
+ * if the image type is coming from the "loadables" field, we
+ * don't care what it is
+ */
+ if ((!type_ok || !os_ok) && image_type != IH_TYPE_LOADABLE) {
+ fit_image_get_os(fit, noffset, &os);
+ printf("No %s %s %s Image\n",
+ genimg_get_os_name(os),
+ genimg_get_arch_name(arch),
+ genimg_get_type_name(image_type));
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
+ return -EIO;
+ }
+
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK);
+
+ /* get image data address and length */
+ if (fit_image_get_data_and_size(fit, noffset,
+ (const void **)&buf, &size)) {
+ printf("Could not find %s subimage data!\n", prop_name);
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA);
+ return -ENOENT;
+ }
+
+ /* Decrypt data before uncompress/move */
+ if (IS_ENABLED(CONFIG_FIT_CIPHER) && IMAGE_ENABLE_DECRYPT) {
+ puts(" Decrypting Data ... ");
+ if (fit_image_uncipher(fit, noffset, &buf, &size)) {
+ puts("Error\n");
+ return -EACCES;
+ }
+ puts("OK\n");
+ }
+
+ /* perform any post-processing on the image data */
+ if (!host_build() && IS_ENABLED(CONFIG_FIT_IMAGE_POST_PROCESS))
+ board_fit_image_post_process(&buf, &size);
+
+ len = (ulong)size;
+
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK);
+
+ data = map_to_sysmem(buf);
+ load = data;
+ if (load_op == FIT_LOAD_IGNORED) {
+ /* Don't load */
+ } else if (fit_image_get_load(fit, noffset, &load)) {
+ if (load_op == FIT_LOAD_REQUIRED) {
+ printf("Can't get %s subimage load address!\n",
+ prop_name);
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_LOAD);
+ return -EBADF;
+ }
+ } else if (load_op != FIT_LOAD_OPTIONAL_NON_ZERO || load) {
+ ulong image_start, image_end;
+
+ /*
+ * move image data to the load address,
+ * make sure we don't overwrite initial image
+ */
+ image_start = addr;
+ image_end = addr + fit_get_size(fit);
+
+ load_end = load + len;
+ if (image_type != IH_TYPE_KERNEL &&
+ load < image_end && load_end > image_start) {
+ printf("Error: %s overwritten\n", prop_name);
+ return -EXDEV;
+ }
+
+ printf(" Loading %s from 0x%08lx to 0x%08lx\n",
+ prop_name, data, load);
+ } else {
+ load = data; /* No load address specified */
+ }
+
+ comp = IH_COMP_NONE;
+ loadbuf = buf;
+ /* Kernel images get decompressed later in bootm_load_os(). */
+ if (!fit_image_get_comp(fit, noffset, &comp) &&
+ comp != IH_COMP_NONE &&
+ !(image_type == IH_TYPE_KERNEL ||
+ image_type == IH_TYPE_KERNEL_NOLOAD ||
+ image_type == IH_TYPE_RAMDISK)) {
+ ulong max_decomp_len = len * 20;
+ if (load == data) {
+ loadbuf = malloc(max_decomp_len);
+ load = map_to_sysmem(loadbuf);
+ } else {
+ loadbuf = map_sysmem(load, max_decomp_len);
+ }
+ if (image_decomp(comp, load, data, image_type,
+ loadbuf, buf, len, max_decomp_len, &load_end)) {
+ printf("Error decompressing %s\n", prop_name);
+
+ return -ENOEXEC;
+ }
+ len = load_end - load;
+ } else if (load != data) {
+ loadbuf = map_sysmem(load, len);
+ memcpy(loadbuf, buf, len);
+ }
+
+ if (image_type == IH_TYPE_RAMDISK && comp != IH_COMP_NONE)
+ puts("WARNING: 'compression' nodes for ramdisks are deprecated,"
+ " please fix your .its file!\n");
+
+ /* verify that image data is a proper FDT blob */
+ if (image_type == IH_TYPE_FLATDT && fdt_check_header(loadbuf)) {
+ puts("Subimage data is not a FDT");
+ return -ENOEXEC;
+ }
+
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD);
+
+ *datap = load;
+ *lenp = len;
+ if (fit_unamep)
+ *fit_unamep = (char *)fit_uname;
+ if (fit_uname_configp)
+ *fit_uname_configp = (char *)(fit_uname_config ? :
+ fit_base_uname_config);
+
+ return noffset;
+}
+
+int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
+ ulong *setup_start, ulong *setup_len)
+{
+ int noffset;
+ ulong addr;
+ ulong len;
+ int ret;
+
+ addr = map_to_sysmem(images->fit_hdr_os);
+ noffset = fit_get_node_from_config(images, FIT_SETUP_PROP, addr);
+ if (noffset < 0)
+ return noffset;
+
+ ret = fit_image_load(images, addr, NULL, NULL, arch,
+ IH_TYPE_X86_SETUP, BOOTSTAGE_ID_FIT_SETUP_START,
+ FIT_LOAD_REQUIRED, setup_start, &len);
+
+ return ret;
+}
+
+#ifndef USE_HOSTCC
+int boot_get_fdt_fit(bootm_headers_t *images, ulong addr,
+ const char **fit_unamep, const char **fit_uname_configp,
+ int arch, ulong *datap, ulong *lenp)
+{
+ int fdt_noffset, cfg_noffset, count;
+ const void *fit;
+ const char *fit_uname = NULL;
+ const char *fit_uname_config = NULL;
+ char *fit_uname_config_copy = NULL;
+ char *next_config = NULL;
+ ulong load, len;
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+ ulong image_start, image_end;
+ ulong ovload, ovlen;
+ const char *uconfig;
+ const char *uname;
+ void *base, *ov;
+ int i, err, noffset, ov_noffset;
+#endif
+
+ fit_uname = fit_unamep ? *fit_unamep : NULL;
+
+ if (fit_uname_configp && *fit_uname_configp) {
+ fit_uname_config_copy = strdup(*fit_uname_configp);
+ if (!fit_uname_config_copy)
+ return -ENOMEM;
+
+ next_config = strchr(fit_uname_config_copy, '#');
+ if (next_config)
+ *next_config++ = '\0';
+ if (next_config - 1 > fit_uname_config_copy)
+ fit_uname_config = fit_uname_config_copy;
+ }
+
+ fdt_noffset = fit_image_load(images,
+ addr, &fit_uname, &fit_uname_config,
+ arch, IH_TYPE_FLATDT,
+ BOOTSTAGE_ID_FIT_FDT_START,
+ FIT_LOAD_OPTIONAL, &load, &len);
+
+ if (fdt_noffset < 0)
+ goto out;
+
+ debug("fit_uname=%s, fit_uname_config=%s\n",
+ fit_uname ? fit_uname : "<NULL>",
+ fit_uname_config ? fit_uname_config : "<NULL>");
+
+ fit = map_sysmem(addr, 0);
+
+ cfg_noffset = fit_conf_get_node(fit, fit_uname_config);
+
+ /* single blob, or error just return as well */
+ count = fit_conf_get_prop_node_count(fit, cfg_noffset, FIT_FDT_PROP);
+ if (count <= 1 && !next_config)
+ goto out;
+
+ /* we need to apply overlays */
+
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+ image_start = addr;
+ image_end = addr + fit_get_size(fit);
+ /* verify that relocation took place by load address not being in fit */
+ if (load >= image_start && load < image_end) {
+ /* check is simplified; fit load checks for overlaps */
+ printf("Overlayed FDT requires relocation\n");
+ fdt_noffset = -EBADF;
+ goto out;
+ }
+
+ base = map_sysmem(load, len);
+
+ /* apply extra configs in FIT first, followed by args */
+ for (i = 1; ; i++) {
+ if (i < count) {
+ noffset = fit_conf_get_prop_node_index(fit, cfg_noffset,
+ FIT_FDT_PROP, i);
+ uname = fit_get_name(fit, noffset, NULL);
+ uconfig = NULL;
+ } else {
+ if (!next_config)
+ break;
+ uconfig = next_config;
+ next_config = strchr(next_config, '#');
+ if (next_config)
+ *next_config++ = '\0';
+ uname = NULL;
+
+ /*
+ * fit_image_load() would load the first FDT from the
+ * extra config only when uconfig is specified.
+ * Check if the extra config contains multiple FDTs and
+ * if so, load them.
+ */
+ cfg_noffset = fit_conf_get_node(fit, uconfig);
+
+ i = 0;
+ count = fit_conf_get_prop_node_count(fit, cfg_noffset,
+ FIT_FDT_PROP);
+ }
+
+ debug("%d: using uname=%s uconfig=%s\n", i, uname, uconfig);
+
+ ov_noffset = fit_image_load(images,
+ addr, &uname, &uconfig,
+ arch, IH_TYPE_FLATDT,
+ BOOTSTAGE_ID_FIT_FDT_START,
+ FIT_LOAD_REQUIRED, &ovload, &ovlen);
+ if (ov_noffset < 0) {
+ printf("load of %s failed\n", uname);
+ continue;
+ }
+ debug("%s loaded at 0x%08lx len=0x%08lx\n",
+ uname, ovload, ovlen);
+ ov = map_sysmem(ovload, ovlen);
+
+ base = map_sysmem(load, len + ovlen);
+ err = fdt_open_into(base, base, len + ovlen);
+ if (err < 0) {
+ printf("failed on fdt_open_into\n");
+ fdt_noffset = err;
+ goto out;
+ }
+ /* the verbose method prints out messages on error */
+ err = fdt_overlay_apply_verbose(base, ov);
+ if (err < 0) {
+ fdt_noffset = err;
+ goto out;
+ }
+ fdt_pack(base);
+ len = fdt_totalsize(base);
+ }
+#else
+ printf("config with overlays but CONFIG_OF_LIBFDT_OVERLAY not set\n");
+ fdt_noffset = -EBADF;
+#endif
+
+out:
+ if (datap)
+ *datap = load;
+ if (lenp)
+ *lenp = len;
+ if (fit_unamep)
+ *fit_unamep = fit_uname;
+ if (fit_uname_configp)
+ *fit_uname_configp = fit_uname_config;
+
+ if (fit_uname_config_copy)
+ free(fit_uname_config_copy);
+ return fdt_noffset;
+}
+#endif
diff --git a/roms/u-boot/common/image-sig.c b/roms/u-boot/common/image-sig.c
new file mode 100644
index 000000000..0f8e592ab
--- /dev/null
+++ b/roms/u-boot/common/image-sig.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013, Google Inc.
+ */
+
+#ifdef USE_HOSTCC
+#include "mkimage.h"
+#include <fdt_support.h>
+#include <time.h>
+#include <linux/libfdt.h>
+#else
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* !USE_HOSTCC*/
+#include <image.h>
+#include <u-boot/ecdsa.h>
+#include <u-boot/rsa.h>
+#include <u-boot/hash-checksum.h>
+
+#define IMAGE_MAX_HASHED_NODES 100
+
+struct checksum_algo checksum_algos[] = {
+ {
+ .name = "sha1",
+ .checksum_len = SHA1_SUM_LEN,
+ .der_len = SHA1_DER_LEN,
+ .der_prefix = sha1_der_prefix,
+#if IMAGE_ENABLE_SIGN
+ .calculate_sign = EVP_sha1,
+#endif
+ .calculate = hash_calculate,
+ },
+ {
+ .name = "sha256",
+ .checksum_len = SHA256_SUM_LEN,
+ .der_len = SHA256_DER_LEN,
+ .der_prefix = sha256_der_prefix,
+#if IMAGE_ENABLE_SIGN
+ .calculate_sign = EVP_sha256,
+#endif
+ .calculate = hash_calculate,
+ },
+#ifdef CONFIG_SHA384
+ {
+ .name = "sha384",
+ .checksum_len = SHA384_SUM_LEN,
+ .der_len = SHA384_DER_LEN,
+ .der_prefix = sha384_der_prefix,
+#if IMAGE_ENABLE_SIGN
+ .calculate_sign = EVP_sha384,
+#endif
+ .calculate = hash_calculate,
+ },
+#endif
+#ifdef CONFIG_SHA512
+ {
+ .name = "sha512",
+ .checksum_len = SHA512_SUM_LEN,
+ .der_len = SHA512_DER_LEN,
+ .der_prefix = sha512_der_prefix,
+#if IMAGE_ENABLE_SIGN
+ .calculate_sign = EVP_sha512,
+#endif
+ .calculate = hash_calculate,
+ },
+#endif
+
+};
+
+struct crypto_algo crypto_algos[] = {
+ {
+ .name = "rsa2048",
+ .key_len = RSA2048_BYTES,
+ .sign = rsa_sign,
+ .add_verify_data = rsa_add_verify_data,
+ .verify = rsa_verify,
+ },
+ {
+ .name = "rsa4096",
+ .key_len = RSA4096_BYTES,
+ .sign = rsa_sign,
+ .add_verify_data = rsa_add_verify_data,
+ .verify = rsa_verify,
+ },
+ {
+ .name = "ecdsa256",
+ .key_len = ECDSA256_BYTES,
+ .sign = ecdsa_sign,
+ .add_verify_data = ecdsa_add_verify_data,
+ .verify = ecdsa_verify,
+ },
+};
+
+struct padding_algo padding_algos[] = {
+ {
+ .name = "pkcs-1.5",
+ .verify = padding_pkcs_15_verify,
+ },
+#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT
+ {
+ .name = "pss",
+ .verify = padding_pss_verify,
+ }
+#endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */
+};
+
+struct checksum_algo *image_get_checksum_algo(const char *full_name)
+{
+ int i;
+ const char *name;
+
+#if !defined(USE_HOSTCC) && defined(CONFIG_NEEDS_MANUAL_RELOC)
+ static bool done;
+
+ if (!done) {
+ done = true;
+ for (i = 0; i < ARRAY_SIZE(checksum_algos); i++) {
+ checksum_algos[i].name += gd->reloc_off;
+#if IMAGE_ENABLE_SIGN
+ checksum_algos[i].calculate_sign += gd->reloc_off;
+#endif
+ checksum_algos[i].calculate += gd->reloc_off;
+ }
+ }
+#endif
+
+ for (i = 0; i < ARRAY_SIZE(checksum_algos); i++) {
+ name = checksum_algos[i].name;
+ /* Make sure names match and next char is a comma */
+ if (!strncmp(name, full_name, strlen(name)) &&
+ full_name[strlen(name)] == ',')
+ return &checksum_algos[i];
+ }
+
+ return NULL;
+}
+
+struct crypto_algo *image_get_crypto_algo(const char *full_name)
+{
+ int i;
+ const char *name;
+
+#if !defined(USE_HOSTCC) && defined(CONFIG_NEEDS_MANUAL_RELOC)
+ static bool done;
+
+ if (!done) {
+ done = true;
+ for (i = 0; i < ARRAY_SIZE(crypto_algos); i++) {
+ crypto_algos[i].name += gd->reloc_off;
+ crypto_algos[i].sign += gd->reloc_off;
+ crypto_algos[i].add_verify_data += gd->reloc_off;
+ crypto_algos[i].verify += gd->reloc_off;
+ }
+ }
+#endif
+
+ /* Move name to after the comma */
+ name = strchr(full_name, ',');
+ if (!name)
+ return NULL;
+ name += 1;
+
+ for (i = 0; i < ARRAY_SIZE(crypto_algos); i++) {
+ if (!strcmp(crypto_algos[i].name, name))
+ return &crypto_algos[i];
+ }
+
+ return NULL;
+}
+
+struct padding_algo *image_get_padding_algo(const char *name)
+{
+ int i;
+
+ if (!name)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(padding_algos); i++) {
+ if (!strcmp(padding_algos[i].name, name))
+ return &padding_algos[i];
+ }
+
+ return NULL;
+}
diff --git a/roms/u-boot/common/image.c b/roms/u-boot/common/image.c
new file mode 100644
index 000000000..51854aae5
--- /dev/null
+++ b/roms/u-boot/common/image.c
@@ -0,0 +1,1753 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#ifndef USE_HOSTCC
+#include <common.h>
+#include <bootstage.h>
+#include <cpu_func.h>
+#include <env.h>
+#include <lmb.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/cache.h>
+#include <u-boot/crc.h>
+#include <watchdog.h>
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+#include <status_led.h>
+#endif
+
+#include <rtc.h>
+
+#include <gzip.h>
+#include <image.h>
+#include <lz4.h>
+#include <mapmem.h>
+
+#if IMAGE_ENABLE_FIT || IMAGE_ENABLE_OF_LIBFDT
+#include <linux/libfdt.h>
+#include <fdt_support.h>
+#include <fpga.h>
+#include <xilinx.h>
+#endif
+
+#include <asm/global_data.h>
+#include <u-boot/md5.h>
+#include <u-boot/sha1.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+
+#include <bzlib.h>
+#include <linux/lzo.h>
+#include <lzma/LzmaTypes.h>
+#include <lzma/LzmaDec.h>
+#include <lzma/LzmaTools.h>
+#include <linux/zstd.h>
+
+#ifdef CONFIG_CMD_BDI
+extern int do_bdinfo(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[]);
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
+ int verify);
+#endif
+#else
+#include "mkimage.h"
+#include <u-boot/md5.h>
+#include <time.h>
+#include <image.h>
+
+#ifndef __maybe_unused
+# define __maybe_unused /* unimplemented */
+#endif
+#endif /* !USE_HOSTCC*/
+
+#include <u-boot/crc.h>
+#include <imximage.h>
+
+#ifndef CONFIG_SYS_BARGSIZE
+#define CONFIG_SYS_BARGSIZE 512
+#endif
+
+static const table_entry_t uimage_arch[] = {
+ { IH_ARCH_INVALID, "invalid", "Invalid ARCH", },
+ { IH_ARCH_ALPHA, "alpha", "Alpha", },
+ { IH_ARCH_ARM, "arm", "ARM", },
+ { IH_ARCH_I386, "x86", "Intel x86", },
+ { IH_ARCH_IA64, "ia64", "IA64", },
+ { IH_ARCH_M68K, "m68k", "M68K", },
+ { IH_ARCH_MICROBLAZE, "microblaze", "MicroBlaze", },
+ { IH_ARCH_MIPS, "mips", "MIPS", },
+ { IH_ARCH_MIPS64, "mips64", "MIPS 64 Bit", },
+ { IH_ARCH_NIOS2, "nios2", "NIOS II", },
+ { IH_ARCH_PPC, "powerpc", "PowerPC", },
+ { IH_ARCH_PPC, "ppc", "PowerPC", },
+ { IH_ARCH_S390, "s390", "IBM S390", },
+ { IH_ARCH_SH, "sh", "SuperH", },
+ { IH_ARCH_SPARC, "sparc", "SPARC", },
+ { IH_ARCH_SPARC64, "sparc64", "SPARC 64 Bit", },
+ { IH_ARCH_BLACKFIN, "blackfin", "Blackfin", },
+ { IH_ARCH_AVR32, "avr32", "AVR32", },
+ { IH_ARCH_NDS32, "nds32", "NDS32", },
+ { IH_ARCH_OPENRISC, "or1k", "OpenRISC 1000",},
+ { IH_ARCH_SANDBOX, "sandbox", "Sandbox", },
+ { IH_ARCH_ARM64, "arm64", "AArch64", },
+ { IH_ARCH_ARC, "arc", "ARC", },
+ { IH_ARCH_X86_64, "x86_64", "AMD x86_64", },
+ { IH_ARCH_XTENSA, "xtensa", "Xtensa", },
+ { IH_ARCH_RISCV, "riscv", "RISC-V", },
+ { -1, "", "", },
+};
+
+static const table_entry_t uimage_os[] = {
+ { IH_OS_INVALID, "invalid", "Invalid OS", },
+ { IH_OS_ARM_TRUSTED_FIRMWARE, "arm-trusted-firmware", "ARM Trusted Firmware" },
+ { IH_OS_LINUX, "linux", "Linux", },
+#if defined(CONFIG_LYNXKDI) || defined(USE_HOSTCC)
+ { IH_OS_LYNXOS, "lynxos", "LynxOS", },
+#endif
+ { IH_OS_NETBSD, "netbsd", "NetBSD", },
+ { IH_OS_OSE, "ose", "Enea OSE", },
+ { IH_OS_PLAN9, "plan9", "Plan 9", },
+ { IH_OS_RTEMS, "rtems", "RTEMS", },
+ { IH_OS_TEE, "tee", "Trusted Execution Environment" },
+ { IH_OS_U_BOOT, "u-boot", "U-Boot", },
+ { IH_OS_VXWORKS, "vxworks", "VxWorks", },
+#if defined(CONFIG_CMD_ELF) || defined(USE_HOSTCC)
+ { IH_OS_QNX, "qnx", "QNX", },
+#endif
+#if defined(CONFIG_INTEGRITY) || defined(USE_HOSTCC)
+ { IH_OS_INTEGRITY,"integrity", "INTEGRITY", },
+#endif
+#ifdef USE_HOSTCC
+ { IH_OS_4_4BSD, "4_4bsd", "4_4BSD", },
+ { IH_OS_DELL, "dell", "Dell", },
+ { IH_OS_ESIX, "esix", "Esix", },
+ { IH_OS_FREEBSD, "freebsd", "FreeBSD", },
+ { IH_OS_IRIX, "irix", "Irix", },
+ { IH_OS_NCR, "ncr", "NCR", },
+ { IH_OS_OPENBSD, "openbsd", "OpenBSD", },
+ { IH_OS_PSOS, "psos", "pSOS", },
+ { IH_OS_SCO, "sco", "SCO", },
+ { IH_OS_SOLARIS, "solaris", "Solaris", },
+ { IH_OS_SVR4, "svr4", "SVR4", },
+#endif
+#if defined(CONFIG_BOOTM_OPENRTOS) || defined(USE_HOSTCC)
+ { IH_OS_OPENRTOS, "openrtos", "OpenRTOS", },
+#endif
+ { IH_OS_OPENSBI, "opensbi", "RISC-V OpenSBI", },
+ { IH_OS_EFI, "efi", "EFI Firmware" },
+
+ { -1, "", "", },
+};
+
+static const table_entry_t uimage_type[] = {
+ { IH_TYPE_AISIMAGE, "aisimage", "Davinci AIS image",},
+ { IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image", },
+ { IH_TYPE_FIRMWARE, "firmware", "Firmware", },
+ { IH_TYPE_FLATDT, "flat_dt", "Flat Device Tree", },
+ { IH_TYPE_GPIMAGE, "gpimage", "TI Keystone SPL Image",},
+ { IH_TYPE_KERNEL, "kernel", "Kernel Image", },
+ { IH_TYPE_KERNEL_NOLOAD, "kernel_noload", "Kernel Image (no loading done)", },
+ { IH_TYPE_KWBIMAGE, "kwbimage", "Kirkwood Boot Image",},
+ { IH_TYPE_IMXIMAGE, "imximage", "Freescale i.MX Boot Image",},
+ { IH_TYPE_IMX8IMAGE, "imx8image", "NXP i.MX8 Boot Image",},
+ { IH_TYPE_IMX8MIMAGE, "imx8mimage", "NXP i.MX8M Boot Image",},
+ { IH_TYPE_INVALID, "invalid", "Invalid Image", },
+ { IH_TYPE_MULTI, "multi", "Multi-File Image", },
+ { IH_TYPE_OMAPIMAGE, "omapimage", "TI OMAP SPL With GP CH",},
+ { IH_TYPE_PBLIMAGE, "pblimage", "Freescale PBL Boot Image",},
+ { IH_TYPE_RAMDISK, "ramdisk", "RAMDisk Image", },
+ { IH_TYPE_SCRIPT, "script", "Script", },
+ { IH_TYPE_SOCFPGAIMAGE, "socfpgaimage", "Altera SoCFPGA CV/AV preloader",},
+ { IH_TYPE_SOCFPGAIMAGE_V1, "socfpgaimage_v1", "Altera SoCFPGA A10 preloader",},
+ { IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
+ { IH_TYPE_UBLIMAGE, "ublimage", "Davinci UBL image",},
+ { IH_TYPE_MXSIMAGE, "mxsimage", "Freescale MXS Boot Image",},
+ { IH_TYPE_ATMELIMAGE, "atmelimage", "ATMEL ROM-Boot Image",},
+ { IH_TYPE_X86_SETUP, "x86_setup", "x86 setup.bin", },
+ { IH_TYPE_LPC32XXIMAGE, "lpc32xximage", "LPC32XX Boot Image", },
+ { IH_TYPE_RKIMAGE, "rkimage", "Rockchip Boot Image" },
+ { IH_TYPE_RKSD, "rksd", "Rockchip SD Boot Image" },
+ { IH_TYPE_RKSPI, "rkspi", "Rockchip SPI Boot Image" },
+ { IH_TYPE_VYBRIDIMAGE, "vybridimage", "Vybrid Boot Image", },
+ { IH_TYPE_ZYNQIMAGE, "zynqimage", "Xilinx Zynq Boot Image" },
+ { IH_TYPE_ZYNQMPIMAGE, "zynqmpimage", "Xilinx ZynqMP Boot Image" },
+ { IH_TYPE_ZYNQMPBIF, "zynqmpbif", "Xilinx ZynqMP Boot Image (bif)" },
+ { IH_TYPE_FPGA, "fpga", "FPGA Image" },
+ { IH_TYPE_TEE, "tee", "Trusted Execution Environment Image",},
+ { IH_TYPE_FIRMWARE_IVT, "firmware_ivt", "Firmware with HABv4 IVT" },
+ { IH_TYPE_PMMC, "pmmc", "TI Power Management Micro-Controller Firmware",},
+ { IH_TYPE_STM32IMAGE, "stm32image", "STMicroelectronics STM32 Image" },
+ { IH_TYPE_MTKIMAGE, "mtk_image", "MediaTek BootROM loadable Image" },
+ { IH_TYPE_COPRO, "copro", "Coprocessor Image"},
+ { IH_TYPE_SUNXI_EGON, "sunxi_egon", "Allwinner eGON Boot Image" },
+ { -1, "", "", },
+};
+
+static const table_entry_t uimage_comp[] = {
+ { IH_COMP_NONE, "none", "uncompressed", },
+ { IH_COMP_BZIP2, "bzip2", "bzip2 compressed", },
+ { IH_COMP_GZIP, "gzip", "gzip compressed", },
+ { IH_COMP_LZMA, "lzma", "lzma compressed", },
+ { IH_COMP_LZO, "lzo", "lzo compressed", },
+ { IH_COMP_LZ4, "lz4", "lz4 compressed", },
+ { IH_COMP_ZSTD, "zstd", "zstd compressed", },
+ { -1, "", "", },
+};
+
+struct table_info {
+ const char *desc;
+ int count;
+ const table_entry_t *table;
+};
+
+static const struct comp_magic_map image_comp[] = {
+ { IH_COMP_BZIP2, "bzip2", {0x42, 0x5a},},
+ { IH_COMP_GZIP, "gzip", {0x1f, 0x8b},},
+ { IH_COMP_LZMA, "lzma", {0x5d, 0x00},},
+ { IH_COMP_LZO, "lzo", {0x89, 0x4c},},
+ { IH_COMP_NONE, "none", {}, },
+};
+
+static const struct table_info table_info[IH_COUNT] = {
+ { "architecture", IH_ARCH_COUNT, uimage_arch },
+ { "compression", IH_COMP_COUNT, uimage_comp },
+ { "operating system", IH_OS_COUNT, uimage_os },
+ { "image type", IH_TYPE_COUNT, uimage_type },
+};
+
+/*****************************************************************************/
+/* Legacy format routines */
+/*****************************************************************************/
+int image_check_hcrc(const image_header_t *hdr)
+{
+ ulong hcrc;
+ ulong len = image_get_header_size();
+ image_header_t header;
+
+ /* Copy header so we can blank CRC field for re-calculation */
+ memmove(&header, (char *)hdr, image_get_header_size());
+ image_set_hcrc(&header, 0);
+
+ hcrc = crc32(0, (unsigned char *)&header, len);
+
+ return (hcrc == image_get_hcrc(hdr));
+}
+
+int image_check_dcrc(const image_header_t *hdr)
+{
+ ulong data = image_get_data(hdr);
+ ulong len = image_get_data_size(hdr);
+ ulong dcrc = crc32_wd(0, (unsigned char *)data, len, CHUNKSZ_CRC32);
+
+ return (dcrc == image_get_dcrc(hdr));
+}
+
+/**
+ * image_multi_count - get component (sub-image) count
+ * @hdr: pointer to the header of the multi component image
+ *
+ * image_multi_count() returns number of components in a multi
+ * component image.
+ *
+ * Note: no checking of the image type is done, caller must pass
+ * a valid multi component image.
+ *
+ * returns:
+ * number of components
+ */
+ulong image_multi_count(const image_header_t *hdr)
+{
+ ulong i, count = 0;
+ uint32_t *size;
+
+ /* get start of the image payload, which in case of multi
+ * component images that points to a table of component sizes */
+ size = (uint32_t *)image_get_data(hdr);
+
+ /* count non empty slots */
+ for (i = 0; size[i]; ++i)
+ count++;
+
+ return count;
+}
+
+/**
+ * image_multi_getimg - get component data address and size
+ * @hdr: pointer to the header of the multi component image
+ * @idx: index of the requested component
+ * @data: pointer to a ulong variable, will hold component data address
+ * @len: pointer to a ulong variable, will hold component size
+ *
+ * image_multi_getimg() returns size and data address for the requested
+ * component in a multi component image.
+ *
+ * Note: no checking of the image type is done, caller must pass
+ * a valid multi component image.
+ *
+ * returns:
+ * data address and size of the component, if idx is valid
+ * 0 in data and len, if idx is out of range
+ */
+void image_multi_getimg(const image_header_t *hdr, ulong idx,
+ ulong *data, ulong *len)
+{
+ int i;
+ uint32_t *size;
+ ulong offset, count, img_data;
+
+ /* get number of component */
+ count = image_multi_count(hdr);
+
+ /* get start of the image payload, which in case of multi
+ * component images that points to a table of component sizes */
+ size = (uint32_t *)image_get_data(hdr);
+
+ /* get address of the proper component data start, which means
+ * skipping sizes table (add 1 for last, null entry) */
+ img_data = image_get_data(hdr) + (count + 1) * sizeof(uint32_t);
+
+ if (idx < count) {
+ *len = uimage_to_cpu(size[idx]);
+ offset = 0;
+
+ /* go over all indices preceding requested component idx */
+ for (i = 0; i < idx; i++) {
+ /* add up i-th component size, rounding up to 4 bytes */
+ offset += (uimage_to_cpu(size[i]) + 3) & ~3 ;
+ }
+
+ /* calculate idx-th component data address */
+ *data = img_data + offset;
+ } else {
+ *len = 0;
+ *data = 0;
+ }
+}
+
+static void image_print_type(const image_header_t *hdr)
+{
+ const char __maybe_unused *os, *arch, *type, *comp;
+
+ os = genimg_get_os_name(image_get_os(hdr));
+ arch = genimg_get_arch_name(image_get_arch(hdr));
+ type = genimg_get_type_name(image_get_type(hdr));
+ comp = genimg_get_comp_name(image_get_comp(hdr));
+
+ printf("%s %s %s (%s)\n", arch, os, type, comp);
+}
+
+/**
+ * image_print_contents - prints out the contents of the legacy format image
+ * @ptr: pointer to the legacy format image header
+ * @p: pointer to prefix string
+ *
+ * image_print_contents() formats a multi line legacy image contents description.
+ * The routine prints out all header fields followed by the size/offset data
+ * for MULTI/SCRIPT images.
+ *
+ * returns:
+ * no returned results
+ */
+void image_print_contents(const void *ptr)
+{
+ const image_header_t *hdr = (const image_header_t *)ptr;
+ const char __maybe_unused *p;
+
+ p = IMAGE_INDENT_STRING;
+ printf("%sImage Name: %.*s\n", p, IH_NMLEN, image_get_name(hdr));
+ if (IMAGE_ENABLE_TIMESTAMP) {
+ printf("%sCreated: ", p);
+ genimg_print_time((time_t)image_get_time(hdr));
+ }
+ printf("%sImage Type: ", p);
+ image_print_type(hdr);
+ printf("%sData Size: ", p);
+ genimg_print_size(image_get_data_size(hdr));
+ printf("%sLoad Address: %08x\n", p, image_get_load(hdr));
+ printf("%sEntry Point: %08x\n", p, image_get_ep(hdr));
+
+ if (image_check_type(hdr, IH_TYPE_MULTI) ||
+ image_check_type(hdr, IH_TYPE_SCRIPT)) {
+ int i;
+ ulong data, len;
+ ulong count = image_multi_count(hdr);
+
+ printf("%sContents:\n", p);
+ for (i = 0; i < count; i++) {
+ image_multi_getimg(hdr, i, &data, &len);
+
+ printf("%s Image %d: ", p, i);
+ genimg_print_size(len);
+
+ if (image_check_type(hdr, IH_TYPE_SCRIPT) && i > 0) {
+ /*
+ * the user may need to know offsets
+ * if planning to do something with
+ * multiple files
+ */
+ printf("%s Offset = 0x%08lx\n", p, data);
+ }
+ }
+ } else if (image_check_type(hdr, IH_TYPE_FIRMWARE_IVT)) {
+ printf("HAB Blocks: 0x%08x 0x0000 0x%08x\n",
+ image_get_load(hdr) - image_get_header_size(),
+ (int)(image_get_size(hdr) + image_get_header_size()
+ + sizeof(flash_header_v2_t) - 0x2060));
+ }
+}
+
+/**
+ * print_decomp_msg() - Print a suitable decompression/loading message
+ *
+ * @type: OS type (IH_OS_...)
+ * @comp_type: Compression type being used (IH_COMP_...)
+ * @is_xip: true if the load address matches the image start
+ */
+static void print_decomp_msg(int comp_type, int type, bool is_xip)
+{
+ const char *name = genimg_get_type_name(type);
+
+ if (comp_type == IH_COMP_NONE)
+ printf(" %s %s\n", is_xip ? "XIP" : "Loading", name);
+ else
+ printf(" Uncompressing %s\n", name);
+}
+
+int image_decomp_type(const unsigned char *buf, ulong len)
+{
+ const struct comp_magic_map *cmagic = image_comp;
+
+ if (len < 2)
+ return -EINVAL;
+
+ for (; cmagic->comp_id > 0; cmagic++) {
+ if (!memcmp(buf, cmagic->magic, 2))
+ break;
+ }
+
+ return cmagic->comp_id;
+}
+
+int image_decomp(int comp, ulong load, ulong image_start, int type,
+ void *load_buf, void *image_buf, ulong image_len,
+ uint unc_len, ulong *load_end)
+{
+ int ret = 0;
+
+ *load_end = load;
+ print_decomp_msg(comp, type, load == image_start);
+
+ /*
+ * Load the image to the right place, decompressing if needed. After
+ * this, image_len will be set to the number of uncompressed bytes
+ * loaded, ret will be non-zero on error.
+ */
+ switch (comp) {
+ case IH_COMP_NONE:
+ if (load == image_start)
+ break;
+ if (image_len <= unc_len)
+ memmove_wd(load_buf, image_buf, image_len, CHUNKSZ);
+ else
+ ret = -ENOSPC;
+ break;
+#ifndef USE_HOSTCC
+#if CONFIG_IS_ENABLED(GZIP)
+ case IH_COMP_GZIP: {
+ ret = gunzip(load_buf, unc_len, image_buf, &image_len);
+ break;
+ }
+#endif /* CONFIG_GZIP */
+#endif
+#ifndef USE_HOSTCC
+#if CONFIG_IS_ENABLED(BZIP2)
+ case IH_COMP_BZIP2: {
+ uint size = unc_len;
+
+ /*
+ * If we've got less than 4 MB of malloc() space,
+ * use slower decompression algorithm which requires
+ * at most 2300 KB of memory.
+ */
+ ret = BZ2_bzBuffToBuffDecompress(load_buf, &size,
+ image_buf, image_len,
+ CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);
+ image_len = size;
+ break;
+ }
+#endif /* CONFIG_BZIP2 */
+#endif
+#ifndef USE_HOSTCC
+#if CONFIG_IS_ENABLED(LZMA)
+ case IH_COMP_LZMA: {
+ SizeT lzma_len = unc_len;
+
+ ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len,
+ image_buf, image_len);
+ image_len = lzma_len;
+ break;
+ }
+#endif /* CONFIG_LZMA */
+#endif
+#ifndef USE_HOSTCC
+#if CONFIG_IS_ENABLED(LZO)
+ case IH_COMP_LZO: {
+ size_t size = unc_len;
+
+ ret = lzop_decompress(image_buf, image_len, load_buf, &size);
+ image_len = size;
+ break;
+ }
+#endif /* CONFIG_LZO */
+#endif
+#ifndef USE_HOSTCC
+#if CONFIG_IS_ENABLED(LZ4)
+ case IH_COMP_LZ4: {
+ size_t size = unc_len;
+
+ ret = ulz4fn(image_buf, image_len, load_buf, &size);
+ image_len = size;
+ break;
+ }
+#endif /* CONFIG_LZ4 */
+#endif
+#ifndef USE_HOSTCC
+#if CONFIG_IS_ENABLED(ZSTD)
+ case IH_COMP_ZSTD: {
+ size_t size = unc_len;
+ ZSTD_DStream *dstream;
+ ZSTD_inBuffer in_buf;
+ ZSTD_outBuffer out_buf;
+ void *workspace;
+ size_t wsize;
+
+ wsize = ZSTD_DStreamWorkspaceBound(image_len);
+ workspace = malloc(wsize);
+ if (!workspace) {
+ debug("%s: cannot allocate workspace of size %zu\n", __func__,
+ wsize);
+ return -1;
+ }
+
+ dstream = ZSTD_initDStream(image_len, workspace, wsize);
+ if (!dstream) {
+ printf("%s: ZSTD_initDStream failed\n", __func__);
+ return ZSTD_getErrorCode(ret);
+ }
+
+ in_buf.src = image_buf;
+ in_buf.pos = 0;
+ in_buf.size = image_len;
+
+ out_buf.dst = load_buf;
+ out_buf.pos = 0;
+ out_buf.size = size;
+
+ while (1) {
+ size_t ret;
+
+ ret = ZSTD_decompressStream(dstream, &out_buf, &in_buf);
+ if (ZSTD_isError(ret)) {
+ printf("%s: ZSTD_decompressStream error %d\n", __func__,
+ ZSTD_getErrorCode(ret));
+ return ZSTD_getErrorCode(ret);
+ }
+
+ if (in_buf.pos >= image_len || !ret)
+ break;
+ }
+
+ image_len = out_buf.pos;
+
+ break;
+ }
+#endif /* CONFIG_ZSTD */
+#endif
+ default:
+ printf("Unimplemented compression type %d\n", comp);
+ return -ENOSYS;
+ }
+
+ *load_end = load + image_len;
+
+ return ret;
+}
+
+
+#ifndef USE_HOSTCC
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+/**
+ * image_get_ramdisk - get and verify ramdisk image
+ * @rd_addr: ramdisk image start address
+ * @arch: expected ramdisk architecture
+ * @verify: checksum verification flag
+ *
+ * image_get_ramdisk() returns a pointer to the verified ramdisk image
+ * header. Routine receives image start address and expected architecture
+ * flag. Verification done covers data and header integrity and os/type/arch
+ * fields checking.
+ *
+ * returns:
+ * pointer to a ramdisk image header, if image was found and valid
+ * otherwise, return NULL
+ */
+static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
+ int verify)
+{
+ const image_header_t *rd_hdr = (const image_header_t *)rd_addr;
+
+ if (!image_check_magic(rd_hdr)) {
+ puts("Bad Magic Number\n");
+ bootstage_error(BOOTSTAGE_ID_RD_MAGIC);
+ return NULL;
+ }
+
+ if (!image_check_hcrc(rd_hdr)) {
+ puts("Bad Header Checksum\n");
+ bootstage_error(BOOTSTAGE_ID_RD_HDR_CHECKSUM);
+ return NULL;
+ }
+
+ bootstage_mark(BOOTSTAGE_ID_RD_MAGIC);
+ image_print_contents(rd_hdr);
+
+ if (verify) {
+ puts(" Verifying Checksum ... ");
+ if (!image_check_dcrc(rd_hdr)) {
+ puts("Bad Data CRC\n");
+ bootstage_error(BOOTSTAGE_ID_RD_CHECKSUM);
+ return NULL;
+ }
+ puts("OK\n");
+ }
+
+ bootstage_mark(BOOTSTAGE_ID_RD_HDR_CHECKSUM);
+
+ if (!image_check_os(rd_hdr, IH_OS_LINUX) ||
+ !image_check_arch(rd_hdr, arch) ||
+ !image_check_type(rd_hdr, IH_TYPE_RAMDISK)) {
+ printf("No Linux %s Ramdisk Image\n",
+ genimg_get_arch_name(arch));
+ bootstage_error(BOOTSTAGE_ID_RAMDISK);
+ return NULL;
+ }
+
+ return rd_hdr;
+}
+#endif
+#endif /* !USE_HOSTCC */
+
+/*****************************************************************************/
+/* Shared dual-format routines */
+/*****************************************************************************/
+#ifndef USE_HOSTCC
+ulong image_load_addr = CONFIG_SYS_LOAD_ADDR; /* Default Load Address */
+ulong image_save_addr; /* Default Save Address */
+ulong image_save_size; /* Default Save Size (in bytes) */
+
+static int on_loadaddr(const char *name, const char *value, enum env_op op,
+ int flags)
+{
+ switch (op) {
+ case env_op_create:
+ case env_op_overwrite:
+ image_load_addr = simple_strtoul(value, NULL, 16);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);
+
+ulong env_get_bootm_low(void)
+{
+ char *s = env_get("bootm_low");
+ if (s) {
+ ulong tmp = simple_strtoul(s, NULL, 16);
+ return tmp;
+ }
+
+#if defined(CONFIG_SYS_SDRAM_BASE)
+ return CONFIG_SYS_SDRAM_BASE;
+#elif defined(CONFIG_ARM) || defined(CONFIG_MICROBLAZE)
+ return gd->bd->bi_dram[0].start;
+#else
+ return 0;
+#endif
+}
+
+phys_size_t env_get_bootm_size(void)
+{
+ phys_size_t tmp, size;
+ phys_addr_t start;
+ char *s = env_get("bootm_size");
+ if (s) {
+ tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
+ return tmp;
+ }
+
+ start = gd->ram_base;
+ size = gd->ram_size;
+
+ if (start + size > gd->ram_top)
+ size = gd->ram_top - start;
+
+ s = env_get("bootm_low");
+ if (s)
+ tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
+ else
+ tmp = start;
+
+ return size - (tmp - start);
+}
+
+phys_size_t env_get_bootm_mapsize(void)
+{
+ phys_size_t tmp;
+ char *s = env_get("bootm_mapsize");
+ if (s) {
+ tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
+ return tmp;
+ }
+
+#if defined(CONFIG_SYS_BOOTMAPSZ)
+ return CONFIG_SYS_BOOTMAPSZ;
+#else
+ return env_get_bootm_size();
+#endif
+}
+
+void memmove_wd(void *to, void *from, size_t len, ulong chunksz)
+{
+ if (to == from)
+ return;
+
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+ if (to > from) {
+ from += len;
+ to += len;
+ }
+ while (len > 0) {
+ size_t tail = (len > chunksz) ? chunksz : len;
+ WATCHDOG_RESET();
+ if (to > from) {
+ to -= tail;
+ from -= tail;
+ }
+ memmove(to, from, tail);
+ if (to < from) {
+ to += tail;
+ from += tail;
+ }
+ len -= tail;
+ }
+#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
+ memmove(to, from, len);
+#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
+}
+#else /* USE_HOSTCC */
+void memmove_wd(void *to, void *from, size_t len, ulong chunksz)
+{
+ memmove(to, from, len);
+}
+#endif /* !USE_HOSTCC */
+
+void genimg_print_size(uint32_t size)
+{
+#ifndef USE_HOSTCC
+ printf("%d Bytes = ", size);
+ print_size(size, "\n");
+#else
+ printf("%d Bytes = %.2f KiB = %.2f MiB\n",
+ size, (double)size / 1.024e3,
+ (double)size / 1.048576e6);
+#endif
+}
+
+#if IMAGE_ENABLE_TIMESTAMP
+void genimg_print_time(time_t timestamp)
+{
+#ifndef USE_HOSTCC
+ struct rtc_time tm;
+
+ rtc_to_tm(timestamp, &tm);
+ printf("%4d-%02d-%02d %2d:%02d:%02d UTC\n",
+ tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+#else
+ printf("%s", ctime(&timestamp));
+#endif
+}
+#endif
+
+const table_entry_t *get_table_entry(const table_entry_t *table, int id)
+{
+ for (; table->id >= 0; ++table) {
+ if (table->id == id)
+ return table;
+ }
+ return NULL;
+}
+
+static const char *unknown_msg(enum ih_category category)
+{
+ static const char unknown_str[] = "Unknown ";
+ static char msg[30];
+
+ strcpy(msg, unknown_str);
+ strncat(msg, table_info[category].desc,
+ sizeof(msg) - sizeof(unknown_str));
+
+ return msg;
+}
+
+/**
+ * genimg_get_cat_name - translate entry id to long name
+ * @category: category to look up (enum ih_category)
+ * @id: entry id to be translated
+ *
+ * This will scan the translation table trying to find the entry that matches
+ * the given id.
+ *
+ * @return long entry name if translation succeeds; error string on failure
+ */
+const char *genimg_get_cat_name(enum ih_category category, uint id)
+{
+ const table_entry_t *entry;
+
+ entry = get_table_entry(table_info[category].table, id);
+ if (!entry)
+ return unknown_msg(category);
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+ return entry->lname;
+#else
+ return entry->lname + gd->reloc_off;
+#endif
+}
+
+/**
+ * genimg_get_cat_short_name - translate entry id to short name
+ * @category: category to look up (enum ih_category)
+ * @id: entry id to be translated
+ *
+ * This will scan the translation table trying to find the entry that matches
+ * the given id.
+ *
+ * @return short entry name if translation succeeds; error string on failure
+ */
+const char *genimg_get_cat_short_name(enum ih_category category, uint id)
+{
+ const table_entry_t *entry;
+
+ entry = get_table_entry(table_info[category].table, id);
+ if (!entry)
+ return unknown_msg(category);
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+ return entry->sname;
+#else
+ return entry->sname + gd->reloc_off;
+#endif
+}
+
+int genimg_get_cat_count(enum ih_category category)
+{
+ return table_info[category].count;
+}
+
+const char *genimg_get_cat_desc(enum ih_category category)
+{
+ return table_info[category].desc;
+}
+
+/**
+ * genimg_cat_has_id - check whether category has entry id
+ * @category: category to look up (enum ih_category)
+ * @id: entry id to be checked
+ *
+ * This will scan the translation table trying to find the entry that matches
+ * the given id.
+ *
+ * @return true if category has entry id; false if not
+ */
+bool genimg_cat_has_id(enum ih_category category, uint id)
+{
+ if (get_table_entry(table_info[category].table, id))
+ return true;
+
+ return false;
+}
+
+/**
+ * get_table_entry_name - translate entry id to long name
+ * @table: pointer to a translation table for entries of a specific type
+ * @msg: message to be returned when translation fails
+ * @id: entry id to be translated
+ *
+ * get_table_entry_name() will go over translation table trying to find
+ * entry that matches given id. If matching entry is found, its long
+ * name is returned to the caller.
+ *
+ * returns:
+ * long entry name if translation succeeds
+ * msg otherwise
+ */
+char *get_table_entry_name(const table_entry_t *table, char *msg, int id)
+{
+ table = get_table_entry(table, id);
+ if (!table)
+ return msg;
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+ return table->lname;
+#else
+ return table->lname + gd->reloc_off;
+#endif
+}
+
+const char *genimg_get_os_name(uint8_t os)
+{
+ return (get_table_entry_name(uimage_os, "Unknown OS", os));
+}
+
+const char *genimg_get_arch_name(uint8_t arch)
+{
+ return (get_table_entry_name(uimage_arch, "Unknown Architecture",
+ arch));
+}
+
+const char *genimg_get_type_name(uint8_t type)
+{
+ return (get_table_entry_name(uimage_type, "Unknown Image", type));
+}
+
+const char *genimg_get_comp_name(uint8_t comp)
+{
+ return (get_table_entry_name(uimage_comp, "Unknown Compression",
+ comp));
+}
+
+static const char *genimg_get_short_name(const table_entry_t *table, int val)
+{
+ table = get_table_entry(table, val);
+ if (!table)
+ return "unknown";
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+ return table->sname;
+#else
+ return table->sname + gd->reloc_off;
+#endif
+}
+
+const char *genimg_get_type_short_name(uint8_t type)
+{
+ return genimg_get_short_name(uimage_type, type);
+}
+
+const char *genimg_get_comp_short_name(uint8_t comp)
+{
+ return genimg_get_short_name(uimage_comp, comp);
+}
+
+const char *genimg_get_os_short_name(uint8_t os)
+{
+ return genimg_get_short_name(uimage_os, os);
+}
+
+const char *genimg_get_arch_short_name(uint8_t arch)
+{
+ return genimg_get_short_name(uimage_arch, arch);
+}
+
+/**
+ * get_table_entry_id - translate short entry name to id
+ * @table: pointer to a translation table for entries of a specific type
+ * @table_name: to be used in case of error
+ * @name: entry short name to be translated
+ *
+ * get_table_entry_id() will go over translation table trying to find
+ * entry that matches given short name. If matching entry is found,
+ * its id returned to the caller.
+ *
+ * returns:
+ * entry id if translation succeeds
+ * -1 otherwise
+ */
+int get_table_entry_id(const table_entry_t *table,
+ const char *table_name, const char *name)
+{
+ const table_entry_t *t;
+
+ for (t = table; t->id >= 0; ++t) {
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ if (t->sname && strcasecmp(t->sname + gd->reloc_off, name) == 0)
+#else
+ if (t->sname && strcasecmp(t->sname, name) == 0)
+#endif
+ return (t->id);
+ }
+ debug("Invalid %s Type: %s\n", table_name, name);
+
+ return -1;
+}
+
+int genimg_get_os_id(const char *name)
+{
+ return (get_table_entry_id(uimage_os, "OS", name));
+}
+
+int genimg_get_arch_id(const char *name)
+{
+ return (get_table_entry_id(uimage_arch, "CPU", name));
+}
+
+int genimg_get_type_id(const char *name)
+{
+ return (get_table_entry_id(uimage_type, "Image", name));
+}
+
+int genimg_get_comp_id(const char *name)
+{
+ return (get_table_entry_id(uimage_comp, "Compression", name));
+}
+
+#ifndef USE_HOSTCC
+/**
+ * genimg_get_kernel_addr_fit - get the real kernel address and return 2
+ * FIT strings
+ * @img_addr: a string might contain real image address
+ * @fit_uname_config: double pointer to a char, will hold pointer to a
+ * configuration unit name
+ * @fit_uname_kernel: double pointer to a char, will hold pointer to a subimage
+ * name
+ *
+ * genimg_get_kernel_addr_fit get the real kernel start address from a string
+ * which is normally the first argv of bootm/bootz
+ *
+ * returns:
+ * kernel start address
+ */
+ulong genimg_get_kernel_addr_fit(char * const img_addr,
+ const char **fit_uname_config,
+ const char **fit_uname_kernel)
+{
+ ulong kernel_addr;
+
+ /* find out kernel image address */
+ if (!img_addr) {
+ kernel_addr = image_load_addr;
+ debug("* kernel: default image load address = 0x%08lx\n",
+ image_load_addr);
+#if CONFIG_IS_ENABLED(FIT)
+ } else if (fit_parse_conf(img_addr, image_load_addr, &kernel_addr,
+ fit_uname_config)) {
+ debug("* kernel: config '%s' from image at 0x%08lx\n",
+ *fit_uname_config, kernel_addr);
+ } else if (fit_parse_subimage(img_addr, image_load_addr, &kernel_addr,
+ fit_uname_kernel)) {
+ debug("* kernel: subimage '%s' from image at 0x%08lx\n",
+ *fit_uname_kernel, kernel_addr);
+#endif
+ } else {
+ kernel_addr = simple_strtoul(img_addr, NULL, 16);
+ debug("* kernel: cmdline image address = 0x%08lx\n",
+ kernel_addr);
+ }
+
+ return kernel_addr;
+}
+
+/**
+ * genimg_get_kernel_addr() is the simple version of
+ * genimg_get_kernel_addr_fit(). It ignores those return FIT strings
+ */
+ulong genimg_get_kernel_addr(char * const img_addr)
+{
+ const char *fit_uname_config = NULL;
+ const char *fit_uname_kernel = NULL;
+
+ return genimg_get_kernel_addr_fit(img_addr, &fit_uname_config,
+ &fit_uname_kernel);
+}
+
+/**
+ * genimg_get_format - get image format type
+ * @img_addr: image start address
+ *
+ * genimg_get_format() checks whether provided address points to a valid
+ * legacy or FIT image.
+ *
+ * New uImage format and FDT blob are based on a libfdt. FDT blob
+ * may be passed directly or embedded in a FIT image. In both situations
+ * genimg_get_format() must be able to dectect libfdt header.
+ *
+ * returns:
+ * image format type or IMAGE_FORMAT_INVALID if no image is present
+ */
+int genimg_get_format(const void *img_addr)
+{
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+ const image_header_t *hdr;
+
+ hdr = (const image_header_t *)img_addr;
+ if (image_check_magic(hdr))
+ return IMAGE_FORMAT_LEGACY;
+#endif
+#if IMAGE_ENABLE_FIT || IMAGE_ENABLE_OF_LIBFDT
+ if (fdt_check_header(img_addr) == 0)
+ return IMAGE_FORMAT_FIT;
+#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ if (android_image_check_header(img_addr) == 0)
+ return IMAGE_FORMAT_ANDROID;
+#endif
+
+ return IMAGE_FORMAT_INVALID;
+}
+
+/**
+ * fit_has_config - check if there is a valid FIT configuration
+ * @images: pointer to the bootm command headers structure
+ *
+ * fit_has_config() checks if there is a FIT configuration in use
+ * (if FTI support is present).
+ *
+ * returns:
+ * 0, no FIT support or no configuration found
+ * 1, configuration found
+ */
+int genimg_has_config(bootm_headers_t *images)
+{
+#if IMAGE_ENABLE_FIT
+ if (images->fit_uname_cfg)
+ return 1;
+#endif
+ return 0;
+}
+
+/**
+ * boot_get_ramdisk - main ramdisk handling routine
+ * @argc: command argument count
+ * @argv: command argument list
+ * @images: pointer to the bootm images structure
+ * @arch: expected ramdisk architecture
+ * @rd_start: pointer to a ulong variable, will hold ramdisk start address
+ * @rd_end: pointer to a ulong variable, will hold ramdisk end
+ *
+ * boot_get_ramdisk() is responsible for finding a valid ramdisk image.
+ * Curently supported are the following ramdisk sources:
+ * - multicomponent kernel/ramdisk image,
+ * - commandline provided address of decicated ramdisk image.
+ *
+ * returns:
+ * 0, if ramdisk image was found and valid, or skiped
+ * rd_start and rd_end are set to ramdisk start/end addresses if
+ * ramdisk image is found and valid
+ *
+ * 1, if ramdisk image is found but corrupted, or invalid
+ * rd_start and rd_end are set to 0 if no ramdisk exists
+ */
+int boot_get_ramdisk(int argc, char *const argv[], bootm_headers_t *images,
+ uint8_t arch, ulong *rd_start, ulong *rd_end)
+{
+ ulong rd_addr, rd_load;
+ ulong rd_data, rd_len;
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+ const image_header_t *rd_hdr;
+#endif
+ void *buf;
+#ifdef CONFIG_SUPPORT_RAW_INITRD
+ char *end;
+#endif
+#if IMAGE_ENABLE_FIT
+ const char *fit_uname_config = images->fit_uname_cfg;
+ const char *fit_uname_ramdisk = NULL;
+ ulong default_addr;
+ int rd_noffset;
+#endif
+ const char *select = NULL;
+
+ *rd_start = 0;
+ *rd_end = 0;
+
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ /*
+ * Look for an Android boot image.
+ */
+ buf = map_sysmem(images->os.start, 0);
+ if (buf && genimg_get_format(buf) == IMAGE_FORMAT_ANDROID)
+ select = (argc == 0) ? env_get("loadaddr") : argv[0];
+#endif
+
+ if (argc >= 2)
+ select = argv[1];
+
+ /*
+ * Look for a '-' which indicates to ignore the
+ * ramdisk argument
+ */
+ if (select && strcmp(select, "-") == 0) {
+ debug("## Skipping init Ramdisk\n");
+ rd_len = rd_data = 0;
+ } else if (select || genimg_has_config(images)) {
+#if IMAGE_ENABLE_FIT
+ if (select) {
+ /*
+ * If the init ramdisk comes from the FIT image and
+ * the FIT image address is omitted in the command
+ * line argument, try to use os FIT image address or
+ * default load address.
+ */
+ if (images->fit_uname_os)
+ default_addr = (ulong)images->fit_hdr_os;
+ else
+ default_addr = image_load_addr;
+
+ if (fit_parse_conf(select, default_addr,
+ &rd_addr, &fit_uname_config)) {
+ debug("* ramdisk: config '%s' from image at "
+ "0x%08lx\n",
+ fit_uname_config, rd_addr);
+ } else if (fit_parse_subimage(select, default_addr,
+ &rd_addr, &fit_uname_ramdisk)) {
+ debug("* ramdisk: subimage '%s' from image at "
+ "0x%08lx\n",
+ fit_uname_ramdisk, rd_addr);
+ } else
+#endif
+ {
+ rd_addr = simple_strtoul(select, NULL, 16);
+ debug("* ramdisk: cmdline image address = "
+ "0x%08lx\n",
+ rd_addr);
+ }
+#if IMAGE_ENABLE_FIT
+ } else {
+ /* use FIT configuration provided in first bootm
+ * command argument. If the property is not defined,
+ * quit silently.
+ */
+ rd_addr = map_to_sysmem(images->fit_hdr_os);
+ rd_noffset = fit_get_node_from_config(images,
+ FIT_RAMDISK_PROP, rd_addr);
+ if (rd_noffset == -ENOENT)
+ return 0;
+ else if (rd_noffset < 0)
+ return 1;
+ }
+#endif
+
+ /*
+ * Check if there is an initrd image at the
+ * address provided in the second bootm argument
+ * check image type, for FIT images get FIT node.
+ */
+ buf = map_sysmem(rd_addr, 0);
+ switch (genimg_get_format(buf)) {
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
+ case IMAGE_FORMAT_LEGACY:
+ printf("## Loading init Ramdisk from Legacy "
+ "Image at %08lx ...\n", rd_addr);
+
+ bootstage_mark(BOOTSTAGE_ID_CHECK_RAMDISK);
+ rd_hdr = image_get_ramdisk(rd_addr, arch,
+ images->verify);
+
+ if (rd_hdr == NULL)
+ return 1;
+
+ rd_data = image_get_data(rd_hdr);
+ rd_len = image_get_data_size(rd_hdr);
+ rd_load = image_get_load(rd_hdr);
+ break;
+#endif
+#if IMAGE_ENABLE_FIT
+ case IMAGE_FORMAT_FIT:
+ rd_noffset = fit_image_load(images,
+ rd_addr, &fit_uname_ramdisk,
+ &fit_uname_config, arch,
+ IH_TYPE_RAMDISK,
+ BOOTSTAGE_ID_FIT_RD_START,
+ FIT_LOAD_OPTIONAL_NON_ZERO,
+ &rd_data, &rd_len);
+ if (rd_noffset < 0)
+ return 1;
+
+ images->fit_hdr_rd = map_sysmem(rd_addr, 0);
+ images->fit_uname_rd = fit_uname_ramdisk;
+ images->fit_noffset_rd = rd_noffset;
+ break;
+#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ case IMAGE_FORMAT_ANDROID:
+ android_image_get_ramdisk((void *)images->os.start,
+ &rd_data, &rd_len);
+ break;
+#endif
+ default:
+#ifdef CONFIG_SUPPORT_RAW_INITRD
+ end = NULL;
+ if (select)
+ end = strchr(select, ':');
+ if (end) {
+ rd_len = simple_strtoul(++end, NULL, 16);
+ rd_data = rd_addr;
+ } else
+#endif
+ {
+ puts("Wrong Ramdisk Image Format\n");
+ rd_data = rd_len = rd_load = 0;
+ return 1;
+ }
+ }
+ } else if (images->legacy_hdr_valid &&
+ image_check_type(&images->legacy_hdr_os_copy,
+ IH_TYPE_MULTI)) {
+
+ /*
+ * Now check if we have a legacy mult-component image,
+ * get second entry data start address and len.
+ */
+ bootstage_mark(BOOTSTAGE_ID_RAMDISK);
+ printf("## Loading init Ramdisk from multi component "
+ "Legacy Image at %08lx ...\n",
+ (ulong)images->legacy_hdr_os);
+
+ image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
+ } else {
+ /*
+ * no initrd image
+ */
+ bootstage_mark(BOOTSTAGE_ID_NO_RAMDISK);
+ rd_len = rd_data = 0;
+ }
+
+ if (!rd_data) {
+ debug("## No init Ramdisk\n");
+ } else {
+ *rd_start = rd_data;
+ *rd_end = rd_data + rd_len;
+ }
+ debug(" ramdisk start = 0x%08lx, ramdisk end = 0x%08lx\n",
+ *rd_start, *rd_end);
+
+ return 0;
+}
+
+#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
+/**
+ * boot_ramdisk_high - relocate init ramdisk
+ * @lmb: pointer to lmb handle, will be used for memory mgmt
+ * @rd_data: ramdisk data start address
+ * @rd_len: ramdisk data length
+ * @initrd_start: pointer to a ulong variable, will hold final init ramdisk
+ * start address (after possible relocation)
+ * @initrd_end: pointer to a ulong variable, will hold final init ramdisk
+ * end address (after possible relocation)
+ *
+ * boot_ramdisk_high() takes a relocation hint from "initrd_high" environment
+ * variable and if requested ramdisk data is moved to a specified location.
+ *
+ * Initrd_start and initrd_end are set to final (after relocation) ramdisk
+ * start/end addresses if ramdisk image start and len were provided,
+ * otherwise set initrd_start and initrd_end set to zeros.
+ *
+ * returns:
+ * 0 - success
+ * -1 - failure
+ */
+int boot_ramdisk_high(struct lmb *lmb, ulong rd_data, ulong rd_len,
+ ulong *initrd_start, ulong *initrd_end)
+{
+ char *s;
+ ulong initrd_high;
+ int initrd_copy_to_ram = 1;
+
+ s = env_get("initrd_high");
+ if (s) {
+ /* a value of "no" or a similar string will act like 0,
+ * turning the "load high" feature off. This is intentional.
+ */
+ initrd_high = simple_strtoul(s, NULL, 16);
+ if (initrd_high == ~0)
+ initrd_copy_to_ram = 0;
+ } else {
+ initrd_high = env_get_bootm_mapsize() + env_get_bootm_low();
+ }
+
+
+ debug("## initrd_high = 0x%08lx, copy_to_ram = %d\n",
+ initrd_high, initrd_copy_to_ram);
+
+ if (rd_data) {
+ if (!initrd_copy_to_ram) { /* zero-copy ramdisk support */
+ debug(" in-place initrd\n");
+ *initrd_start = rd_data;
+ *initrd_end = rd_data + rd_len;
+ lmb_reserve(lmb, rd_data, rd_len);
+ } else {
+ if (initrd_high)
+ *initrd_start = (ulong)lmb_alloc_base(lmb,
+ rd_len, 0x1000, initrd_high);
+ else
+ *initrd_start = (ulong)lmb_alloc(lmb, rd_len,
+ 0x1000);
+
+ if (*initrd_start == 0) {
+ puts("ramdisk - allocation error\n");
+ goto error;
+ }
+ bootstage_mark(BOOTSTAGE_ID_COPY_RAMDISK);
+
+ *initrd_end = *initrd_start + rd_len;
+ printf(" Loading Ramdisk to %08lx, end %08lx ... ",
+ *initrd_start, *initrd_end);
+
+ memmove_wd((void *)*initrd_start,
+ (void *)rd_data, rd_len, CHUNKSZ);
+
+#ifdef CONFIG_MP
+ /*
+ * Ensure the image is flushed to memory to handle
+ * AMP boot scenarios in which we might not be
+ * HW cache coherent
+ */
+ flush_cache((unsigned long)*initrd_start,
+ ALIGN(rd_len, ARCH_DMA_MINALIGN));
+#endif
+ puts("OK\n");
+ }
+ } else {
+ *initrd_start = 0;
+ *initrd_end = 0;
+ }
+ debug(" ramdisk load start = 0x%08lx, ramdisk load end = 0x%08lx\n",
+ *initrd_start, *initrd_end);
+
+ return 0;
+
+error:
+ return -1;
+}
+#endif /* CONFIG_SYS_BOOT_RAMDISK_HIGH */
+
+int boot_get_setup(bootm_headers_t *images, uint8_t arch,
+ ulong *setup_start, ulong *setup_len)
+{
+#if IMAGE_ENABLE_FIT
+ return boot_get_setup_fit(images, arch, setup_start, setup_len);
+#else
+ return -ENOENT;
+#endif
+}
+
+#if IMAGE_ENABLE_FIT
+#if defined(CONFIG_FPGA)
+int boot_get_fpga(int argc, char *const argv[], bootm_headers_t *images,
+ uint8_t arch, const ulong *ld_start, ulong * const ld_len)
+{
+ ulong tmp_img_addr, img_data, img_len;
+ void *buf;
+ int conf_noffset;
+ int fit_img_result;
+ const char *uname, *name;
+ int err;
+ int devnum = 0; /* TODO support multi fpga platforms */
+
+ /* Check to see if the images struct has a FIT configuration */
+ if (!genimg_has_config(images)) {
+ debug("## FIT configuration was not specified\n");
+ return 0;
+ }
+
+ /*
+ * Obtain the os FIT header from the images struct
+ */
+ tmp_img_addr = map_to_sysmem(images->fit_hdr_os);
+ buf = map_sysmem(tmp_img_addr, 0);
+ /*
+ * Check image type. For FIT images get FIT node
+ * and attempt to locate a generic binary.
+ */
+ switch (genimg_get_format(buf)) {
+ case IMAGE_FORMAT_FIT:
+ conf_noffset = fit_conf_get_node(buf, images->fit_uname_cfg);
+
+ uname = fdt_stringlist_get(buf, conf_noffset, FIT_FPGA_PROP, 0,
+ NULL);
+ if (!uname) {
+ debug("## FPGA image is not specified\n");
+ return 0;
+ }
+ fit_img_result = fit_image_load(images,
+ tmp_img_addr,
+ (const char **)&uname,
+ &(images->fit_uname_cfg),
+ arch,
+ IH_TYPE_FPGA,
+ BOOTSTAGE_ID_FPGA_INIT,
+ FIT_LOAD_OPTIONAL_NON_ZERO,
+ &img_data, &img_len);
+
+ debug("FPGA image (%s) loaded to 0x%lx/size 0x%lx\n",
+ uname, img_data, img_len);
+
+ if (fit_img_result < 0) {
+ /* Something went wrong! */
+ return fit_img_result;
+ }
+
+ if (!fpga_is_partial_data(devnum, img_len)) {
+ name = "full";
+ err = fpga_loadbitstream(devnum, (char *)img_data,
+ img_len, BIT_FULL);
+ if (err)
+ err = fpga_load(devnum, (const void *)img_data,
+ img_len, BIT_FULL);
+ } else {
+ name = "partial";
+ err = fpga_loadbitstream(devnum, (char *)img_data,
+ img_len, BIT_PARTIAL);
+ if (err)
+ err = fpga_load(devnum, (const void *)img_data,
+ img_len, BIT_PARTIAL);
+ }
+
+ if (err)
+ return err;
+
+ printf(" Programming %s bitstream... OK\n", name);
+ break;
+ default:
+ printf("The given image format is not supported (corrupt?)\n");
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+static void fit_loadable_process(uint8_t img_type,
+ ulong img_data,
+ ulong img_len)
+{
+ int i;
+ const unsigned int count =
+ ll_entry_count(struct fit_loadable_tbl, fit_loadable);
+ struct fit_loadable_tbl *fit_loadable_handler =
+ ll_entry_start(struct fit_loadable_tbl, fit_loadable);
+ /* For each loadable handler */
+ for (i = 0; i < count; i++, fit_loadable_handler++)
+ /* matching this type */
+ if (fit_loadable_handler->type == img_type)
+ /* call that handler with this image data */
+ fit_loadable_handler->handler(img_data, img_len);
+}
+
+int boot_get_loadable(int argc, char *const argv[], bootm_headers_t *images,
+ uint8_t arch, const ulong *ld_start, ulong * const ld_len)
+{
+ /*
+ * These variables are used to hold the current image location
+ * in system memory.
+ */
+ ulong tmp_img_addr;
+ /*
+ * These two variables are requirements for fit_image_load, but
+ * their values are not used
+ */
+ ulong img_data, img_len;
+ void *buf;
+ int loadables_index;
+ int conf_noffset;
+ int fit_img_result;
+ const char *uname;
+ uint8_t img_type;
+
+ /* Check to see if the images struct has a FIT configuration */
+ if (!genimg_has_config(images)) {
+ debug("## FIT configuration was not specified\n");
+ return 0;
+ }
+
+ /*
+ * Obtain the os FIT header from the images struct
+ */
+ tmp_img_addr = map_to_sysmem(images->fit_hdr_os);
+ buf = map_sysmem(tmp_img_addr, 0);
+ /*
+ * Check image type. For FIT images get FIT node
+ * and attempt to locate a generic binary.
+ */
+ switch (genimg_get_format(buf)) {
+ case IMAGE_FORMAT_FIT:
+ conf_noffset = fit_conf_get_node(buf, images->fit_uname_cfg);
+
+ for (loadables_index = 0;
+ uname = fdt_stringlist_get(buf, conf_noffset,
+ FIT_LOADABLE_PROP, loadables_index,
+ NULL), uname;
+ loadables_index++)
+ {
+ fit_img_result = fit_image_load(images,
+ tmp_img_addr,
+ &uname,
+ &(images->fit_uname_cfg), arch,
+ IH_TYPE_LOADABLE,
+ BOOTSTAGE_ID_FIT_LOADABLE_START,
+ FIT_LOAD_OPTIONAL_NON_ZERO,
+ &img_data, &img_len);
+ if (fit_img_result < 0) {
+ /* Something went wrong! */
+ return fit_img_result;
+ }
+
+ fit_img_result = fit_image_get_node(buf, uname);
+ if (fit_img_result < 0) {
+ /* Something went wrong! */
+ return fit_img_result;
+ }
+ fit_img_result = fit_image_get_type(buf,
+ fit_img_result,
+ &img_type);
+ if (fit_img_result < 0) {
+ /* Something went wrong! */
+ return fit_img_result;
+ }
+
+ fit_loadable_process(img_type, img_data, img_len);
+ }
+ break;
+ default:
+ printf("The given image format is not supported (corrupt?)\n");
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_SYS_BOOT_GET_CMDLINE
+/**
+ * boot_get_cmdline - allocate and initialize kernel cmdline
+ * @lmb: pointer to lmb handle, will be used for memory mgmt
+ * @cmd_start: pointer to a ulong variable, will hold cmdline start
+ * @cmd_end: pointer to a ulong variable, will hold cmdline end
+ *
+ * boot_get_cmdline() allocates space for kernel command line below
+ * BOOTMAPSZ + env_get_bootm_low() address. If "bootargs" U-Boot environment
+ * variable is present its contents is copied to allocated kernel
+ * command line.
+ *
+ * returns:
+ * 0 - success
+ * -1 - failure
+ */
+int boot_get_cmdline(struct lmb *lmb, ulong *cmd_start, ulong *cmd_end)
+{
+ char *cmdline;
+ char *s;
+
+ cmdline = (char *)(ulong)lmb_alloc_base(lmb, CONFIG_SYS_BARGSIZE, 0xf,
+ env_get_bootm_mapsize() + env_get_bootm_low());
+
+ if (cmdline == NULL)
+ return -1;
+
+ s = env_get("bootargs");
+ if (!s)
+ s = "";
+
+ strcpy(cmdline, s);
+
+ *cmd_start = (ulong) & cmdline[0];
+ *cmd_end = *cmd_start + strlen(cmdline);
+
+ debug("## cmdline at 0x%08lx ... 0x%08lx\n", *cmd_start, *cmd_end);
+
+ return 0;
+}
+#endif /* CONFIG_SYS_BOOT_GET_CMDLINE */
+
+#ifdef CONFIG_SYS_BOOT_GET_KBD
+/**
+ * boot_get_kbd - allocate and initialize kernel copy of board info
+ * @lmb: pointer to lmb handle, will be used for memory mgmt
+ * @kbd: double pointer to board info data
+ *
+ * boot_get_kbd() allocates space for kernel copy of board info data below
+ * BOOTMAPSZ + env_get_bootm_low() address and kernel board info is initialized
+ * with the current u-boot board info data.
+ *
+ * returns:
+ * 0 - success
+ * -1 - failure
+ */
+int boot_get_kbd(struct lmb *lmb, struct bd_info **kbd)
+{
+ *kbd = (struct bd_info *)(ulong)lmb_alloc_base(lmb,
+ sizeof(struct bd_info),
+ 0xf,
+ env_get_bootm_mapsize() + env_get_bootm_low());
+ if (*kbd == NULL)
+ return -1;
+
+ **kbd = *(gd->bd);
+
+ debug("## kernel board info at 0x%08lx\n", (ulong)*kbd);
+
+#if defined(DEBUG) && defined(CONFIG_CMD_BDI)
+ do_bdinfo(NULL, 0, 0, NULL);
+#endif
+
+ return 0;
+}
+#endif /* CONFIG_SYS_BOOT_GET_KBD */
+
+#ifdef CONFIG_LMB
+int image_setup_linux(bootm_headers_t *images)
+{
+ ulong of_size = images->ft_len;
+ char **of_flat_tree = &images->ft_addr;
+ struct lmb *lmb = &images->lmb;
+ int ret;
+
+ if (IMAGE_ENABLE_OF_LIBFDT)
+ boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);
+
+ if (IMAGE_BOOT_GET_CMDLINE) {
+ ret = boot_get_cmdline(lmb, &images->cmdline_start,
+ &images->cmdline_end);
+ if (ret) {
+ puts("ERROR with allocation of cmdline\n");
+ return ret;
+ }
+ }
+
+ if (IMAGE_ENABLE_OF_LIBFDT) {
+ ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
+ if (ret)
+ return ret;
+ }
+
+ if (IMAGE_ENABLE_OF_LIBFDT && of_size) {
+ ret = image_setup_libfdt(images, *of_flat_tree, of_size, lmb);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_LMB */
+#endif /* !USE_HOSTCC */
diff --git a/roms/u-boot/common/init/Makefile b/roms/u-boot/common/init/Makefile
new file mode 100644
index 000000000..853b56d1e
--- /dev/null
+++ b/roms/u-boot/common/init/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2015 Google, Inc
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += board_init.o
+obj-$(CONFIG_$(SPL_TPL_)HANDOFF) += handoff.o
diff --git a/roms/u-boot/common/init/board_init.c b/roms/u-boot/common/init/board_init.c
new file mode 100644
index 000000000..3f183ee11
--- /dev/null
+++ b/roms/u-boot/common/init/board_init.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Code shared between SPL and U-Boot proper
+ *
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <bootstage.h>
+#include <init.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Unfortunately x86 or ARM can't compile this code as gd cannot be assigned */
+#if !defined(CONFIG_X86) && !defined(CONFIG_ARM)
+__weak void arch_setup_gd(struct global_data *gd_ptr)
+{
+ gd = gd_ptr;
+}
+#endif /* !CONFIG_X86 && !CONFIG_ARM */
+
+/**
+ * This function is called from board_init_f_init_reserve to set up
+ * gd->start_addr_sp for stack protection if not already set otherwise
+ */
+__weak void board_init_f_init_stack_protection_addr(ulong base)
+{
+#if CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE)
+ /* set up stack pointer for stack usage if not set yet */
+ if (!gd->start_addr_sp)
+ gd->start_addr_sp = base;
+#endif
+}
+
+/**
+ * This function is called after the position of the initial stack is
+ * determined in gd->start_addr_sp. Boards can override it to set up
+ * stack-checking markers.
+ */
+__weak void board_init_f_init_stack_protection(void)
+{
+#if CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE)
+ ulong stack_bottom = gd->start_addr_sp -
+ CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK);
+
+ /* substact some safety margin (0x20) since stack is in use here */
+ memset((void *)stack_bottom, CONFIG_VAL(SYS_STACK_F_CHECK_BYTE),
+ CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK) - 0x20);
+#endif
+}
+
+/*
+ * Allocate reserved space for use as 'globals' from 'top' address and
+ * return 'bottom' address of allocated space
+ *
+ * Notes:
+ *
+ * Actual reservation cannot be done from within this function as
+ * it requires altering the C stack pointer, so this will be done by
+ * the caller upon return from this function.
+ *
+ * IMPORTANT:
+ *
+ * Alignment constraints may differ for each 'chunk' allocated. For now:
+ *
+ * - GD is aligned down on a 16-byte boundary
+ *
+ * - the early malloc arena is not aligned, therefore it follows the stack
+ * alignment constraint of the architecture for which we are bulding.
+ *
+ * - GD is allocated last, so that the return value of this functions is
+ * both the bottom of the reserved area and the address of GD, should
+ * the calling context need it.
+ */
+
+ulong board_init_f_alloc_reserve(ulong top)
+{
+ /* Reserve early malloc arena */
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ top -= CONFIG_VAL(SYS_MALLOC_F_LEN);
+#endif
+ /* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
+ top = rounddown(top-sizeof(struct global_data), 16);
+
+ return top;
+}
+
+/*
+ * Initialize reserved space (which has been safely allocated on the C
+ * stack from the C runtime environment handling code).
+ *
+ * Notes:
+ *
+ * Actual reservation was done by the caller; the locations from base
+ * to base+size-1 (where 'size' is the value returned by the allocation
+ * function above) can be accessed freely without risk of corrupting the
+ * C runtime environment.
+ *
+ * IMPORTANT:
+ *
+ * Upon return from the allocation function above, on some architectures
+ * the caller will set gd to the lowest reserved location. Therefore, in
+ * this initialization function, the global data MUST be placed at base.
+ *
+ * ALSO IMPORTANT:
+ *
+ * On some architectures, gd will already be good when entering this
+ * function. On others, it will only be good once arch_setup_gd() returns.
+ * Therefore, global data accesses must be done:
+ *
+ * - through gd_ptr if before the call to arch_setup_gd();
+ *
+ * - through gd once arch_setup_gd() has been called.
+ *
+ * Do not use 'gd->' until arch_setup_gd() has been called!
+ *
+ * IMPORTANT TOO:
+ *
+ * Initialization for each "chunk" (GD, early malloc arena...) ends with
+ * an incrementation line of the form 'base += <some size>'. The last of
+ * these incrementations seems useless, as base will not be used any
+ * more after this incrementation; but if/when a new "chunk" is appended,
+ * this increment will be essential as it will give base right value for
+ * this new chunk (which will have to end with its own incrementation
+ * statement). Besides, the compiler's optimizer will silently detect
+ * and remove the last base incrementation, therefore leaving that last
+ * (seemingly useless) incrementation causes no code increase.
+ */
+
+void board_init_f_init_reserve(ulong base)
+{
+ struct global_data *gd_ptr;
+
+ /*
+ * clear GD entirely and set it up.
+ * Use gd_ptr, as gd may not be properly set yet.
+ */
+
+ gd_ptr = (struct global_data *)base;
+ /* zero the area */
+ memset(gd_ptr, '\0', sizeof(*gd));
+ /* set GD unless architecture did it already */
+#if !defined(CONFIG_ARM)
+ arch_setup_gd(gd_ptr);
+#endif
+
+ if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
+ board_init_f_init_stack_protection_addr(base);
+
+ /* next alloc will be higher by one GD plus 16-byte alignment */
+ base += roundup(sizeof(struct global_data), 16);
+
+ /*
+ * record early malloc arena start.
+ * Use gd as it is now properly set for all architectures.
+ */
+
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ /* go down one 'early malloc arena' */
+ gd->malloc_base = base;
+#endif
+
+ if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
+ board_init_f_init_stack_protection();
+}
+
+/*
+ * Board-specific Platform code can reimplement show_boot_progress () if needed
+ */
+__weak void show_boot_progress(int val) {}
diff --git a/roms/u-boot/common/init/handoff.c b/roms/u-boot/common/init/handoff.c
new file mode 100644
index 000000000..d0be1bb17
--- /dev/null
+++ b/roms/u-boot/common/init/handoff.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Passing basic information from SPL to U-Boot proper
+ *
+ * Copyright 2018 Google, Inc
+ */
+
+#include <common.h>
+#include <handoff.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void handoff_save_dram(struct spl_handoff *ho)
+{
+ struct bd_info *bd = gd->bd;
+ int i;
+
+ ho->ram_size = gd->ram_size;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ ho->ram_bank[i].start = bd->bi_dram[i].start;
+ ho->ram_bank[i].size = bd->bi_dram[i].size;
+ }
+}
+
+void handoff_load_dram_size(struct spl_handoff *ho)
+{
+ gd->ram_size = ho->ram_size;
+}
+
+void handoff_load_dram_banks(struct spl_handoff *ho)
+{
+ struct bd_info *bd = gd->bd;
+ int i;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ bd->bi_dram[i].start = ho->ram_bank[i].start;
+ bd->bi_dram[i].size = ho->ram_bank[i].size;
+ }
+}
diff --git a/roms/u-boot/common/iomux.c b/roms/u-boot/common/iomux.c
new file mode 100644
index 000000000..c428f7110
--- /dev/null
+++ b/roms/u-boot/common/iomux.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2008
+ * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
+ */
+
+#include <common.h>
+#include <console.h>
+#include <serial.h>
+#include <malloc.h>
+
+#if CONFIG_IS_ENABLED(CONSOLE_MUX)
+void iomux_printdevs(const int console)
+{
+ int i;
+ struct stdio_dev *dev;
+
+ for_each_console_dev(i, console, dev)
+ printf("%s ", dev->name);
+ printf("\n");
+}
+
+int iomux_match_device(struct stdio_dev **set, const int n, struct stdio_dev *sdev)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ if (sdev == set[i])
+ return i;
+ return -ENOENT;
+}
+
+/* This tries to preserve the old list if an error occurs. */
+int iomux_doenv(const int console, const char *arg)
+{
+ char *console_args, *temp, **start;
+ int i, j, io_flag, cs_idx, repeat;
+ struct stdio_dev **cons_set, **old_set;
+ struct stdio_dev *dev;
+
+ console_args = strdup(arg);
+ if (console_args == NULL)
+ return 1;
+ /*
+ * Check whether a comma separated list of devices was
+ * entered and count how many devices were entered.
+ * The array start[] has pointers to the beginning of
+ * each device name (up to MAX_CONSARGS devices).
+ *
+ * Have to do this twice - once to count the number of
+ * commas and then again to populate start.
+ */
+ i = 0;
+ temp = console_args;
+ for (;;) {
+ /* There's always one entry more than the number of commas. */
+ i++;
+
+ temp = strchr(temp, ',');
+ if (temp == NULL)
+ break;
+
+ temp++;
+ }
+ start = (char **)malloc(i * sizeof(char *));
+ if (start == NULL) {
+ free(console_args);
+ return 1;
+ }
+ i = 0;
+ start[0] = console_args;
+ for (;;) {
+ temp = strchr(start[i++], ',');
+ if (temp == NULL)
+ break;
+ *temp = '\0';
+ start[i] = temp + 1;
+ }
+ cons_set = (struct stdio_dev **)calloc(i, sizeof(struct stdio_dev *));
+ if (cons_set == NULL) {
+ free(start);
+ free(console_args);
+ return 1;
+ }
+
+ io_flag = stdio_file_to_flags(console);
+ if (io_flag < 0) {
+ free(start);
+ free(console_args);
+ free(cons_set);
+ return 1;
+ }
+
+ cs_idx = 0;
+ for (j = 0; j < i; j++) {
+ /*
+ * Check whether the device exists and is valid.
+ * console_assign() also calls console_search_dev(),
+ * but I need the pointer to the device.
+ */
+ dev = console_search_dev(io_flag, start[j]);
+ if (dev == NULL)
+ continue;
+ /*
+ * Prevent multiple entries for a device.
+ */
+ repeat = iomux_match_device(cons_set, cs_idx, dev);
+ if (repeat >= 0)
+ continue;
+ /*
+ * Try assigning the specified device.
+ * This could screw up the console settings for apps.
+ */
+ if (console_assign(console, start[j]) < 0)
+ continue;
+ cons_set[cs_idx++] = dev;
+ }
+ free(console_args);
+ free(start);
+ /* failed to set any console */
+ if (cs_idx == 0) {
+ free(cons_set);
+ return 1;
+ }
+
+ old_set = console_devices[console];
+ repeat = cd_count[console];
+
+ console_devices[console] = cons_set;
+ cd_count[console] = cs_idx;
+
+ /* Stop dropped consoles */
+ for (i = 0; i < repeat; i++) {
+ j = iomux_match_device(cons_set, cs_idx, old_set[i]);
+ if (j == cs_idx)
+ console_stop(console, old_set[i]);
+ }
+
+ free(old_set);
+ return 0;
+}
+
+int iomux_replace_device(const int console, const char *old, const char *new)
+{
+ struct stdio_dev *dev;
+ char *arg = NULL; /* Initial empty list */
+ int size = 1; /* For NUL terminator */
+ int i, ret;
+
+ for_each_console_dev(i, console, dev) {
+ const char *name = strcmp(dev->name, old) ? dev->name : new;
+ char *tmp;
+
+ /* Append name with a ',' (comma) separator */
+ tmp = realloc(arg, size + strlen(name) + 1);
+ if (!tmp) {
+ free(arg);
+ return -ENOMEM;
+ }
+
+ if (arg) {
+ strcat(tmp, ",");
+ strcat(tmp, name);
+ }
+ else
+ strcpy(tmp, name);
+
+ arg = tmp;
+ size = strlen(tmp) + 1;
+ }
+
+ ret = iomux_doenv(console, arg);
+ if (ret)
+ ret = -EINVAL;
+
+ free(arg);
+ return ret;
+}
+#endif /* CONSOLE_MUX */
diff --git a/roms/u-boot/common/iotrace.c b/roms/u-boot/common/iotrace.c
new file mode 100644
index 000000000..63d0cca3a
--- /dev/null
+++ b/roms/u-boot/common/iotrace.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Google, Inc.
+ */
+
+#define IOTRACE_IMPL
+
+#include <common.h>
+#include <mapmem.h>
+#include <time.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <u-boot/crc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct iotrace - current trace status and checksum
+ *
+ * @start: Start address of iotrace buffer
+ * @size: Actual size of iotrace buffer in bytes
+ * @needed_size: Needed of iotrace buffer in bytes
+ * @offset: Current write offset into iotrace buffer
+ * @region_start: Address of IO region to trace
+ * @region_size: Size of region to trace. if 0 will trace all address space
+ * @crc32: Current value of CRC chceksum of trace records
+ * @enabled: true if enabled, false if disabled
+ */
+static struct iotrace {
+ ulong start;
+ ulong size;
+ ulong needed_size;
+ ulong offset;
+ ulong region_start;
+ ulong region_size;
+ u32 crc32;
+ bool enabled;
+} iotrace;
+
+static void add_record(int flags, const void *ptr, ulong value)
+{
+ struct iotrace_record srec, *rec = &srec;
+
+ /*
+ * We don't support iotrace before relocation. Since the trace buffer
+ * is set up by a command, it can't be enabled at present. To change
+ * this we would need to set the iotrace buffer at build-time. See
+ * lib/trace.c for how this might be done if you are interested.
+ */
+ if (!(gd->flags & GD_FLG_RELOC) || !iotrace.enabled)
+ return;
+
+ if (iotrace.region_size)
+ if ((ulong)ptr < iotrace.region_start ||
+ (ulong)ptr > iotrace.region_start + iotrace.region_size)
+ return;
+
+ /* Store it if there is room */
+ if (iotrace.offset + sizeof(*rec) < iotrace.size) {
+ rec = (struct iotrace_record *)map_sysmem(
+ iotrace.start + iotrace.offset,
+ sizeof(value));
+ } else {
+ WARN_ONCE(1, "WARNING: iotrace buffer exhausted, please check needed length using \"iotrace stats\"\n");
+ iotrace.needed_size += sizeof(struct iotrace_record);
+ return;
+ }
+
+ rec->timestamp = timer_get_us();
+ rec->flags = flags;
+ rec->addr = map_to_sysmem(ptr);
+ rec->value = value;
+
+ /* Update our checksum */
+ iotrace.crc32 = crc32(iotrace.crc32, (unsigned char *)rec,
+ sizeof(*rec));
+
+ iotrace.needed_size += sizeof(struct iotrace_record);
+ iotrace.offset += sizeof(struct iotrace_record);
+}
+
+u32 iotrace_readl(const void *ptr)
+{
+ u32 v;
+
+ v = readl(ptr);
+ add_record(IOT_32 | IOT_READ, ptr, v);
+
+ return v;
+}
+
+void iotrace_writel(ulong value, void *ptr)
+{
+ add_record(IOT_32 | IOT_WRITE, ptr, value);
+ writel(value, ptr);
+}
+
+u16 iotrace_readw(const void *ptr)
+{
+ u32 v;
+
+ v = readw(ptr);
+ add_record(IOT_16 | IOT_READ, ptr, v);
+
+ return v;
+}
+
+void iotrace_writew(ulong value, void *ptr)
+{
+ add_record(IOT_16 | IOT_WRITE, ptr, value);
+ writew(value, ptr);
+}
+
+u8 iotrace_readb(const void *ptr)
+{
+ u32 v;
+
+ v = readb(ptr);
+ add_record(IOT_8 | IOT_READ, ptr, v);
+
+ return v;
+}
+
+void iotrace_writeb(ulong value, void *ptr)
+{
+ add_record(IOT_8 | IOT_WRITE, ptr, value);
+ writeb(value, ptr);
+}
+
+void iotrace_reset_checksum(void)
+{
+ iotrace.crc32 = 0;
+}
+
+u32 iotrace_get_checksum(void)
+{
+ return iotrace.crc32;
+}
+
+void iotrace_set_region(ulong start, ulong size)
+{
+ iotrace.region_start = start;
+ iotrace.region_size = size;
+}
+
+void iotrace_reset_region(void)
+{
+ iotrace.region_start = 0;
+ iotrace.region_size = 0;
+}
+
+void iotrace_get_region(ulong *start, ulong *size)
+{
+ *start = iotrace.region_start;
+ *size = iotrace.region_size;
+}
+
+void iotrace_set_enabled(int enable)
+{
+ iotrace.enabled = enable;
+}
+
+int iotrace_get_enabled(void)
+{
+ return iotrace.enabled;
+}
+
+void iotrace_set_buffer(ulong start, ulong size)
+{
+ iotrace.start = start;
+ iotrace.size = size;
+ iotrace.offset = 0;
+ iotrace.crc32 = 0;
+}
+
+void iotrace_get_buffer(ulong *start, ulong *size, ulong *needed_size, ulong *offset, ulong *count)
+{
+ *start = iotrace.start;
+ *size = iotrace.size;
+ *needed_size = iotrace.needed_size;
+ *offset = iotrace.offset;
+ *count = iotrace.offset / sizeof(struct iotrace_record);
+}
diff --git a/roms/u-boot/common/kallsyms.c b/roms/u-boot/common/kallsyms.c
new file mode 100644
index 000000000..ce42a932b
--- /dev/null
+++ b/roms/u-boot/common/kallsyms.c
@@ -0,0 +1,44 @@
+/*
+ * Helper functions for working with the builtin symbol table
+ *
+ * Copyright (c) 2008-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+
+/* We need the weak marking as this symbol is provided specially */
+extern const char system_map[] __attribute__((weak));
+
+/* Given an address, return a pointer to the symbol name and store
+ * the base address in caddr. So if the symbol map had an entry:
+ * 03fb9b7c_spi_cs_deactivate
+ * Then the following call:
+ * unsigned long base;
+ * const char *sym = symbol_lookup(0x03fb9b80, &base);
+ * Would end up setting the variables like so:
+ * base = 0x03fb9b7c;
+ * sym = "_spi_cs_deactivate";
+ */
+const char *symbol_lookup(unsigned long addr, unsigned long *caddr)
+{
+ const char *sym, *csym;
+ char *esym;
+ unsigned long sym_addr;
+
+ sym = system_map;
+ csym = NULL;
+ *caddr = 0;
+
+ while (*sym) {
+ sym_addr = simple_strtoul(sym, &esym, 16);
+ sym = esym;
+ if (sym_addr > addr)
+ break;
+ *caddr = sym_addr;
+ csym = sym;
+ sym += strlen(sym) + 1;
+ }
+
+ return csym;
+}
diff --git a/roms/u-boot/common/kgdb.c b/roms/u-boot/common/kgdb.c
new file mode 100644
index 000000000..4493a1591
--- /dev/null
+++ b/roms/u-boot/common/kgdb.c
@@ -0,0 +1,599 @@
+/* taken from arch/powerpc/kernel/ppc-stub.c */
+
+/****************************************************************************
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ HP offers the following for use in the public domain. HP makes no
+ warranty with regard to the software or its performance and the
+ user accepts the software "AS IS" with all faults.
+
+ HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+ TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ * Module name: remcom.c $
+ * Revision: 1.34 $
+ * Date: 91/03/09 12:29:49 $
+ * Contributor: Lake Stevens Instrument Division$
+ *
+ * Description: low level support for gdb debugger. $
+ *
+ * Considerations: only works on target hardware $
+ *
+ * Written by: Glenn Engel $
+ * ModuleState: Experimental $
+ *
+ * NOTES: See Below $
+ *
+ * Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ * This code has been extensively tested on the Fujitsu SPARClite demo board.
+ *
+ * To enable debugger support, two things need to happen. One, a
+ * call to set_debug_traps() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint(). Breakpoint()
+ * simulates a breakpoint by executing a trap #1.
+ *
+ *************
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * G set the value of the CPU registers OK or ENN
+ * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
+ * baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer. '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host: Reply:
+ * $m0,10#2a +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+
+#include <common.h>
+#include <asm/ptrace.h>
+
+#include <kgdb.h>
+#include <command.h>
+
+#undef KGDB_DEBUG
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ */
+#define BUFMAX 1024
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static char remcomRegBuffer[BUFMAX];
+
+static int initialized = 0;
+static int kgdb_active;
+static struct pt_regs entry_regs;
+static long error_jmp_buf[BUFMAX/2];
+static int longjmp_on_fault = 0;
+#ifdef KGDB_DEBUG
+static int kdebug = 1;
+#endif
+
+static const char hexchars[]="0123456789abcdef";
+
+/* Convert ch from a hex digit to an int */
+static int
+hex(unsigned char ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return ch-'a'+10;
+ if (ch >= '0' && ch <= '9')
+ return ch-'0';
+ if (ch >= 'A' && ch <= 'F')
+ return ch-'A'+10;
+ return -1;
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null).
+ */
+static unsigned char *
+mem2hex(char *mem, char *buf, int count)
+{
+ char *tmp;
+ unsigned char ch;
+
+ /*
+ * We use the upper half of buf as an intermediate buffer for the
+ * raw memory copy. Hex conversion will work against this one.
+ */
+ tmp = buf + count;
+ longjmp_on_fault = 1;
+
+ memcpy(tmp, mem, count);
+
+ while (count-- > 0) {
+ ch = *tmp++;
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch & 0xf];
+ }
+ *buf = 0;
+ longjmp_on_fault = 0;
+ return (unsigned char *)buf;
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte fetched from buf.
+*/
+static char *
+hex2mem(char *buf, char *mem, int count)
+{
+ int hexValue;
+ char *tmp_raw, *tmp_hex;
+
+ /*
+ * We use the upper half of buf as an intermediate buffer for the
+ * raw memory that is converted from hex.
+ */
+ tmp_raw = buf + count * 2;
+ tmp_hex = tmp_raw - 1;
+
+ longjmp_on_fault = 1;
+ while (tmp_hex >= buf) {
+ tmp_raw--;
+ hexValue = hex(*tmp_hex--);
+ if (hexValue < 0)
+ kgdb_error(KGDBERR_NOTHEXDIG);
+ *tmp_raw = hexValue;
+ hexValue = hex(*tmp_hex--);
+ if (hexValue < 0)
+ kgdb_error(KGDBERR_NOTHEXDIG);
+ *tmp_raw |= hexValue << 4;
+
+ }
+
+ memcpy(mem, tmp_raw, count);
+
+ kgdb_flush_cache_range((void *)mem, (void *)(mem+count));
+ longjmp_on_fault = 0;
+
+ return buf;
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int
+hexToInt(char **ptr, int *intValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *intValue = 0;
+
+ longjmp_on_fault = 1;
+ while (**ptr) {
+ hexValue = hex(**ptr);
+ if (hexValue < 0)
+ break;
+
+ *intValue = (*intValue << 4) | hexValue;
+ numChars ++;
+
+ (*ptr)++;
+ }
+ longjmp_on_fault = 0;
+
+ return (numChars);
+}
+
+/* scan for the sequence $<data>#<checksum> */
+static void
+getpacket(char *buffer)
+{
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int i;
+ int count;
+ unsigned char ch;
+
+ do {
+ /* wait around for the start character, ignore all other
+ * characters */
+ while ((ch = (getDebugChar() & 0x7f)) != '$') {
+#ifdef KGDB_DEBUG
+ if (kdebug)
+ putc(ch);
+#endif
+ ;
+ }
+
+ checksum = 0;
+ xmitcsum = -1;
+
+ count = 0;
+
+ /* now, read until a # or end of buffer is found */
+ while (count < BUFMAX) {
+ ch = getDebugChar() & 0x7f;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+
+ if (count >= BUFMAX)
+ continue;
+
+ buffer[count] = 0;
+
+ if (ch == '#') {
+ xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+ xmitcsum |= hex(getDebugChar() & 0x7f);
+ if (checksum != xmitcsum)
+ putDebugChar('-'); /* failed checksum */
+ else {
+ putDebugChar('+'); /* successful transfer */
+ /* if a sequence char is present, reply the ID */
+ if (buffer[2] == ':') {
+ putDebugChar(buffer[0]);
+ putDebugChar(buffer[1]);
+ /* remove sequence chars from buffer */
+ count = strlen(buffer);
+ for (i=3; i <= count; i++)
+ buffer[i-3] = buffer[i];
+ }
+ }
+ }
+ } while (checksum != xmitcsum);
+}
+
+/* send the packet in buffer. */
+static void
+putpacket(unsigned char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ unsigned char ch, recv;
+
+ /* $<packet info>#<checksum>. */
+ do {
+ putDebugChar('$');
+ checksum = 0;
+ count = 0;
+
+ while ((ch = buffer[count])) {
+ putDebugChar(ch);
+ checksum += ch;
+ count += 1;
+ }
+
+ putDebugChar('#');
+ putDebugChar(hexchars[checksum >> 4]);
+ putDebugChar(hexchars[checksum & 0xf]);
+ recv = getDebugChar();
+ } while ((recv & 0x7f) != '+');
+}
+
+/*
+ * This function does all command processing for interfacing to gdb.
+ */
+static int
+handle_exception (struct pt_regs *regs)
+{
+ int addr;
+ int length;
+ char *ptr;
+ kgdb_data kd;
+ int i;
+
+ if (!initialized) {
+ printf("kgdb: exception before kgdb is initialized! huh?\n");
+ return (0);
+ }
+
+ /* probably should check which exception occurred as well */
+ if (longjmp_on_fault) {
+ longjmp_on_fault = 0;
+ kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT);
+ panic("kgdb longjump failed!\n");
+ }
+
+ if (kgdb_active) {
+ printf("kgdb: unexpected exception from within kgdb\n");
+ return (0);
+ }
+ kgdb_active = 1;
+
+ kgdb_interruptible(0);
+
+ printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs));
+
+ if (kgdb_setjmp(error_jmp_buf) != 0)
+ panic("kgdb: error or fault in entry init!\n");
+
+ kgdb_enter(regs, &kd);
+
+ entry_regs = *regs;
+
+ ptr = remcomOutBuffer;
+
+ *ptr++ = 'T';
+
+ *ptr++ = hexchars[kd.sigval >> 4];
+ *ptr++ = hexchars[kd.sigval & 0xf];
+
+ for (i = 0; i < kd.nregs; i++) {
+ kgdb_reg *rp = &kd.regs[i];
+
+ *ptr++ = hexchars[rp->num >> 4];
+ *ptr++ = hexchars[rp->num & 0xf];
+ *ptr++ = ':';
+ ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
+ *ptr++ = ';';
+ }
+
+ *ptr = 0;
+
+#ifdef KGDB_DEBUG
+ if (kdebug)
+ printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
+#endif
+
+ putpacket((unsigned char *)&remcomOutBuffer);
+
+ while (1) {
+ volatile int errnum;
+
+ remcomOutBuffer[0] = 0;
+
+ getpacket(remcomInBuffer);
+ ptr = &remcomInBuffer[1];
+
+#ifdef KGDB_DEBUG
+ if (kdebug)
+ printf("kgdb: remcomInBuffer: %s\n", remcomInBuffer);
+#endif
+
+ errnum = kgdb_setjmp(error_jmp_buf);
+
+ if (errnum == 0) switch (remcomInBuffer[0]) {
+
+ case '?': /* report most recent signal */
+ remcomOutBuffer[0] = 'S';
+ remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
+ remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
+ remcomOutBuffer[3] = 0;
+ break;
+
+#ifdef KGDB_DEBUG
+ case 'd':
+ /* toggle debug flag */
+ kdebug ^= 1;
+ break;
+#endif
+
+ case 'g': /* return the value of the CPU registers. */
+ length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
+ mem2hex(remcomRegBuffer, remcomOutBuffer, length);
+ break;
+
+ case 'G': /* set the value of the CPU registers */
+ length = strlen(ptr);
+ if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
+ hex2mem(ptr, remcomRegBuffer, length/2);
+ kgdb_putregs(regs, remcomRegBuffer, length/2);
+ strcpy(remcomOutBuffer,"OK");
+ break;
+
+ case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
+ /* Try to read %x,%x. */
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)) {
+ mem2hex((char *)addr, remcomOutBuffer, length);
+ } else {
+ kgdb_error(KGDBERR_BADPARAMS);
+ }
+ break;
+
+ case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+ /* Try to read '%x,%x:'. */
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)
+ && *ptr++ == ':') {
+ hex2mem(ptr, (char *)addr, length);
+ strcpy(remcomOutBuffer, "OK");
+ } else {
+ kgdb_error(KGDBERR_BADPARAMS);
+ }
+ break;
+
+
+ case 'k': /* kill the program, actually return to monitor */
+ kd.extype = KGDBEXIT_KILL;
+ *regs = entry_regs;
+ goto doexit;
+
+ case 'C': /* CSS continue with signal SS */
+ *ptr = '\0'; /* ignore the signal number for now */
+ /* fall through */
+
+ case 'c': /* cAA..AA Continue; address AA..AA optional */
+ /* try to read optional parameter, pc unchanged if no parm */
+ kd.extype = KGDBEXIT_CONTINUE;
+
+ if (hexToInt(&ptr, &addr)) {
+ kd.exaddr = addr;
+ kd.extype |= KGDBEXIT_WITHADDR;
+ }
+
+ goto doexit;
+
+ case 'S': /* SSS single step with signal SS */
+ *ptr = '\0'; /* ignore the signal number for now */
+ /* fall through */
+
+ case 's':
+ kd.extype = KGDBEXIT_SINGLE;
+
+ if (hexToInt(&ptr, &addr)) {
+ kd.exaddr = addr;
+ kd.extype |= KGDBEXIT_WITHADDR;
+ }
+
+ doexit:
+/* Need to flush the instruction cache here, as we may have deposited a
+ * breakpoint, and the icache probably has no way of knowing that a data ref to
+ * some location may have changed something that is in the instruction cache.
+ */
+ kgdb_flush_cache_all();
+ kgdb_exit(regs, &kd);
+ kgdb_active = 0;
+ kgdb_interruptible(1);
+ return (1);
+
+ case 'r': /* Reset (if user process..exit ???)*/
+ panic("kgdb reset.");
+ break;
+
+ case 'P': /* Pr=v set reg r to value v (r and v are hex) */
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == '='
+ && ((length = strlen(ptr)) & 1) == 0) {
+ hex2mem(ptr, remcomRegBuffer, length/2);
+ kgdb_putreg(regs, addr,
+ remcomRegBuffer, length/2);
+ strcpy(remcomOutBuffer,"OK");
+ } else {
+ kgdb_error(KGDBERR_BADPARAMS);
+ }
+ break;
+ } /* switch */
+
+ if (errnum != 0)
+ sprintf(remcomOutBuffer, "E%02d", errnum);
+
+#ifdef KGDB_DEBUG
+ if (kdebug)
+ printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
+#endif
+
+ /* reply to the request */
+ putpacket((unsigned char *)&remcomOutBuffer);
+
+ } /* while(1) */
+}
+
+/*
+ * kgdb_init must be called *after* the
+ * monitor is relocated into ram
+ */
+void
+kgdb_init(void)
+{
+ kgdb_serial_init();
+ debugger_exception_handler = handle_exception;
+ initialized = 1;
+
+ putDebugStr("kgdb ready\n");
+ puts("ready\n");
+}
+
+void
+kgdb_error(int errnum)
+{
+ longjmp_on_fault = 0;
+ kgdb_longjmp(error_jmp_buf, errnum);
+ panic("kgdb_error: longjmp failed!\n");
+}
+
+/* Output string in GDB O-packet format if GDB has connected. If nothing
+ output, returns 0 (caller must then handle output). */
+int
+kgdb_output_string (const char* s, unsigned int count)
+{
+ char buffer[512];
+
+ count = (count <= (sizeof(buffer) / 2 - 2))
+ ? count : (sizeof(buffer) / 2 - 2);
+
+ buffer[0] = 'O';
+ mem2hex ((char *)s, &buffer[1], count);
+ putpacket((unsigned char *)&buffer);
+
+ return 1;
+}
+
+void
+breakpoint(void)
+{
+ if (!initialized) {
+ printf("breakpoint() called b4 kgdb init\n");
+ return;
+ }
+
+ kgdb_breakpoint(0, 0);
+}
+
+int
+do_kgdb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ printf("Entering KGDB mode via exception handler...\n\n");
+ kgdb_breakpoint(argc - 1, argv + 1);
+ printf("\nReturned from KGDB mode\n");
+ return 0;
+}
+
+U_BOOT_CMD(
+ kgdb, CONFIG_SYS_MAXARGS, 1, do_kgdb,
+ "enter gdb remote debug mode",
+ "[arg0 arg1 .. argN]\n"
+ " - executes a breakpoint so that kgdb mode is\n"
+ " entered via the exception handler. To return\n"
+ " to the monitor, the remote gdb debugger must\n"
+ " execute a \"continue\" or \"quit\" command.\n"
+ "\n"
+ " if a program is loaded by the remote gdb, any args\n"
+ " passed to the kgdb command are given to the loaded\n"
+ " program if it is executed (see the \"hello_world\"\n"
+ " example program in the U-Boot examples directory)."
+);
diff --git a/roms/u-boot/common/kgdb_stubs.c b/roms/u-boot/common/kgdb_stubs.c
new file mode 100644
index 000000000..66aed7cea
--- /dev/null
+++ b/roms/u-boot/common/kgdb_stubs.c
@@ -0,0 +1,67 @@
+/*
+ * U-Boot - stub functions for common kgdb code,
+ * can be overridden in board specific files
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <kgdb.h>
+#include <serial.h>
+#include <asm/ptrace.h>
+
+int (*debugger_exception_handler)(struct pt_regs *);
+
+__attribute__((weak))
+void kgdb_serial_init(void)
+{
+ puts("[on serial] ");
+}
+
+__attribute__((weak))
+void putDebugChar(int c)
+{
+ serial_putc(c);
+}
+
+__attribute__((weak))
+void putDebugStr(const char *str)
+{
+#ifdef DEBUG
+ serial_puts(str);
+#endif
+}
+
+__attribute__((weak))
+int getDebugChar(void)
+{
+ return serial_getc();
+}
+
+__attribute__((weak))
+void kgdb_interruptible(int yes)
+{
+ return;
+}
+
+__attribute__((weak))
+void kgdb_flush_cache_range(void *from, void *to)
+{
+ flush_cache((unsigned long)from, (unsigned long)(to - from));
+}
+
+__attribute__((weak))
+void kgdb_flush_cache_all(void)
+{
+ if (dcache_status()) {
+ dcache_disable();
+ dcache_enable();
+ }
+ if (icache_status()) {
+ icache_disable();
+ icache_enable();
+ }
+}
diff --git a/roms/u-boot/common/lcd.c b/roms/u-boot/common/lcd.c
new file mode 100644
index 000000000..ab5614ad0
--- /dev/null
+++ b/roms/u-boot/common/lcd.c
@@ -0,0 +1,772 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Common LCD routines
+ *
+ * (C) Copyright 2001-2002
+ * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
+ */
+
+/* #define DEBUG */
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <cpu_func.h>
+#include <env_callback.h>
+#include <log.h>
+#include <asm/cache.h>
+#include <init.h>
+#include <asm/global_data.h>
+#include <linux/types.h>
+#include <stdio_dev.h>
+#include <lcd.h>
+#include <mapmem.h>
+#include <watchdog.h>
+#include <asm/unaligned.h>
+#include <splash.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <video_font.h>
+
+#ifdef CONFIG_LCD_LOGO
+#include <bmp_logo.h>
+#include <bmp_logo_data.h>
+#if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)
+#error Default Color Map overlaps with Logo Color Map
+#endif
+#endif
+
+#ifndef CONFIG_LCD_ALIGNMENT
+#define CONFIG_LCD_ALIGNMENT PAGE_SIZE
+#endif
+
+#if (LCD_BPP != LCD_COLOR8) && (LCD_BPP != LCD_COLOR16) && \
+ (LCD_BPP != LCD_COLOR32)
+#error Unsupported LCD BPP.
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int lcd_init(void *lcdbase);
+static void lcd_logo(void);
+static void lcd_setfgcolor(int color);
+static void lcd_setbgcolor(int color);
+
+static int lcd_color_fg;
+static int lcd_color_bg;
+int lcd_line_length;
+char lcd_is_enabled = 0;
+static void *lcd_base; /* Start of framebuffer memory */
+static char lcd_flush_dcache; /* 1 to flush dcache after each lcd update */
+
+/* Flush LCD activity to the caches */
+void lcd_sync(void)
+{
+ /*
+ * flush_dcache_range() is declared in common.h but it seems that some
+ * architectures do not actually implement it. Is there a way to find
+ * out whether it exists? For now, ARM is safe.
+ */
+#if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
+ int line_length;
+
+ if (lcd_flush_dcache)
+ flush_dcache_range((ulong)lcd_base,
+ (ulong)(lcd_base + lcd_get_size(&line_length)));
+#endif
+}
+
+void lcd_set_flush_dcache(int flush)
+{
+ lcd_flush_dcache = (flush != 0);
+}
+
+static void lcd_stub_putc(struct stdio_dev *dev, const char c)
+{
+ lcd_putc(c);
+}
+
+static void lcd_stub_puts(struct stdio_dev *dev, const char *s)
+{
+ lcd_puts(s);
+}
+
+/* Small utility to check that you got the colours right */
+#ifdef LCD_TEST_PATTERN
+
+#if LCD_BPP == LCD_COLOR8
+#define N_BLK_VERT 2
+#define N_BLK_HOR 3
+
+static int test_colors[N_BLK_HOR * N_BLK_VERT] = {
+ CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW,
+ CONSOLE_COLOR_BLUE, CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN,
+}; /*LCD_BPP == LCD_COLOR8 */
+
+#elif LCD_BPP == LCD_COLOR16
+#define N_BLK_VERT 2
+#define N_BLK_HOR 4
+
+static int test_colors[N_BLK_HOR * N_BLK_VERT] = {
+ CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW, CONSOLE_COLOR_BLUE,
+ CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN, CONSOLE_COLOR_GREY, CONSOLE_COLOR_WHITE,
+};
+#endif /*LCD_BPP == LCD_COLOR16 */
+
+static void test_pattern(void)
+{
+ ushort v_max = panel_info.vl_row;
+ ushort h_max = panel_info.vl_col;
+ ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT;
+ ushort h_step = (h_max + N_BLK_HOR - 1) / N_BLK_HOR;
+ ushort v, h;
+#if LCD_BPP == LCD_COLOR8
+ uchar *pix = (uchar *)lcd_base;
+#elif LCD_BPP == LCD_COLOR16
+ ushort *pix = (ushort *)lcd_base;
+#endif
+
+ printf("[LCD] Test Pattern: %d x %d [%d x %d]\n",
+ h_max, v_max, h_step, v_step);
+
+ for (v = 0; v < v_max; ++v) {
+ uchar iy = v / v_step;
+ for (h = 0; h < h_max; ++h) {
+ uchar ix = N_BLK_HOR * iy + h / h_step;
+ *pix++ = test_colors[ix];
+ }
+ }
+}
+#endif /* LCD_TEST_PATTERN */
+
+/*
+ * With most lcd drivers the line length is set up
+ * by calculating it from panel_info parameters. Some
+ * drivers need to calculate the line length differently,
+ * so make the function weak to allow overriding it.
+ */
+__weak int lcd_get_size(int *line_length)
+{
+ *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
+ return *line_length * panel_info.vl_row;
+}
+
+int drv_lcd_init(void)
+{
+ struct stdio_dev lcddev;
+ int rc;
+
+ lcd_base = map_sysmem(gd->fb_base, 0);
+
+ lcd_init(lcd_base);
+
+ /* Device initialization */
+ memset(&lcddev, 0, sizeof(lcddev));
+
+ strcpy(lcddev.name, "lcd");
+ lcddev.ext = 0; /* No extensions */
+ lcddev.flags = DEV_FLAGS_OUTPUT; /* Output only */
+ lcddev.putc = lcd_stub_putc; /* 'putc' function */
+ lcddev.puts = lcd_stub_puts; /* 'puts' function */
+
+ rc = stdio_register(&lcddev);
+
+ return (rc == 0) ? 1 : rc;
+}
+
+void lcd_clear(void)
+{
+ int bg_color;
+ __maybe_unused ulong addr;
+ static int do_splash = 1;
+#if LCD_BPP == LCD_COLOR8
+ /* Setting the palette */
+ lcd_setcolreg(CONSOLE_COLOR_BLACK, 0, 0, 0);
+ lcd_setcolreg(CONSOLE_COLOR_RED, 0xFF, 0, 0);
+ lcd_setcolreg(CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
+ lcd_setcolreg(CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
+ lcd_setcolreg(CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
+ lcd_setcolreg(CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
+ lcd_setcolreg(CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
+ lcd_setcolreg(CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
+ lcd_setcolreg(CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
+#endif
+
+#ifndef CONFIG_SYS_WHITE_ON_BLACK
+ lcd_setfgcolor(CONSOLE_COLOR_BLACK);
+ lcd_setbgcolor(CONSOLE_COLOR_WHITE);
+ bg_color = CONSOLE_COLOR_WHITE;
+#else
+ lcd_setfgcolor(CONSOLE_COLOR_WHITE);
+ lcd_setbgcolor(CONSOLE_COLOR_BLACK);
+ bg_color = CONSOLE_COLOR_BLACK;
+#endif /* CONFIG_SYS_WHITE_ON_BLACK */
+
+#ifdef LCD_TEST_PATTERN
+ test_pattern();
+#else
+ /* set framebuffer to background color */
+#if (LCD_BPP != LCD_COLOR32)
+ memset((char *)lcd_base, bg_color, lcd_line_length * panel_info.vl_row);
+#else
+ u32 *ppix = lcd_base;
+ u32 i;
+ for (i = 0;
+ i < (lcd_line_length * panel_info.vl_row)/NBYTES(panel_info.vl_bpix);
+ i++) {
+ *ppix++ = bg_color;
+ }
+#endif
+#endif
+ /* setup text-console */
+ debug("[LCD] setting up console...\n");
+ lcd_init_console(lcd_base,
+ panel_info.vl_col,
+ panel_info.vl_row,
+ panel_info.vl_rot);
+ /* Paint the logo and retrieve LCD base address */
+ debug("[LCD] Drawing the logo...\n");
+ if (do_splash) {
+ if (splash_display() == 0) {
+ do_splash = 0;
+ lcd_sync();
+ return;
+ }
+ }
+
+ lcd_logo();
+#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
+ addr = (ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length;
+ lcd_init_console((void *)addr, panel_info.vl_col,
+ panel_info.vl_row, panel_info.vl_rot);
+#endif
+ lcd_sync();
+}
+
+static int lcd_init(void *lcdbase)
+{
+ debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
+ lcd_ctrl_init(lcdbase);
+
+ /*
+ * lcd_ctrl_init() of some drivers (i.e. bcm2835 on rpi) ignores
+ * the 'lcdbase' argument and uses custom lcd base address
+ * by setting up gd->fb_base. Check for this condition and fixup
+ * 'lcd_base' address.
+ */
+ if (map_to_sysmem(lcdbase) != gd->fb_base)
+ lcd_base = map_sysmem(gd->fb_base, 0);
+
+ debug("[LCD] Using LCD frambuffer at %p\n", lcd_base);
+
+ lcd_get_size(&lcd_line_length);
+ lcd_is_enabled = 1;
+ lcd_clear();
+ lcd_enable();
+
+ /* Initialize the console */
+ lcd_set_col(0);
+#ifdef CONFIG_LCD_INFO_BELOW_LOGO
+ lcd_set_row(7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT);
+#else
+ lcd_set_row(1); /* leave 1 blank line below logo */
+#endif
+
+ return 0;
+}
+
+/*
+ * This is called early in the system initialization to grab memory
+ * for the LCD controller.
+ * Returns new address for monitor, after reserving LCD buffer memory
+ *
+ * Note that this is running from ROM, so no write access to global data.
+ */
+ulong lcd_setmem(ulong addr)
+{
+ ulong size;
+ int line_length;
+
+ debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col,
+ panel_info.vl_row, NBITS(panel_info.vl_bpix));
+
+ size = lcd_get_size(&line_length);
+
+ /* Round up to nearest full page, or MMU section if defined */
+ size = ALIGN(size, CONFIG_LCD_ALIGNMENT);
+ addr = ALIGN(addr - CONFIG_LCD_ALIGNMENT + 1, CONFIG_LCD_ALIGNMENT);
+
+ /* Allocate pages for the frame buffer. */
+ addr -= size;
+
+ debug("Reserving %ldk for LCD Framebuffer at: %08lx\n",
+ size >> 10, addr);
+
+ return addr;
+}
+
+static void lcd_setfgcolor(int color)
+{
+ lcd_color_fg = color;
+}
+
+int lcd_getfgcolor(void)
+{
+ return lcd_color_fg;
+}
+
+static void lcd_setbgcolor(int color)
+{
+ lcd_color_bg = color;
+}
+
+int lcd_getbgcolor(void)
+{
+ return lcd_color_bg;
+}
+
+#ifdef CONFIG_LCD_LOGO
+__weak void lcd_logo_set_cmap(void)
+{
+ int i;
+ ushort *cmap = configuration_get_cmap();
+
+ for (i = 0; i < ARRAY_SIZE(bmp_logo_palette); ++i)
+ *cmap++ = bmp_logo_palette[i];
+}
+
+void lcd_logo_plot(int x, int y)
+{
+ ushort i, j;
+ uchar *bmap = &bmp_logo_bitmap[0];
+ unsigned bpix = NBITS(panel_info.vl_bpix);
+ uchar *fb = (uchar *)(lcd_base + y * lcd_line_length + x * bpix / 8);
+ ushort *fb16;
+
+ debug("Logo: width %d height %d colors %d\n",
+ BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS);
+
+ if (bpix < 12) {
+ WATCHDOG_RESET();
+ lcd_logo_set_cmap();
+ WATCHDOG_RESET();
+
+ for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
+ memcpy(fb, bmap, BMP_LOGO_WIDTH);
+ bmap += BMP_LOGO_WIDTH;
+ fb += panel_info.vl_col;
+ }
+ }
+ else { /* true color mode */
+ u16 col16;
+ fb16 = (ushort *)fb;
+ for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
+ for (j = 0; j < BMP_LOGO_WIDTH; j++) {
+ col16 = bmp_logo_palette[(bmap[j]-16)];
+ fb16[j] =
+ ((col16 & 0x000F) << 1) |
+ ((col16 & 0x00F0) << 3) |
+ ((col16 & 0x0F00) << 4);
+ }
+ bmap += BMP_LOGO_WIDTH;
+ fb16 += panel_info.vl_col;
+ }
+ }
+
+ WATCHDOG_RESET();
+ lcd_sync();
+}
+#else
+static inline void lcd_logo_plot(int x, int y) {}
+#endif /* CONFIG_LCD_LOGO */
+
+#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
+#ifdef CONFIG_SPLASH_SCREEN_ALIGN
+
+static void splash_align_axis(int *axis, unsigned long panel_size,
+ unsigned long picture_size)
+{
+ unsigned long panel_picture_delta = panel_size - picture_size;
+ unsigned long axis_alignment;
+
+ if (*axis == BMP_ALIGN_CENTER)
+ axis_alignment = panel_picture_delta / 2;
+ else if (*axis < 0)
+ axis_alignment = panel_picture_delta + *axis + 1;
+ else
+ return;
+
+ *axis = max(0, (int)axis_alignment);
+}
+#endif
+
+#ifdef CONFIG_LCD_BMP_RLE8
+#define BMP_RLE8_ESCAPE 0
+#define BMP_RLE8_EOL 0
+#define BMP_RLE8_EOBMP 1
+#define BMP_RLE8_DELTA 2
+
+static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap,
+ int cnt)
+{
+ while (cnt > 0) {
+ *(*fbp)++ = cmap[*bmap++];
+ cnt--;
+ }
+}
+
+static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt)
+{
+ ushort *fb = *fbp;
+ int cnt_8copy = cnt >> 3;
+
+ cnt -= cnt_8copy << 3;
+ while (cnt_8copy > 0) {
+ *fb++ = c;
+ *fb++ = c;
+ *fb++ = c;
+ *fb++ = c;
+ *fb++ = c;
+ *fb++ = c;
+ *fb++ = c;
+ *fb++ = c;
+ cnt_8copy--;
+ }
+ while (cnt > 0) {
+ *fb++ = c;
+ cnt--;
+ }
+ *fbp = fb;
+}
+
+/*
+ * Do not call this function directly, must be called from lcd_display_bitmap.
+ */
+static void lcd_display_rle8_bitmap(struct bmp_image *bmp, ushort *cmap,
+ uchar *fb, int x_off, int y_off)
+{
+ uchar *bmap;
+ ulong width, height;
+ ulong cnt, runlen;
+ int x, y;
+ int decode = 1;
+
+ width = get_unaligned_le32(&bmp->header.width);
+ height = get_unaligned_le32(&bmp->header.height);
+ bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
+
+ x = 0;
+ y = height - 1;
+
+ while (decode) {
+ if (bmap[0] == BMP_RLE8_ESCAPE) {
+ switch (bmap[1]) {
+ case BMP_RLE8_EOL:
+ /* end of line */
+ bmap += 2;
+ x = 0;
+ y--;
+ /* 16bpix, 2-byte per pixel, width should *2 */
+ fb -= (width * 2 + lcd_line_length);
+ break;
+ case BMP_RLE8_EOBMP:
+ /* end of bitmap */
+ decode = 0;
+ break;
+ case BMP_RLE8_DELTA:
+ /* delta run */
+ x += bmap[2];
+ y -= bmap[3];
+ /* 16bpix, 2-byte per pixel, x should *2 */
+ fb = (uchar *) (lcd_base + (y + y_off - 1)
+ * lcd_line_length + (x + x_off) * 2);
+ bmap += 4;
+ break;
+ default:
+ /* unencoded run */
+ runlen = bmap[1];
+ bmap += 2;
+ if (y < height) {
+ if (x < width) {
+ if (x + runlen > width)
+ cnt = width - x;
+ else
+ cnt = runlen;
+ draw_unencoded_bitmap(
+ (ushort **)&fb,
+ bmap, cmap, cnt);
+ }
+ x += runlen;
+ }
+ bmap += runlen;
+ if (runlen & 1)
+ bmap++;
+ }
+ } else {
+ /* encoded run */
+ if (y < height) {
+ runlen = bmap[0];
+ if (x < width) {
+ /* aggregate the same code */
+ while (bmap[0] == 0xff &&
+ bmap[2] != BMP_RLE8_ESCAPE &&
+ bmap[1] == bmap[3]) {
+ runlen += bmap[2];
+ bmap += 2;
+ }
+ if (x + runlen > width)
+ cnt = width - x;
+ else
+ cnt = runlen;
+ draw_encoded_bitmap((ushort **)&fb,
+ cmap[bmap[1]], cnt);
+ }
+ x += runlen;
+ }
+ bmap += 2;
+ }
+ }
+}
+#endif
+
+__weak void fb_put_byte(uchar **fb, uchar **from)
+{
+ *(*fb)++ = *(*from)++;
+}
+
+#if defined(CONFIG_BMP_16BPP)
+__weak void fb_put_word(uchar **fb, uchar **from)
+{
+ *(*fb)++ = *(*from)++;
+ *(*fb)++ = *(*from)++;
+}
+#endif /* CONFIG_BMP_16BPP */
+
+__weak void lcd_set_cmap(struct bmp_image *bmp, unsigned colors)
+{
+ int i;
+ struct bmp_color_table_entry cte;
+ ushort *cmap = configuration_get_cmap();
+
+ for (i = 0; i < colors; ++i) {
+ cte = bmp->color_table[i];
+ *cmap = (((cte.red) << 8) & 0xf800) |
+ (((cte.green) << 3) & 0x07e0) |
+ (((cte.blue) >> 3) & 0x001f);
+ cmap++;
+ }
+}
+
+int lcd_display_bitmap(ulong bmp_image, int x, int y)
+{
+ ushort *cmap_base = NULL;
+ ushort i, j;
+ uchar *fb;
+ struct bmp_image *bmp = (struct bmp_image *)map_sysmem(bmp_image, 0);
+ uchar *bmap;
+ ushort padded_width;
+ unsigned long width, height, byte_width;
+ unsigned long pwidth = panel_info.vl_col;
+ unsigned colors, bpix, bmp_bpix;
+ int hdr_size;
+ struct bmp_color_table_entry *palette;
+
+ if (!bmp || !(bmp->header.signature[0] == 'B' &&
+ bmp->header.signature[1] == 'M')) {
+ printf("Error: no valid bmp image at %lx\n", bmp_image);
+
+ return 1;
+ }
+
+ palette = bmp->color_table;
+ width = get_unaligned_le32(&bmp->header.width);
+ height = get_unaligned_le32(&bmp->header.height);
+ bmp_bpix = get_unaligned_le16(&bmp->header.bit_count);
+ hdr_size = get_unaligned_le16(&bmp->header.size);
+ debug("hdr_size=%d, bmp_bpix=%d\n", hdr_size, bmp_bpix);
+
+ colors = 1 << bmp_bpix;
+
+ bpix = NBITS(panel_info.vl_bpix);
+
+ if (bpix != 1 && bpix != 8 && bpix != 16 && bpix != 32) {
+ printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+ bpix, bmp_bpix);
+
+ return 1;
+ }
+
+ /*
+ * We support displaying 8bpp BMPs on 16bpp LCDs
+ * and displaying 24bpp BMPs on 32bpp LCDs
+ * */
+ if (bpix != bmp_bpix &&
+ !(bmp_bpix == 8 && bpix == 16) &&
+ !(bmp_bpix == 24 && bpix == 32)) {
+ printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+ bpix, get_unaligned_le16(&bmp->header.bit_count));
+ return 1;
+ }
+
+ debug("Display-bmp: %d x %d with %d colors, display %d\n",
+ (int)width, (int)height, (int)colors, 1 << bpix);
+
+ if (bmp_bpix == 8)
+ lcd_set_cmap(bmp, colors);
+
+ padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width);
+
+#ifdef CONFIG_SPLASH_SCREEN_ALIGN
+ splash_align_axis(&x, pwidth, width);
+ splash_align_axis(&y, panel_info.vl_row, height);
+#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
+
+ if ((x + width) > pwidth)
+ width = pwidth - x;
+ if ((y + height) > panel_info.vl_row)
+ height = panel_info.vl_row - y;
+
+ bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
+ fb = (uchar *)(lcd_base +
+ (y + height - 1) * lcd_line_length + x * bpix / 8);
+
+ switch (bmp_bpix) {
+ case 1:
+ case 8: {
+ cmap_base = configuration_get_cmap();
+#ifdef CONFIG_LCD_BMP_RLE8
+ u32 compression = get_unaligned_le32(&bmp->header.compression);
+ debug("compressed %d %d\n", compression, BMP_BI_RLE8);
+ if (compression == BMP_BI_RLE8) {
+ if (bpix != 16) {
+ /* TODO implement render code for bpix != 16 */
+ printf("Error: only support 16 bpix");
+ return 1;
+ }
+ lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y);
+ break;
+ }
+#endif
+
+ if (bpix != 16)
+ byte_width = width;
+ else
+ byte_width = width * 2;
+
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++) {
+ if (bpix != 16) {
+ fb_put_byte(&fb, &bmap);
+ } else {
+ struct bmp_color_table_entry *entry;
+ uint val;
+
+ if (cmap_base) {
+ val = cmap_base[*bmap];
+ } else {
+ entry = &palette[*bmap];
+ val = entry->blue >> 3 |
+ entry->green >> 2 << 5 |
+ entry->red >> 3 << 11;
+ }
+ *(uint16_t *)fb = val;
+ bmap++;
+ fb += sizeof(uint16_t) / sizeof(*fb);
+ }
+ }
+ bmap += (padded_width - width);
+ fb -= byte_width + lcd_line_length;
+ }
+ break;
+ }
+#if defined(CONFIG_BMP_16BPP)
+ case 16:
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++)
+ fb_put_word(&fb, &bmap);
+
+ bmap += (padded_width - width) * 2;
+ fb -= width * 2 + lcd_line_length;
+ }
+ break;
+#endif /* CONFIG_BMP_16BPP */
+#if defined(CONFIG_BMP_24BPP)
+ case 24:
+ for (i = 0; i < height; ++i) {
+ for (j = 0; j < width; j++) {
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = 0;
+ }
+ fb -= lcd_line_length + width * (bpix / 8);
+ }
+ break;
+#endif /* CONFIG_BMP_24BPP */
+#if defined(CONFIG_BMP_32BPP)
+ case 32:
+ for (i = 0; i < height; ++i) {
+ for (j = 0; j < width; j++) {
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ }
+ fb -= lcd_line_length + width * (bpix / 8);
+ }
+ break;
+#endif /* CONFIG_BMP_32BPP */
+ default:
+ break;
+ };
+
+ lcd_sync();
+ return 0;
+}
+#endif
+
+static void lcd_logo(void)
+{
+ lcd_logo_plot(0, 0);
+
+#ifdef CONFIG_LCD_INFO
+ lcd_set_col(LCD_INFO_X / VIDEO_FONT_WIDTH);
+ lcd_set_row(LCD_INFO_Y / VIDEO_FONT_HEIGHT);
+ lcd_show_board_info();
+#endif /* CONFIG_LCD_INFO */
+}
+
+#ifdef CONFIG_SPLASHIMAGE_GUARD
+static int on_splashimage(const char *name, const char *value, enum env_op op,
+ int flags)
+{
+ ulong addr;
+ int aligned;
+
+ if (op == env_op_delete)
+ return 0;
+
+ addr = simple_strtoul(value, NULL, 16);
+ /* See README.displaying-bmps */
+ aligned = (addr % 4 == 2);
+ if (!aligned) {
+ printf("Invalid splashimage value. Value must be 16 bit aligned, but not 32 bit aligned\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+U_BOOT_ENV_CALLBACK(splashimage, on_splashimage);
+#endif
+
+int lcd_get_pixel_width(void)
+{
+ return panel_info.vl_col;
+}
+
+int lcd_get_pixel_height(void)
+{
+ return panel_info.vl_row;
+}
diff --git a/roms/u-boot/common/lcd_console.c b/roms/u-boot/common/lcd_console.c
new file mode 100644
index 000000000..1a246c492
--- /dev/null
+++ b/roms/u-boot/common/lcd_console.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001-2015
+ * DENX Software Engineering -- wd@denx.de
+ * Compulab Ltd - http://compulab.co.il/
+ * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
+ */
+
+#include <common.h>
+#include <command.h>
+#include <lcd.h>
+#include <log.h>
+#include <serial.h>
+#include <video_font.h> /* Get font data, width and height */
+#if defined(CONFIG_LCD_LOGO)
+#include <bmp_logo.h>
+#endif
+
+static struct console_t cons;
+
+void lcd_set_col(short col)
+{
+ cons.curr_col = col;
+}
+
+void lcd_set_row(short row)
+{
+ cons.curr_row = row;
+}
+
+void lcd_position_cursor(unsigned col, unsigned row)
+{
+ cons.curr_col = min_t(short, col, cons.cols - 1);
+ cons.curr_row = min_t(short, row, cons.rows - 1);
+}
+
+int lcd_get_screen_rows(void)
+{
+ return cons.rows;
+}
+
+int lcd_get_screen_columns(void)
+{
+ return cons.cols;
+}
+
+static void lcd_putc_xy0(struct console_t *pcons, ushort x, ushort y, char c)
+{
+ int fg_color = lcd_getfgcolor();
+ int bg_color = lcd_getbgcolor();
+ int i, row;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ y * pcons->lcdsizex +
+ x;
+
+ for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
+ uchar bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
+ for (i = 0; i < VIDEO_FONT_WIDTH; ++i) {
+ *dst++ = (bits & 0x80) ? fg_color : bg_color;
+ bits <<= 1;
+ }
+ dst += (pcons->lcdsizex - VIDEO_FONT_WIDTH);
+ }
+}
+
+static inline void console_setrow0(struct console_t *pcons, u32 row, int clr)
+{
+ int i;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ row * VIDEO_FONT_HEIGHT *
+ pcons->lcdsizex;
+
+ for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
+ *dst++ = clr;
+}
+
+static inline void console_moverow0(struct console_t *pcons,
+ u32 rowdst, u32 rowsrc)
+{
+ int i;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ rowdst * VIDEO_FONT_HEIGHT *
+ pcons->lcdsizex;
+
+ fbptr_t *src = (fbptr_t *)pcons->fbbase +
+ rowsrc * VIDEO_FONT_HEIGHT *
+ pcons->lcdsizex;
+
+ for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
+ *dst++ = *src++;
+}
+
+static inline void console_back(void)
+{
+ if (--cons.curr_col < 0) {
+ cons.curr_col = cons.cols - 1;
+ if (--cons.curr_row < 0)
+ cons.curr_row = 0;
+ }
+
+ cons.fp_putc_xy(&cons,
+ cons.curr_col * VIDEO_FONT_WIDTH,
+ cons.curr_row * VIDEO_FONT_HEIGHT, ' ');
+}
+
+static inline void console_newline(void)
+{
+ const int rows = CONFIG_CONSOLE_SCROLL_LINES;
+ int bg_color = lcd_getbgcolor();
+ int i;
+
+ cons.curr_col = 0;
+
+ /* Check if we need to scroll the terminal */
+ if (++cons.curr_row >= cons.rows) {
+ for (i = 0; i < cons.rows-rows; i++)
+ cons.fp_console_moverow(&cons, i, i+rows);
+ for (i = 0; i < rows; i++)
+ cons.fp_console_setrow(&cons, cons.rows-i-1, bg_color);
+ cons.curr_row -= rows;
+ }
+ lcd_sync();
+}
+
+void console_calc_rowcol(struct console_t *pcons, u32 sizex, u32 sizey)
+{
+ pcons->cols = sizex / VIDEO_FONT_WIDTH;
+#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
+ pcons->rows = (pcons->lcdsizey - BMP_LOGO_HEIGHT);
+ pcons->rows /= VIDEO_FONT_HEIGHT;
+#else
+ pcons->rows = sizey / VIDEO_FONT_HEIGHT;
+#endif
+}
+
+void __weak lcd_init_console_rot(struct console_t *pcons)
+{
+ return;
+}
+
+void lcd_init_console(void *address, int vl_cols, int vl_rows, int vl_rot)
+{
+ memset(&cons, 0, sizeof(cons));
+ cons.fbbase = address;
+
+ cons.lcdsizex = vl_cols;
+ cons.lcdsizey = vl_rows;
+ cons.lcdrot = vl_rot;
+
+ cons.fp_putc_xy = &lcd_putc_xy0;
+ cons.fp_console_moverow = &console_moverow0;
+ cons.fp_console_setrow = &console_setrow0;
+ console_calc_rowcol(&cons, cons.lcdsizex, cons.lcdsizey);
+
+ lcd_init_console_rot(&cons);
+
+ debug("lcd_console: have %d/%d col/rws on scr %dx%d (%d deg rotated)\n",
+ cons.cols, cons.rows, cons.lcdsizex, cons.lcdsizey, vl_rot);
+}
+
+void lcd_putc(const char c)
+{
+ if (!lcd_is_enabled) {
+ serial_putc(c);
+
+ return;
+ }
+
+ switch (c) {
+ case '\r':
+ cons.curr_col = 0;
+ return;
+ case '\n':
+ console_newline();
+
+ return;
+ case '\t': /* Tab (8 chars alignment) */
+ cons.curr_col += 8;
+ cons.curr_col &= ~7;
+
+ if (cons.curr_col >= cons.cols)
+ console_newline();
+
+ return;
+ case '\b':
+ console_back();
+
+ return;
+ default:
+ cons.fp_putc_xy(&cons,
+ cons.curr_col * VIDEO_FONT_WIDTH,
+ cons.curr_row * VIDEO_FONT_HEIGHT, c);
+ if (++cons.curr_col >= cons.cols)
+ console_newline();
+ }
+}
+
+void lcd_puts(const char *s)
+{
+ if (!lcd_is_enabled) {
+ serial_puts(s);
+
+ return;
+ }
+
+ while (*s)
+ lcd_putc(*s++);
+
+ lcd_sync();
+}
+
+void lcd_printf(const char *fmt, ...)
+{
+ va_list args;
+ char buf[CONFIG_SYS_PBSIZE];
+
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+
+ lcd_puts(buf);
+}
+
+static int do_lcd_setcursor(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ unsigned int col, row;
+
+ if (argc != 3)
+ return CMD_RET_USAGE;
+
+ col = simple_strtoul(argv[1], NULL, 10);
+ row = simple_strtoul(argv[2], NULL, 10);
+ lcd_position_cursor(col, row);
+
+ return 0;
+}
+
+static int do_lcd_puts(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ if (argc != 2)
+ return CMD_RET_USAGE;
+
+ lcd_puts(argv[1]);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ setcurs, 3, 1, do_lcd_setcursor,
+ "set cursor position within screen",
+ " <col> <row> in character"
+);
+
+U_BOOT_CMD(
+ lcdputs, 2, 1, do_lcd_puts,
+ "print string on lcd-framebuffer",
+ " <string>"
+);
+
diff --git a/roms/u-boot/common/lcd_console_rotation.c b/roms/u-boot/common/lcd_console_rotation.c
new file mode 100644
index 000000000..a5f5c6da7
--- /dev/null
+++ b/roms/u-boot/common/lcd_console_rotation.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015
+ * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
+ */
+
+#include <common.h>
+#include <lcd.h>
+#include <video_font.h> /* Get font data, width and height */
+
+static void lcd_putc_xy90(struct console_t *pcons, ushort x, ushort y, char c)
+{
+ int fg_color = lcd_getfgcolor();
+ int bg_color = lcd_getbgcolor();
+ int col, i;
+
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ (x+1) * pcons->lcdsizex -
+ y;
+
+ uchar msk = 0x80;
+ uchar *pfont = video_fontdata + c * VIDEO_FONT_HEIGHT;
+ for (col = 0; col < VIDEO_FONT_WIDTH; ++col) {
+ for (i = 0; i < VIDEO_FONT_HEIGHT; ++i)
+ *dst-- = (*(pfont + i) & msk) ? fg_color : bg_color;
+ msk >>= 1;
+ dst += (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
+ }
+}
+
+static inline void console_setrow90(struct console_t *pcons, u32 row, int clr)
+{
+ int i, j;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ pcons->lcdsizex -
+ row*VIDEO_FONT_HEIGHT+1;
+
+ for (j = 0; j < pcons->lcdsizey; j++) {
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst-- = clr;
+ dst += (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
+ }
+}
+
+static inline void console_moverow90(struct console_t *pcons,
+ u32 rowdst, u32 rowsrc)
+{
+ int i, j;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ pcons->lcdsizex -
+ (rowdst*VIDEO_FONT_HEIGHT+1);
+
+ fbptr_t *src = (fbptr_t *)pcons->fbbase +
+ pcons->lcdsizex -
+ (rowsrc*VIDEO_FONT_HEIGHT+1);
+
+ for (j = 0; j < pcons->lcdsizey; j++) {
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst-- = *src--;
+ src += (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
+ dst += (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
+ }
+}
+static void lcd_putc_xy180(struct console_t *pcons, ushort x, ushort y, char c)
+{
+ int fg_color = lcd_getfgcolor();
+ int bg_color = lcd_getbgcolor();
+ int i, row;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ pcons->lcdsizex +
+ pcons->lcdsizey * pcons->lcdsizex -
+ y * pcons->lcdsizex -
+ (x+1);
+
+ for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
+ uchar bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
+
+ for (i = 0; i < VIDEO_FONT_WIDTH; ++i) {
+ *dst-- = (bits & 0x80) ? fg_color : bg_color;
+ bits <<= 1;
+ }
+ dst -= (pcons->lcdsizex - VIDEO_FONT_WIDTH);
+ }
+}
+
+static inline void console_setrow180(struct console_t *pcons, u32 row, int clr)
+{
+ int i;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ (pcons->rows-row-1) * VIDEO_FONT_HEIGHT *
+ pcons->lcdsizex;
+
+ for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
+ *dst++ = clr;
+}
+
+static inline void console_moverow180(struct console_t *pcons,
+ u32 rowdst, u32 rowsrc)
+{
+ int i;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ (pcons->rows-rowdst-1) * VIDEO_FONT_HEIGHT *
+ pcons->lcdsizex;
+
+ fbptr_t *src = (fbptr_t *)pcons->fbbase +
+ (pcons->rows-rowsrc-1) * VIDEO_FONT_HEIGHT *
+ pcons->lcdsizex;
+
+ for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
+ *dst++ = *src++;
+}
+
+static void lcd_putc_xy270(struct console_t *pcons, ushort x, ushort y, char c)
+{
+ int fg_color = lcd_getfgcolor();
+ int bg_color = lcd_getbgcolor();
+ int i, col;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ pcons->lcdsizey * pcons->lcdsizex -
+ (x+1) * pcons->lcdsizex +
+ y;
+
+ uchar msk = 0x80;
+ uchar *pfont = video_fontdata + c * VIDEO_FONT_HEIGHT;
+ for (col = 0; col < VIDEO_FONT_WIDTH; ++col) {
+ for (i = 0; i < VIDEO_FONT_HEIGHT; ++i)
+ *dst++ = (*(pfont + i) & msk) ? fg_color : bg_color;
+ msk >>= 1;
+ dst -= (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
+ }
+}
+
+static inline void console_setrow270(struct console_t *pcons, u32 row, int clr)
+{
+ int i, j;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ row*VIDEO_FONT_HEIGHT;
+
+ for (j = 0; j < pcons->lcdsizey; j++) {
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst++ = clr;
+ dst += (pcons->lcdsizex - VIDEO_FONT_HEIGHT);
+ }
+}
+
+static inline void console_moverow270(struct console_t *pcons,
+ u32 rowdst, u32 rowsrc)
+{
+ int i, j;
+ fbptr_t *dst = (fbptr_t *)pcons->fbbase +
+ rowdst*VIDEO_FONT_HEIGHT;
+
+ fbptr_t *src = (fbptr_t *)pcons->fbbase +
+ rowsrc*VIDEO_FONT_HEIGHT;
+
+ for (j = 0; j < pcons->lcdsizey; j++) {
+ for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
+ *dst++ = *src++;
+ src += (pcons->lcdsizex - VIDEO_FONT_HEIGHT);
+ dst += (pcons->lcdsizex - VIDEO_FONT_HEIGHT);
+ }
+}
+
+static void console_calc_rowcol_rot(struct console_t *pcons)
+{
+ if (pcons->lcdrot == 1 || pcons->lcdrot == 3)
+ console_calc_rowcol(pcons, pcons->lcdsizey, pcons->lcdsizex);
+ else
+ console_calc_rowcol(pcons, pcons->lcdsizex, pcons->lcdsizey);
+}
+
+void lcd_init_console_rot(struct console_t *pcons)
+{
+ if (pcons->lcdrot == 0) {
+ return;
+ } else if (pcons->lcdrot == 1) {
+ pcons->fp_putc_xy = &lcd_putc_xy90;
+ pcons->fp_console_moverow = &console_moverow90;
+ pcons->fp_console_setrow = &console_setrow90;
+ } else if (pcons->lcdrot == 2) {
+ pcons->fp_putc_xy = &lcd_putc_xy180;
+ pcons->fp_console_moverow = &console_moverow180;
+ pcons->fp_console_setrow = &console_setrow180;
+ } else if (pcons->lcdrot == 3) {
+ pcons->fp_putc_xy = &lcd_putc_xy270;
+ pcons->fp_console_moverow = &console_moverow270;
+ pcons->fp_console_setrow = &console_setrow270;
+ } else {
+ printf("%s: invalid framebuffer rotation (%d)!\n",
+ __func__, pcons->lcdrot);
+ return;
+ }
+ console_calc_rowcol_rot(pcons);
+}
diff --git a/roms/u-boot/common/lcd_simplefb.c b/roms/u-boot/common/lcd_simplefb.c
new file mode 100644
index 000000000..1650615cd
--- /dev/null
+++ b/roms/u-boot/common/lcd_simplefb.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Simplefb device tree support
+ *
+ * (C) Copyright 2015
+ * Stephen Warren <swarren@wwwdotorg.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <lcd.h>
+#include <fdt_support.h>
+#include <asm/global_data.h>
+#include <linux/libfdt.h>
+#include <video.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int lcd_dt_simplefb_configure_node(void *blob, int off)
+{
+ int xsize, ysize;
+ int bpix; /* log2 of bits per pixel */
+ const char *name;
+ ulong fb_base;
+#ifdef CONFIG_DM_VIDEO
+ struct video_uc_plat *plat;
+ struct video_priv *uc_priv;
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
+ if (ret)
+ return ret;
+ uc_priv = dev_get_uclass_priv(dev);
+ plat = dev_get_uclass_plat(dev);
+ xsize = uc_priv->xsize;
+ ysize = uc_priv->ysize;
+ bpix = uc_priv->bpix;
+ fb_base = plat->base;
+#else
+ xsize = lcd_get_pixel_width();
+ ysize = lcd_get_pixel_height();
+ bpix = LCD_BPP;
+ fb_base = gd->fb_base;
+#endif
+ switch (bpix) {
+ case 4: /* VIDEO_BPP16 */
+ name = "r5g6b5";
+ break;
+ case 5: /* VIDEO_BPP32 */
+ name = "a8r8g8b8";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return fdt_setup_simplefb_node(blob, off, fb_base, xsize, ysize,
+ xsize * (1 << bpix) / 8, name);
+}
+
+int lcd_dt_simplefb_add_node(void *blob)
+{
+ static const char compat[] = "simple-framebuffer";
+ static const char disabled[] = "disabled";
+ int off, ret;
+
+ off = fdt_add_subnode(blob, 0, "framebuffer");
+ if (off < 0)
+ return -1;
+
+ ret = fdt_setprop(blob, off, "status", disabled, sizeof(disabled));
+ if (ret < 0)
+ return -1;
+
+ ret = fdt_setprop(blob, off, "compatible", compat, sizeof(compat));
+ if (ret < 0)
+ return -1;
+
+ return lcd_dt_simplefb_configure_node(blob, off);
+}
+
+int lcd_dt_simplefb_enable_existing_node(void *blob)
+{
+ int off;
+
+ off = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer");
+ if (off < 0)
+ return -1;
+
+ return lcd_dt_simplefb_configure_node(blob, off);
+}
diff --git a/roms/u-boot/common/log.c b/roms/u-boot/common/log.c
new file mode 100644
index 000000000..ea407c6db
--- /dev/null
+++ b/roms/u-boot/common/log.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Logging support
+ *
+ * Copyright (c) 2017 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <dm/uclass.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *const log_cat_name[] = {
+ "none",
+ "arch",
+ "board",
+ "core",
+ "driver-model",
+ "device-tree",
+ "efi",
+ "alloc",
+ "sandbox",
+ "bloblist",
+ "devres",
+ "acpi",
+ "boot",
+};
+
+_Static_assert(ARRAY_SIZE(log_cat_name) == LOGC_COUNT - LOGC_NONE,
+ "log_cat_name size");
+
+static const char *const log_level_name[] = {
+ "EMERG",
+ "ALERT",
+ "CRIT",
+ "ERR",
+ "WARNING",
+ "NOTICE",
+ "INFO",
+ "DEBUG",
+ "CONTENT",
+ "IO",
+};
+
+_Static_assert(ARRAY_SIZE(log_level_name) == LOGL_COUNT, "log_level_name size");
+
+/* All error responses MUST begin with '<' */
+const char *log_get_cat_name(enum log_category_t cat)
+{
+ const char *name;
+
+ if (cat < 0 || cat >= LOGC_COUNT)
+ return "<invalid>";
+ if (cat >= LOGC_NONE)
+ return log_cat_name[cat - LOGC_NONE];
+
+#if CONFIG_IS_ENABLED(DM)
+ name = uclass_get_name((enum uclass_id)cat);
+#else
+ name = NULL;
+#endif
+
+ return name ? name : "<missing>";
+}
+
+enum log_category_t log_get_cat_by_name(const char *name)
+{
+ enum uclass_id id;
+ int i;
+
+ for (i = LOGC_NONE; i < LOGC_COUNT; i++)
+ if (!strcmp(name, log_cat_name[i - LOGC_NONE]))
+ return i;
+ id = uclass_get_by_name(name);
+ if (id != UCLASS_INVALID)
+ return (enum log_category_t)id;
+
+ return LOGC_NONE;
+}
+
+const char *log_get_level_name(enum log_level_t level)
+{
+ if (level >= LOGL_COUNT)
+ return "INVALID";
+ return log_level_name[level];
+}
+
+enum log_level_t log_get_level_by_name(const char *name)
+{
+ int i;
+
+ for (i = 0; i < LOGL_COUNT; i++) {
+ if (!strcasecmp(log_level_name[i], name))
+ return i;
+ }
+
+ return LOGL_NONE;
+}
+
+struct log_device *log_device_find_by_name(const char *drv_name)
+{
+ struct log_device *ldev;
+
+ list_for_each_entry(ldev, &gd->log_head, sibling_node) {
+ if (!strcmp(drv_name, ldev->drv->name))
+ return ldev;
+ }
+
+ return NULL;
+}
+
+bool log_has_cat(enum log_category_t cat_list[], enum log_category_t cat)
+{
+ int i;
+
+ for (i = 0; i < LOGF_MAX_CATEGORIES && cat_list[i] != LOGC_END; i++) {
+ if (cat_list[i] == cat)
+ return true;
+ }
+
+ return false;
+}
+
+bool log_has_file(const char *file_list, const char *file)
+{
+ int file_len = strlen(file);
+ const char *s, *p;
+ int substr_len;
+
+ for (s = file_list; *s; s = p + (*p != '\0')) {
+ p = strchrnul(s, ',');
+ substr_len = p - s;
+ if (file_len >= substr_len &&
+ !strncmp(file + file_len - substr_len, s, substr_len))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * log_passes_filters() - check if a log record passes the filters for a device
+ *
+ * @ldev: Log device to check
+ * @rec: Log record to check
+ * @return true if @rec is not blocked by the filters in @ldev, false if it is
+ */
+static bool log_passes_filters(struct log_device *ldev, struct log_rec *rec)
+{
+ struct log_filter *filt;
+
+ if (rec->flags & LOGRECF_FORCE_DEBUG)
+ return true;
+
+ /* If there are no filters, filter on the default log level */
+ if (list_empty(&ldev->filter_head)) {
+ if (rec->level > gd->default_log_level)
+ return false;
+ return true;
+ }
+
+ list_for_each_entry(filt, &ldev->filter_head, sibling_node) {
+ if (filt->flags & LOGFF_LEVEL_MIN) {
+ if (rec->level < filt->level)
+ continue;
+ } else if (rec->level > filt->level) {
+ continue;
+ }
+
+ if ((filt->flags & LOGFF_HAS_CAT) &&
+ !log_has_cat(filt->cat_list, rec->cat))
+ continue;
+
+ if (filt->file_list &&
+ !log_has_file(filt->file_list, rec->file))
+ continue;
+
+ if (filt->flags & LOGFF_DENY)
+ return false;
+ else
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * log_dispatch() - Send a log record to all log devices for processing
+ *
+ * The log record is sent to each log device in turn, skipping those which have
+ * filters which block the record.
+ *
+ * All log messages created while processing log record @rec are ignored.
+ *
+ * @rec: log record to dispatch
+ * Return: 0 msg sent, 1 msg not sent while already dispatching another msg
+ */
+static int log_dispatch(struct log_rec *rec, const char *fmt, va_list args)
+{
+ struct log_device *ldev;
+ char buf[CONFIG_SYS_CBSIZE];
+
+ /*
+ * When a log driver writes messages (e.g. via the network stack) this
+ * may result in further generated messages. We cannot process them here
+ * as this might result in infinite recursion.
+ */
+ if (gd->processing_msg)
+ return 1;
+
+ /* Emit message */
+ gd->processing_msg = true;
+ list_for_each_entry(ldev, &gd->log_head, sibling_node) {
+ if ((ldev->flags & LOGDF_ENABLE) &&
+ log_passes_filters(ldev, rec)) {
+ if (!rec->msg) {
+ int len;
+
+ len = vsnprintf(buf, sizeof(buf), fmt, args);
+ rec->msg = buf;
+ gd->log_cont = len && buf[len - 1] != '\n';
+ }
+ ldev->drv->emit(ldev, rec);
+ }
+ }
+ gd->processing_msg = false;
+ return 0;
+}
+
+int _log(enum log_category_t cat, enum log_level_t level, const char *file,
+ int line, const char *func, const char *fmt, ...)
+{
+ struct log_rec rec;
+ va_list args;
+
+ if (!gd)
+ return -ENOSYS;
+
+ /* Check for message continuation */
+ if (cat == LOGC_CONT)
+ cat = gd->logc_prev;
+ if (level == LOGL_CONT)
+ level = gd->logl_prev;
+
+ rec.cat = cat;
+ rec.level = level & LOGL_LEVEL_MASK;
+ rec.flags = 0;
+ if (level & LOGL_FORCE_DEBUG)
+ rec.flags |= LOGRECF_FORCE_DEBUG;
+ if (gd->log_cont)
+ rec.flags |= LOGRECF_CONT;
+ rec.file = file;
+ rec.line = line;
+ rec.func = func;
+ rec.msg = NULL;
+
+ if (!(gd->flags & GD_FLG_LOG_READY)) {
+ gd->log_drop_count++;
+
+ /* display dropped traces with console puts and DEBUG_UART */
+ if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL ||
+ rec.flags & LOGRECF_FORCE_DEBUG) {
+ char buf[CONFIG_SYS_CBSIZE];
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ puts(buf);
+ va_end(args);
+ }
+
+ return -ENOSYS;
+ }
+ va_start(args, fmt);
+ if (!log_dispatch(&rec, fmt, args)) {
+ gd->logc_prev = cat;
+ gd->logl_prev = level;
+ }
+ va_end(args);
+
+ return 0;
+}
+
+int log_add_filter_flags(const char *drv_name, enum log_category_t cat_list[],
+ enum log_level_t level, const char *file_list,
+ int flags)
+{
+ struct log_filter *filt;
+ struct log_device *ldev;
+ int ret;
+ int i;
+
+ ldev = log_device_find_by_name(drv_name);
+ if (!ldev)
+ return -ENOENT;
+ filt = calloc(1, sizeof(*filt));
+ if (!filt)
+ return -ENOMEM;
+
+ filt->flags = flags;
+ if (cat_list) {
+ filt->flags |= LOGFF_HAS_CAT;
+ for (i = 0; ; i++) {
+ if (i == ARRAY_SIZE(filt->cat_list)) {
+ ret = -ENOSPC;
+ goto err;
+ }
+ filt->cat_list[i] = cat_list[i];
+ if (cat_list[i] == LOGC_END)
+ break;
+ }
+ }
+ filt->level = level;
+ if (file_list) {
+ filt->file_list = strdup(file_list);
+ if (!filt->file_list) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
+ filt->filter_num = ldev->next_filter_num++;
+ /* Add deny filters to the beginning of the list */
+ if (flags & LOGFF_DENY)
+ list_add(&filt->sibling_node, &ldev->filter_head);
+ else
+ list_add_tail(&filt->sibling_node, &ldev->filter_head);
+
+ return filt->filter_num;
+
+err:
+ free(filt);
+ return ret;
+}
+
+int log_remove_filter(const char *drv_name, int filter_num)
+{
+ struct log_filter *filt;
+ struct log_device *ldev;
+
+ ldev = log_device_find_by_name(drv_name);
+ if (!ldev)
+ return -ENOENT;
+
+ list_for_each_entry(filt, &ldev->filter_head, sibling_node) {
+ if (filt->filter_num == filter_num) {
+ list_del(&filt->sibling_node);
+ free(filt);
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * log_find_device_by_drv() - Find a device by its driver
+ *
+ * @drv: Log driver
+ * @return Device associated with that driver, or NULL if not found
+ */
+static struct log_device *log_find_device_by_drv(struct log_driver *drv)
+{
+ struct log_device *ldev;
+
+ list_for_each_entry(ldev, &gd->log_head, sibling_node) {
+ if (ldev->drv == drv)
+ return ldev;
+ }
+ /*
+ * It is quite hard to pass an invalid driver since passing an unknown
+ * LOG_GET_DRIVER(xxx) would normally produce a compilation error. But
+ * it is possible to pass NULL, for example, so this
+ */
+
+ return NULL;
+}
+
+int log_device_set_enable(struct log_driver *drv, bool enable)
+{
+ struct log_device *ldev;
+
+ ldev = log_find_device_by_drv(drv);
+ if (!ldev)
+ return -ENOENT;
+ if (enable)
+ ldev->flags |= LOGDF_ENABLE;
+ else
+ ldev->flags &= ~LOGDF_ENABLE;
+
+ return 0;
+}
+
+int log_init(void)
+{
+ struct log_driver *drv = ll_entry_start(struct log_driver, log_driver);
+ const int count = ll_entry_count(struct log_driver, log_driver);
+ struct log_driver *end = drv + count;
+
+ /*
+ * We cannot add runtime data to the driver since it is likely stored
+ * in rodata. Instead, set up a 'device' corresponding to each driver.
+ * We only support having a single device.
+ */
+ INIT_LIST_HEAD((struct list_head *)&gd->log_head);
+ while (drv < end) {
+ struct log_device *ldev;
+
+ ldev = calloc(1, sizeof(*ldev));
+ if (!ldev) {
+ debug("%s: Cannot allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&ldev->filter_head);
+ ldev->drv = drv;
+ ldev->flags = drv->flags;
+ list_add_tail(&ldev->sibling_node,
+ (struct list_head *)&gd->log_head);
+ drv++;
+ }
+ gd->flags |= GD_FLG_LOG_READY;
+ if (!gd->default_log_level)
+ gd->default_log_level = CONFIG_LOG_DEFAULT_LEVEL;
+ gd->log_fmt = log_get_default_format();
+ gd->logc_prev = LOGC_NONE;
+ gd->logl_prev = LOGL_INFO;
+
+ return 0;
+}
diff --git a/roms/u-boot/common/log_console.c b/roms/u-boot/common/log_console.c
new file mode 100644
index 000000000..3f6177499
--- /dev/null
+++ b/roms/u-boot/common/log_console.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Logging support
+ *
+ * Copyright (c) 2017 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int log_console_emit(struct log_device *ldev, struct log_rec *rec)
+{
+ int fmt = gd->log_fmt;
+ bool add_space = false;
+
+ /*
+ * The output format is designed to give someone a fighting chance of
+ * figuring out which field is which:
+ * - level is in CAPS
+ * - cat is lower case and ends with comma
+ * - file normally has a .c extension and ends with a colon
+ * - line is integer and ends with a -
+ * - function is an identifier and ends with ()
+ * - message has a space before it unless it is on its own
+ */
+ if (!(rec->flags & LOGRECF_CONT) && fmt != BIT(LOGF_MSG)) {
+ add_space = true;
+ if (fmt & BIT(LOGF_LEVEL))
+ printf("%s.", log_get_level_name(rec->level));
+ if (fmt & BIT(LOGF_CAT))
+ printf("%s,", log_get_cat_name(rec->cat));
+ if (fmt & BIT(LOGF_FILE))
+ printf("%s:", rec->file);
+ if (fmt & BIT(LOGF_LINE))
+ printf("%d-", rec->line);
+ if (fmt & BIT(LOGF_FUNC))
+ printf("%s()", rec->func);
+ }
+ if (fmt & BIT(LOGF_MSG))
+ printf("%s%s", add_space ? " " : "", rec->msg);
+
+ return 0;
+}
+
+LOG_DRIVER(console) = {
+ .name = "console",
+ .emit = log_console_emit,
+ .flags = LOGDF_ENABLE,
+};
diff --git a/roms/u-boot/common/log_syslog.c b/roms/u-boot/common/log_syslog.c
new file mode 100644
index 000000000..53c4def5d
--- /dev/null
+++ b/roms/u-boot/common/log_syslog.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Log to syslog.
+ *
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <net.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define BUFFER_SIZE 480
+
+static void append(char **buf, char *buf_end, const char *fmt, ...)
+{
+ va_list args;
+ size_t size = buf_end - *buf;
+
+ va_start(args, fmt);
+ vsnprintf(*buf, size, fmt, args);
+ va_end(args);
+ *buf += strlen(*buf);
+}
+
+static int log_syslog_emit(struct log_device *ldev, struct log_rec *rec)
+{
+ int ret;
+ int fmt = gd->log_fmt;
+ char msg[BUFFER_SIZE];
+ char *msg_end = msg + BUFFER_SIZE;
+ char *ptr = msg;
+ char *iphdr;
+ char *log_msg;
+ int eth_hdr_size;
+ struct in_addr bcast_ip;
+ unsigned int log_level;
+ char *log_hostname;
+
+ /* Setup packet buffers */
+ ret = net_init();
+ if (ret)
+ return ret;
+ /* Disable hardware and put it into the reset state */
+ eth_halt();
+ /* Set current device according to environment variables */
+ eth_set_current();
+ /* Get hardware ready for send and receive operations */
+ ret = eth_init();
+ if (ret < 0) {
+ eth_halt();
+ goto out;
+ }
+
+ memset(msg, 0, BUFFER_SIZE);
+
+ /* Set ethernet header */
+ eth_hdr_size = net_set_ether((uchar *)ptr, net_bcast_ethaddr, PROT_IP);
+ ptr += eth_hdr_size;
+ iphdr = ptr;
+ ptr += IP_UDP_HDR_SIZE;
+ log_msg = ptr;
+
+ /*
+ * The syslog log levels defined in RFC 5424 match the U-Boot ones up to
+ * level 7 (debug).
+ */
+ log_level = rec->level;
+ if (log_level > 7)
+ log_level = 7;
+ /* Leave high bits as 0 to write a 'kernel message' */
+
+ /* Write log message to buffer */
+ append(&ptr, msg_end, "<%u>", log_level);
+ log_hostname = env_get("log_hostname");
+ if (log_hostname)
+ append(&ptr, msg_end, "%s ", log_hostname);
+ append(&ptr, msg_end, "uboot: ");
+ if (fmt & BIT(LOGF_LEVEL))
+ append(&ptr, msg_end, "%s.",
+ log_get_level_name(rec->level));
+ if (fmt & BIT(LOGF_CAT))
+ append(&ptr, msg_end, "%s,",
+ log_get_cat_name(rec->cat));
+ if (fmt & BIT(LOGF_FILE))
+ append(&ptr, msg_end, "%s:", rec->file);
+ if (fmt & BIT(LOGF_LINE))
+ append(&ptr, msg_end, "%d-", rec->line);
+ if (fmt & BIT(LOGF_FUNC))
+ append(&ptr, msg_end, "%s()", rec->func);
+ if (fmt & BIT(LOGF_MSG))
+ append(&ptr, msg_end, "%s%s",
+ fmt != BIT(LOGF_MSG) ? " " : "", rec->msg);
+ /* Consider trailing 0x00 */
+ ptr++;
+
+ debug("log message: '%s'\n", log_msg);
+
+ /* Broadcast message */
+ bcast_ip.s_addr = 0xFFFFFFFFL;
+ net_set_udp_header((uchar *)iphdr, bcast_ip, 514, 514, ptr - log_msg);
+ net_send_packet((uchar *)msg, ptr - msg);
+
+out:
+ return ret;
+}
+
+LOG_DRIVER(syslog) = {
+ .name = "syslog",
+ .emit = log_syslog_emit,
+};
diff --git a/roms/u-boot/common/lynxkdi.c b/roms/u-boot/common/lynxkdi.c
new file mode 100644
index 000000000..1c8e122c3
--- /dev/null
+++ b/roms/u-boot/common/lynxkdi.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) Orbacom Systems, Inc <www.orbacom.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <image.h>
+#include <net.h>
+
+#include <lynxkdi.h>
+
+#error "Lynx KDI support not implemented for configured CPU"
diff --git a/roms/u-boot/common/main.c b/roms/u-boot/common/main.c
new file mode 100644
index 000000000..ae5bcdb32
--- /dev/null
+++ b/roms/u-boot/common/main.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <autoboot.h>
+#include <bootstage.h>
+#include <cli.h>
+#include <command.h>
+#include <console.h>
+#include <env.h>
+#include <init.h>
+#include <net.h>
+#include <version.h>
+#include <efi_loader.h>
+
+static void run_preboot_environment_command(void)
+{
+ char *p;
+
+ p = env_get("preboot");
+ if (p != NULL) {
+ int prev = 0;
+
+ if (IS_ENABLED(CONFIG_AUTOBOOT_KEYED))
+ prev = disable_ctrlc(1); /* disable Ctrl-C checking */
+
+ run_command_list(p, -1, 0);
+
+ if (IS_ENABLED(CONFIG_AUTOBOOT_KEYED))
+ disable_ctrlc(prev); /* restore Ctrl-C checking */
+ }
+}
+
+/* We come here after U-Boot is initialised and ready to process commands */
+void main_loop(void)
+{
+ const char *s;
+
+ bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
+
+ if (IS_ENABLED(CONFIG_VERSION_VARIABLE))
+ env_set("ver", version_string); /* set version variable */
+
+ cli_init();
+
+ if (IS_ENABLED(CONFIG_USE_PREBOOT))
+ run_preboot_environment_command();
+
+ if (IS_ENABLED(CONFIG_UPDATE_TFTP))
+ update_tftp(0UL, NULL, NULL);
+
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
+ efi_launch_capsules();
+
+ s = bootdelay_process();
+ if (cli_process_fdt(&s))
+ cli_secure_boot_cmd(s);
+
+ autoboot_command(s);
+
+ cli_loop();
+ panic("No CLI available");
+}
diff --git a/roms/u-boot/common/malloc_simple.c b/roms/u-boot/common/malloc_simple.c
new file mode 100644
index 000000000..0267fb6be
--- /dev/null
+++ b/roms/u-boot/common/malloc_simple.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Simple malloc implementation
+ *
+ * Copyright (c) 2014 Google, Inc
+ */
+
+#define LOG_CATEGORY LOGC_ALLOC
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void *alloc_simple(size_t bytes, int align)
+{
+ ulong addr, new_ptr;
+ void *ptr;
+
+ addr = ALIGN(gd->malloc_base + gd->malloc_ptr, align);
+ new_ptr = addr + bytes - gd->malloc_base;
+ log_debug("size=%zx, ptr=%lx, limit=%lx: ", bytes, new_ptr,
+ gd->malloc_limit);
+ if (new_ptr > gd->malloc_limit) {
+ log_err("alloc space exhausted\n");
+ return NULL;
+ }
+
+ ptr = map_sysmem(addr, bytes);
+ gd->malloc_ptr = ALIGN(new_ptr, sizeof(new_ptr));
+
+ return ptr;
+}
+
+void *malloc_simple(size_t bytes)
+{
+ void *ptr;
+
+ ptr = alloc_simple(bytes, 1);
+ if (!ptr)
+ return ptr;
+
+ log_debug("%lx\n", (ulong)ptr);
+
+ return ptr;
+}
+
+void *memalign_simple(size_t align, size_t bytes)
+{
+ void *ptr;
+
+ ptr = alloc_simple(bytes, align);
+ if (!ptr)
+ return ptr;
+ log_debug("aligned to %lx\n", (ulong)ptr);
+
+ return ptr;
+}
+
+#if CONFIG_IS_ENABLED(SYS_MALLOC_SIMPLE)
+void *calloc(size_t nmemb, size_t elem_size)
+{
+ size_t size = nmemb * elem_size;
+ void *ptr;
+
+ ptr = malloc(size);
+ if (!ptr)
+ return ptr;
+ memset(ptr, '\0', size);
+
+ return ptr;
+}
+#endif
+
+void malloc_simple_info(void)
+{
+ log_info("malloc_simple: %lx bytes used, %lx remain\n", gd->malloc_ptr,
+ CONFIG_VAL(SYS_MALLOC_F_LEN) - gd->malloc_ptr);
+}
diff --git a/roms/u-boot/common/memsize.c b/roms/u-boot/common/memsize.c
new file mode 100644
index 000000000..d5d13d51b
--- /dev/null
+++ b/roms/u-boot/common/memsize.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef __PPC__
+/*
+ * At least on G2 PowerPC cores, sequential accesses to non-existent
+ * memory must be synchronized.
+ */
+# include <asm/io.h> /* for sync() */
+#else
+# define sync() /* nothing */
+#endif
+
+/*
+ * Check memory range for valid RAM. A simple memory test determines
+ * the actually available RAM size between addresses `base' and
+ * `base + maxsize'.
+ */
+long get_ram_size(long *base, long maxsize)
+{
+ volatile long *addr;
+ long save[BITS_PER_LONG - 1];
+ long save_base;
+ long cnt;
+ long val;
+ long size;
+ int i = 0;
+
+ for (cnt = (maxsize / sizeof(long)) >> 1; cnt > 0; cnt >>= 1) {
+ addr = base + cnt; /* pointer arith! */
+ sync();
+ save[i++] = *addr;
+ sync();
+ *addr = ~cnt;
+ }
+
+ addr = base;
+ sync();
+ save_base = *addr;
+ sync();
+ *addr = 0;
+
+ sync();
+ if ((val = *addr) != 0) {
+ /* Restore the original data before leaving the function. */
+ sync();
+ *base = save_base;
+ for (cnt = 1; cnt < maxsize / sizeof(long); cnt <<= 1) {
+ addr = base + cnt;
+ sync();
+ *addr = save[--i];
+ }
+ return (0);
+ }
+
+ for (cnt = 1; cnt < maxsize / sizeof(long); cnt <<= 1) {
+ addr = base + cnt; /* pointer arith! */
+ val = *addr;
+ *addr = save[--i];
+ if (val != ~cnt) {
+ size = cnt * sizeof(long);
+ /*
+ * Restore the original data
+ * before leaving the function.
+ */
+ for (cnt <<= 1;
+ cnt < maxsize / sizeof(long);
+ cnt <<= 1) {
+ addr = base + cnt;
+ *addr = save[--i];
+ }
+ /* warning: don't restore save_base in this case,
+ * it is already done in the loop because
+ * base and base+size share the same physical memory
+ * and *base is saved after *(base+size) modification
+ * in first loop
+ */
+ return (size);
+ }
+ }
+ *base = save_base;
+
+ return (maxsize);
+}
+
+phys_size_t __weak get_effective_memsize(void)
+{
+#ifndef CONFIG_VERY_BIG_RAM
+ return gd->ram_size;
+#else
+ /* limit stack to what we can reasonable map */
+ return ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ?
+ CONFIG_MAX_MEM_MAPPED : gd->ram_size);
+#endif
+}
diff --git a/roms/u-boot/common/menu.c b/roms/u-boot/common/menu.c
new file mode 100644
index 000000000..5fb2ffbd0
--- /dev/null
+++ b/roms/u-boot/common/menu.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+ */
+
+#include <common.h>
+#include <cli.h>
+#include <malloc.h>
+#include <errno.h>
+#include <linux/list.h>
+
+#include "menu.h"
+
+/*
+ * Internally, each item in a menu is represented by a struct menu_item.
+ *
+ * These items will be alloc'd and initialized by menu_item_add and destroyed
+ * by menu_item_destroy, and the consumer of the interface never sees that
+ * this struct is used at all.
+ */
+struct menu_item {
+ char *key;
+ void *data;
+ struct list_head list;
+};
+
+/*
+ * The menu is composed of a list of items along with settings and callbacks
+ * provided by the user. An incomplete definition of this struct is available
+ * in menu.h, but the full definition is here to prevent consumers from
+ * relying on its contents.
+ */
+struct menu {
+ struct menu_item *default_item;
+ int timeout;
+ char *title;
+ int prompt;
+ void (*display_statusline)(struct menu *);
+ void (*item_data_print)(void *);
+ char *(*item_choice)(void *);
+ void *item_choice_data;
+ struct list_head items;
+ int item_cnt;
+};
+
+/*
+ * An iterator function for menu items. callback will be called for each item
+ * in m, with m, a pointer to the item, and extra being passed to callback. If
+ * callback returns a value other than NULL, iteration stops and the value
+ * return by callback is returned from menu_items_iter. This allows it to be
+ * used for search type operations. It is also safe for callback to remove the
+ * item from the list of items.
+ */
+static inline void *menu_items_iter(struct menu *m,
+ void *(*callback)(struct menu *, struct menu_item *, void *),
+ void *extra)
+{
+ struct list_head *pos, *n;
+ struct menu_item *item;
+ void *ret;
+
+ list_for_each_safe(pos, n, &m->items) {
+ item = list_entry(pos, struct menu_item, list);
+
+ ret = callback(m, item, extra);
+
+ if (ret)
+ return ret;
+ }
+
+ return NULL;
+}
+
+/*
+ * Print a menu_item. If the consumer provided an item_data_print function
+ * when creating the menu, call it with a pointer to the item's private data.
+ * Otherwise, print the key of the item.
+ */
+static inline void *menu_item_print(struct menu *m,
+ struct menu_item *item,
+ void *extra)
+{
+ if (!m->item_data_print) {
+ puts(item->key);
+ putc('\n');
+ } else {
+ m->item_data_print(item->data);
+ }
+
+ return NULL;
+}
+
+/*
+ * Free the memory used by a menu item. This includes the memory used by its
+ * key.
+ */
+static inline void *menu_item_destroy(struct menu *m,
+ struct menu_item *item,
+ void *extra)
+{
+ if (item->key)
+ free(item->key);
+
+ free(item);
+
+ return NULL;
+}
+
+/*
+ * Display a menu so the user can make a choice of an item. First display its
+ * title, if any, and then each item in the menu.
+ */
+static inline void menu_display(struct menu *m)
+{
+ if (m->title) {
+ puts(m->title);
+ putc('\n');
+ }
+ if (m->display_statusline)
+ m->display_statusline(m);
+
+ menu_items_iter(m, menu_item_print, NULL);
+}
+
+/*
+ * Check if an item's key matches a provided string, pointed to by extra. If
+ * extra is NULL, an item with a NULL key will match. Otherwise, the item's
+ * key has to match according to strcmp.
+ *
+ * This is called via menu_items_iter, so it returns a pointer to the item if
+ * the key matches, and returns NULL otherwise.
+ */
+static inline void *menu_item_key_match(struct menu *m,
+ struct menu_item *item, void *extra)
+{
+ char *item_key = extra;
+
+ if (!item_key || !item->key) {
+ if (item_key == item->key)
+ return item;
+
+ return NULL;
+ }
+
+ if (strcmp(item->key, item_key) == 0)
+ return item;
+
+ return NULL;
+}
+
+/*
+ * Find the first item with a key matching item_key, if any exists.
+ */
+static inline struct menu_item *menu_item_by_key(struct menu *m,
+ char *item_key)
+{
+ return menu_items_iter(m, menu_item_key_match, item_key);
+}
+
+/*
+ * Set *choice to point to the default item's data, if any default item was
+ * set, and returns 1. If no default item was set, returns -ENOENT.
+ */
+int menu_default_choice(struct menu *m, void **choice)
+{
+ if (m->default_item) {
+ *choice = m->default_item->data;
+ return 1;
+ }
+
+ return -ENOENT;
+}
+
+/*
+ * Displays the menu and asks the user to choose an item. *choice will point
+ * to the private data of the item the user chooses. The user makes a choice
+ * by inputting a string matching the key of an item. Invalid choices will
+ * cause the user to be prompted again, repeatedly, until the user makes a
+ * valid choice. The user can exit the menu without making a choice via ^c.
+ *
+ * Returns 1 if the user made a choice, or -EINTR if they bail via ^c.
+ */
+static inline int menu_interactive_choice(struct menu *m, void **choice)
+{
+ char cbuf[CONFIG_SYS_CBSIZE];
+ struct menu_item *choice_item = NULL;
+ int readret;
+
+ while (!choice_item) {
+ cbuf[0] = '\0';
+
+ menu_display(m);
+
+ if (!m->item_choice) {
+ readret = cli_readline_into_buffer("Enter choice: ",
+ cbuf, m->timeout);
+
+ if (readret >= 0) {
+ choice_item = menu_item_by_key(m, cbuf);
+ if (!choice_item)
+ printf("%s not found\n", cbuf);
+ } else if (readret == -1) {
+ printf("<INTERRUPT>\n");
+ return -EINTR;
+ } else {
+ return menu_default_choice(m, choice);
+ }
+ } else {
+ char *key = m->item_choice(m->item_choice_data);
+
+ if (key)
+ choice_item = menu_item_by_key(m, key);
+ }
+
+ if (!choice_item)
+ m->timeout = 0;
+ }
+
+ *choice = choice_item->data;
+
+ return 1;
+}
+
+/*
+ * menu_default_set() - Sets the default choice for the menu. This is safe to
+ * call more than once on a menu.
+ *
+ * m - Points to a menu created by menu_create().
+ *
+ * item_key - Points to a string that, when compared using strcmp, matches the
+ * key for an existing item in the menu.
+ *
+ * Returns 1 if successful, -EINVAL if m is NULL, or -ENOENT if no item with a
+ * key matching item_key is found.
+ */
+int menu_default_set(struct menu *m, char *item_key)
+{
+ struct menu_item *item;
+
+ if (!m)
+ return -EINVAL;
+
+ item = menu_item_by_key(m, item_key);
+
+ if (!item)
+ return -ENOENT;
+
+ m->default_item = item;
+
+ return 1;
+}
+
+/*
+ * menu_get_choice() - Returns the user's selected menu entry, or the default
+ * if the menu is set to not prompt or the timeout expires. This is safe to
+ * call more than once.
+ *
+ * m - Points to a menu created by menu_create().
+ *
+ * choice - Points to a location that will store a pointer to the selected
+ * menu item. If no item is selected or there is an error, no value will be
+ * written at the location it points to.
+ *
+ * Returns 1 if successful, -EINVAL if m or choice is NULL, -ENOENT if no
+ * default has been set and the menu is set to not prompt or the timeout
+ * expires, or -EINTR if the user exits the menu via ^c.
+ */
+int menu_get_choice(struct menu *m, void **choice)
+{
+ if (!m || !choice)
+ return -EINVAL;
+
+ if (!m->prompt || m->item_cnt == 1)
+ return menu_default_choice(m, choice);
+
+ return menu_interactive_choice(m, choice);
+}
+
+/*
+ * menu_item_add() - Adds or replaces a menu item. Note that this replaces the
+ * data of an item if it already exists, but doesn't change the order of the
+ * item.
+ *
+ * m - Points to a menu created by menu_create().
+ *
+ * item_key - Points to a string that will uniquely identify the item. The
+ * string will be copied to internal storage, and is safe to discard after
+ * passing to menu_item_add.
+ *
+ * item_data - An opaque pointer associated with an item. It is never
+ * dereferenced internally, but will be passed to the item_data_print, and
+ * will be returned from menu_get_choice if the menu item is selected.
+ *
+ * Returns 1 if successful, -EINVAL if m is NULL, or -ENOMEM if there is
+ * insufficient memory to add the menu item.
+ */
+int menu_item_add(struct menu *m, char *item_key, void *item_data)
+{
+ struct menu_item *item;
+
+ if (!m)
+ return -EINVAL;
+
+ item = menu_item_by_key(m, item_key);
+
+ if (item) {
+ item->data = item_data;
+ return 1;
+ }
+
+ item = malloc(sizeof *item);
+ if (!item)
+ return -ENOMEM;
+
+ item->key = strdup(item_key);
+
+ if (!item->key) {
+ free(item);
+ return -ENOMEM;
+ }
+
+ item->data = item_data;
+
+ list_add_tail(&item->list, &m->items);
+ m->item_cnt++;
+
+ return 1;
+}
+
+/*
+ * menu_create() - Creates a menu handle with default settings
+ *
+ * title - If not NULL, points to a string that will be displayed before the
+ * list of menu items. It will be copied to internal storage, and is safe to
+ * discard after passing to menu_create().
+ *
+ * timeout - A delay in seconds to wait for user input. If 0, timeout is
+ * disabled, and the default choice will be returned unless prompt is 1.
+ *
+ * prompt - If 0, don't ask for user input unless there is an interrupted
+ * timeout. If 1, the user will be prompted for input regardless of the value
+ * of timeout.
+ *
+ * display_statusline - If not NULL, will be called to show a statusline when
+ * the menu is displayed.
+ *
+ * item_data_print - If not NULL, will be called for each item when the menu
+ * is displayed, with the pointer to the item's data passed as the argument.
+ * If NULL, each item's key will be printed instead. Since an item's key is
+ * what must be entered to select an item, the item_data_print function should
+ * make it obvious what the key for each entry is.
+ *
+ * item_choice - If not NULL, will be called when asking the user to choose an
+ * item. Returns a key string corresponding to the chosen item or NULL if
+ * no item has been selected.
+ *
+ * item_choice_data - Will be passed as the argument to the item_choice function
+ *
+ * Returns a pointer to the menu if successful, or NULL if there is
+ * insufficient memory available to create the menu.
+ */
+struct menu *menu_create(char *title, int timeout, int prompt,
+ void (*display_statusline)(struct menu *),
+ void (*item_data_print)(void *),
+ char *(*item_choice)(void *),
+ void *item_choice_data)
+{
+ struct menu *m;
+
+ m = malloc(sizeof *m);
+
+ if (!m)
+ return NULL;
+
+ m->default_item = NULL;
+ m->prompt = prompt;
+ m->timeout = timeout;
+ m->display_statusline = display_statusline;
+ m->item_data_print = item_data_print;
+ m->item_choice = item_choice;
+ m->item_choice_data = item_choice_data;
+ m->item_cnt = 0;
+
+ if (title) {
+ m->title = strdup(title);
+ if (!m->title) {
+ free(m);
+ return NULL;
+ }
+ } else
+ m->title = NULL;
+
+
+ INIT_LIST_HEAD(&m->items);
+
+ return m;
+}
+
+/*
+ * menu_destroy() - frees the memory used by a menu and its items.
+ *
+ * m - Points to a menu created by menu_create().
+ *
+ * Returns 1 if successful, or -EINVAL if m is NULL.
+ */
+int menu_destroy(struct menu *m)
+{
+ if (!m)
+ return -EINVAL;
+
+ menu_items_iter(m, menu_item_destroy, NULL);
+
+ if (m->title)
+ free(m->title);
+
+ free(m);
+
+ return 1;
+}
diff --git a/roms/u-boot/common/miiphyutil.c b/roms/u-boot/common/miiphyutil.c
new file mode 100644
index 000000000..7d4d15ed9
--- /dev/null
+++ b/roms/u-boot/common/miiphyutil.c
@@ -0,0 +1,561 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
+ */
+
+/*
+ * This provides a bit-banged interface to the ethernet MII management
+ * channel.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <linux/delay.h>
+
+#include <asm/types.h>
+#include <linux/list.h>
+#include <malloc.h>
+#include <net.h>
+
+/* local debug macro */
+#undef MII_DEBUG
+
+#undef debug
+#ifdef MII_DEBUG
+#define debug(fmt, args...) printf(fmt, ##args)
+#else
+#define debug(fmt, args...)
+#endif /* MII_DEBUG */
+
+static struct list_head mii_devs;
+static struct mii_dev *current_mii;
+
+/*
+ * Lookup the mii_dev struct by the registered device name.
+ */
+struct mii_dev *miiphy_get_dev_by_name(const char *devname)
+{
+ struct list_head *entry;
+ struct mii_dev *dev;
+
+ if (!devname) {
+ printf("NULL device name!\n");
+ return NULL;
+ }
+
+ list_for_each(entry, &mii_devs) {
+ dev = list_entry(entry, struct mii_dev, link);
+ if (strcmp(dev->name, devname) == 0)
+ return dev;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************
+ *
+ * Initialize global data. Need to be called before any other miiphy routine.
+ */
+void miiphy_init(void)
+{
+ INIT_LIST_HEAD(&mii_devs);
+ current_mii = NULL;
+}
+
+struct mii_dev *mdio_alloc(void)
+{
+ struct mii_dev *bus;
+
+ bus = malloc(sizeof(*bus));
+ if (!bus)
+ return bus;
+
+ memset(bus, 0, sizeof(*bus));
+
+ /* initalize mii_dev struct fields */
+ INIT_LIST_HEAD(&bus->link);
+
+ return bus;
+}
+
+void mdio_free(struct mii_dev *bus)
+{
+ free(bus);
+}
+
+int mdio_register(struct mii_dev *bus)
+{
+ if (!bus || !bus->read || !bus->write)
+ return -1;
+
+ /* check if we have unique name */
+ if (miiphy_get_dev_by_name(bus->name)) {
+ printf("mdio_register: non unique device name '%s'\n",
+ bus->name);
+ return -1;
+ }
+
+ /* add it to the list */
+ list_add_tail(&bus->link, &mii_devs);
+
+ if (!current_mii)
+ current_mii = bus;
+
+ return 0;
+}
+
+int mdio_register_seq(struct mii_dev *bus, int seq)
+{
+ int ret;
+
+ /* Setup a unique name for each mdio bus */
+ ret = snprintf(bus->name, MDIO_NAME_LEN, "eth%d", seq);
+ if (ret < 0)
+ return ret;
+
+ return mdio_register(bus);
+}
+
+int mdio_unregister(struct mii_dev *bus)
+{
+ if (!bus)
+ return 0;
+
+ /* delete it from the list */
+ list_del(&bus->link);
+
+ if (current_mii == bus)
+ current_mii = NULL;
+
+ return 0;
+}
+
+void mdio_list_devices(void)
+{
+ struct list_head *entry;
+
+ list_for_each(entry, &mii_devs) {
+ int i;
+ struct mii_dev *bus = list_entry(entry, struct mii_dev, link);
+
+ printf("%s:\n", bus->name);
+
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ struct phy_device *phydev = bus->phymap[i];
+
+ if (phydev) {
+ printf("%x - %s", i, phydev->drv->name);
+
+ if (phydev->dev)
+ printf(" <--> %s\n", phydev->dev->name);
+ else
+ printf("\n");
+ }
+ }
+ }
+}
+
+int miiphy_set_current_dev(const char *devname)
+{
+ struct mii_dev *dev;
+
+ dev = miiphy_get_dev_by_name(devname);
+ if (dev) {
+ current_mii = dev;
+ return 0;
+ }
+
+ printf("No such device: %s\n", devname);
+
+ return 1;
+}
+
+struct mii_dev *mdio_get_current_dev(void)
+{
+ return current_mii;
+}
+
+struct list_head *mdio_get_list_head(void)
+{
+ return &mii_devs;
+}
+
+struct phy_device *mdio_phydev_for_ethname(const char *ethname)
+{
+ struct list_head *entry;
+ struct mii_dev *bus;
+
+ list_for_each(entry, &mii_devs) {
+ int i;
+ bus = list_entry(entry, struct mii_dev, link);
+
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ if (!bus->phymap[i] || !bus->phymap[i]->dev)
+ continue;
+
+ if (strcmp(bus->phymap[i]->dev->name, ethname) == 0)
+ return bus->phymap[i];
+ }
+ }
+
+ printf("%s is not a known ethernet\n", ethname);
+ return NULL;
+}
+
+const char *miiphy_get_current_dev(void)
+{
+ if (current_mii)
+ return current_mii->name;
+
+ return NULL;
+}
+
+static struct mii_dev *miiphy_get_active_dev(const char *devname)
+{
+ /* If the current mii is the one we want, return it */
+ if (current_mii)
+ if (strcmp(current_mii->name, devname) == 0)
+ return current_mii;
+
+ /* Otherwise, set the active one to the one we want */
+ if (miiphy_set_current_dev(devname))
+ return NULL;
+ else
+ return current_mii;
+}
+
+/*****************************************************************************
+ *
+ * Read to variable <value> from the PHY attached to device <devname>,
+ * use PHY address <addr> and register <reg>.
+ *
+ * This API is deprecated. Use phy_read on a phy_device found via phy_connect
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
+ unsigned short *value)
+{
+ struct mii_dev *bus;
+ int ret;
+
+ bus = miiphy_get_active_dev(devname);
+ if (!bus)
+ return 1;
+
+ ret = bus->read(bus, addr, MDIO_DEVAD_NONE, reg);
+ if (ret < 0)
+ return 1;
+
+ *value = (unsigned short)ret;
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * Write <value> to the PHY attached to device <devname>,
+ * use PHY address <addr> and register <reg>.
+ *
+ * This API is deprecated. Use phy_write on a phy_device found by phy_connect
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
+ unsigned short value)
+{
+ struct mii_dev *bus;
+
+ bus = miiphy_get_active_dev(devname);
+ if (bus)
+ return bus->write(bus, addr, MDIO_DEVAD_NONE, reg, value);
+
+ return 1;
+}
+
+/*****************************************************************************
+ *
+ * Print out list of registered MII capable devices.
+ */
+void miiphy_listdev(void)
+{
+ struct list_head *entry;
+ struct mii_dev *dev;
+
+ puts("MII devices: ");
+ list_for_each(entry, &mii_devs) {
+ dev = list_entry(entry, struct mii_dev, link);
+ printf("'%s' ", dev->name);
+ }
+ puts("\n");
+
+ if (current_mii)
+ printf("Current device: '%s'\n", current_mii->name);
+}
+
+/*****************************************************************************
+ *
+ * Read the OUI, manufacture's model number, and revision number.
+ *
+ * OUI: 22 bits (unsigned int)
+ * Model: 6 bits (unsigned char)
+ * Revision: 4 bits (unsigned char)
+ *
+ * This API is deprecated.
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui,
+ unsigned char *model, unsigned char *rev)
+{
+ unsigned int reg = 0;
+ unsigned short tmp;
+
+ if (miiphy_read(devname, addr, MII_PHYSID2, &tmp) != 0) {
+ debug("PHY ID register 2 read failed\n");
+ return -1;
+ }
+ reg = tmp;
+
+ debug("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg);
+
+ if (reg == 0xFFFF) {
+ /* No physical device present at this address */
+ return -1;
+ }
+
+ if (miiphy_read(devname, addr, MII_PHYSID1, &tmp) != 0) {
+ debug("PHY ID register 1 read failed\n");
+ return -1;
+ }
+ reg |= tmp << 16;
+ debug("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
+
+ *oui = (reg >> 10);
+ *model = (unsigned char)((reg >> 4) & 0x0000003F);
+ *rev = (unsigned char)(reg & 0x0000000F);
+ return 0;
+}
+
+#ifndef CONFIG_PHYLIB
+/*****************************************************************************
+ *
+ * Reset the PHY.
+ *
+ * This API is deprecated. Use PHYLIB.
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_reset(const char *devname, unsigned char addr)
+{
+ unsigned short reg;
+ int timeout = 500;
+
+ if (miiphy_read(devname, addr, MII_BMCR, &reg) != 0) {
+ debug("PHY status read failed\n");
+ return -1;
+ }
+ if (miiphy_write(devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) {
+ debug("PHY reset failed\n");
+ return -1;
+ }
+#ifdef CONFIG_PHY_RESET_DELAY
+ udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */
+#endif
+ /*
+ * Poll the control register for the reset bit to go to 0 (it is
+ * auto-clearing). This should happen within 0.5 seconds per the
+ * IEEE spec.
+ */
+ reg = 0x8000;
+ while (((reg & 0x8000) != 0) && timeout--) {
+ if (miiphy_read(devname, addr, MII_BMCR, &reg) != 0) {
+ debug("PHY status read failed\n");
+ return -1;
+ }
+ udelay(1000);
+ }
+ if ((reg & 0x8000) == 0) {
+ return 0;
+ } else {
+ puts("PHY reset timed out\n");
+ return -1;
+ }
+ return 0;
+}
+#endif /* !PHYLIB */
+
+/*****************************************************************************
+ *
+ * Determine the ethernet speed (10/100/1000). Return 10 on error.
+ */
+int miiphy_speed(const char *devname, unsigned char addr)
+{
+ u16 bmcr, anlpar, adv;
+
+#if defined(CONFIG_PHY_GIGE)
+ u16 btsr;
+
+ /*
+ * Check for 1000BASE-X. If it is supported, then assume that the speed
+ * is 1000.
+ */
+ if (miiphy_is_1000base_x(devname, addr))
+ return _1000BASET;
+
+ /*
+ * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
+ */
+ /* Check for 1000BASE-T. */
+ if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) {
+ printf("PHY 1000BT status");
+ goto miiphy_read_failed;
+ }
+ if (btsr != 0xFFFF &&
+ (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)))
+ return _1000BASET;
+#endif /* CONFIG_PHY_GIGE */
+
+ /* Check Basic Management Control Register first. */
+ if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) {
+ printf("PHY speed");
+ goto miiphy_read_failed;
+ }
+ /* Check if auto-negotiation is on. */
+ if (bmcr & BMCR_ANENABLE) {
+ /* Get auto-negotiation results. */
+ if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
+ printf("PHY AN speed");
+ goto miiphy_read_failed;
+ }
+
+ if (miiphy_read(devname, addr, MII_ADVERTISE, &adv)) {
+ puts("PHY AN adv speed");
+ goto miiphy_read_failed;
+ }
+ return ((anlpar & adv) & LPA_100) ? _100BASET : _10BASET;
+ }
+ /* Get speed from basic control settings. */
+ return (bmcr & BMCR_SPEED100) ? _100BASET : _10BASET;
+
+miiphy_read_failed:
+ printf(" read failed, assuming 10BASE-T\n");
+ return _10BASET;
+}
+
+/*****************************************************************************
+ *
+ * Determine full/half duplex. Return half on error.
+ */
+int miiphy_duplex(const char *devname, unsigned char addr)
+{
+ u16 bmcr, anlpar, adv;
+
+#if defined(CONFIG_PHY_GIGE)
+ u16 btsr;
+
+ /* Check for 1000BASE-X. */
+ if (miiphy_is_1000base_x(devname, addr)) {
+ /* 1000BASE-X */
+ if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
+ printf("1000BASE-X PHY AN duplex");
+ goto miiphy_read_failed;
+ }
+ }
+ /*
+ * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
+ */
+ /* Check for 1000BASE-T. */
+ if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) {
+ printf("PHY 1000BT status");
+ goto miiphy_read_failed;
+ }
+ if (btsr != 0xFFFF) {
+ if (btsr & PHY_1000BTSR_1000FD) {
+ return FULL;
+ } else if (btsr & PHY_1000BTSR_1000HD) {
+ return HALF;
+ }
+ }
+#endif /* CONFIG_PHY_GIGE */
+
+ /* Check Basic Management Control Register first. */
+ if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) {
+ puts("PHY duplex");
+ goto miiphy_read_failed;
+ }
+ /* Check if auto-negotiation is on. */
+ if (bmcr & BMCR_ANENABLE) {
+ /* Get auto-negotiation results. */
+ if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
+ puts("PHY AN duplex");
+ goto miiphy_read_failed;
+ }
+
+ if (miiphy_read(devname, addr, MII_ADVERTISE, &adv)) {
+ puts("PHY AN adv duplex");
+ goto miiphy_read_failed;
+ }
+ return ((anlpar & adv) & (LPA_10FULL | LPA_100FULL)) ?
+ FULL : HALF;
+ }
+ /* Get speed from basic control settings. */
+ return (bmcr & BMCR_FULLDPLX) ? FULL : HALF;
+
+miiphy_read_failed:
+ printf(" read failed, assuming half duplex\n");
+ return HALF;
+}
+
+/*****************************************************************************
+ *
+ * Return 1 if PHY supports 1000BASE-X, 0 if PHY supports 10BASE-T/100BASE-TX/
+ * 1000BASE-T, or on error.
+ */
+int miiphy_is_1000base_x(const char *devname, unsigned char addr)
+{
+#if defined(CONFIG_PHY_GIGE)
+ u16 exsr;
+
+ if (miiphy_read(devname, addr, MII_ESTATUS, &exsr)) {
+ printf("PHY extended status read failed, assuming no "
+ "1000BASE-X\n");
+ return 0;
+ }
+ return 0 != (exsr & (ESTATUS_1000XF | ESTATUS_1000XH));
+#else
+ return 0;
+#endif
+}
+
+#ifdef CONFIG_SYS_FAULT_ECHO_LINK_DOWN
+/*****************************************************************************
+ *
+ * Determine link status
+ */
+int miiphy_link(const char *devname, unsigned char addr)
+{
+ unsigned short reg;
+
+ /* dummy read; needed to latch some phys */
+ (void)miiphy_read(devname, addr, MII_BMSR, &reg);
+ if (miiphy_read(devname, addr, MII_BMSR, &reg)) {
+ puts("MII_BMSR read failed, assuming no link\n");
+ return 0;
+ }
+
+ /* Determine if a link is active */
+ if ((reg & BMSR_LSTATUS) != 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+#endif
diff --git a/roms/u-boot/common/qfw.c b/roms/u-boot/common/qfw.c
new file mode 100644
index 000000000..90cbb8c5d
--- /dev/null
+++ b/roms/u-boot/common/qfw.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
+ */
+
+#include <dm.h>
+#include <dm/uclass.h>
+#include <qfw.h>
+#include <stdlib.h>
+
+int qfw_get_dev(struct udevice **devp)
+{
+ return uclass_first_device_err(UCLASS_QFW, devp);
+}
+
+int qfw_online_cpus(struct udevice *dev)
+{
+ u16 nb_cpus;
+
+ qfw_read_entry(dev, FW_CFG_NB_CPUS, 2, &nb_cpus);
+
+ return le16_to_cpu(nb_cpus);
+}
+
+int qfw_read_firmware_list(struct udevice *dev)
+{
+ int i;
+ u32 count;
+ struct fw_file *file;
+ struct list_head *entry;
+
+ struct qfw_dev *qdev = dev_get_uclass_priv(dev);
+
+ /* don't read it twice */
+ if (!list_empty(&qdev->fw_list))
+ return 0;
+
+ qfw_read_entry(dev, FW_CFG_FILE_DIR, 4, &count);
+ if (!count)
+ return 0;
+
+ count = be32_to_cpu(count);
+ for (i = 0; i < count; i++) {
+ file = malloc(sizeof(*file));
+ if (!file) {
+ printf("error: allocating resource\n");
+ goto err;
+ }
+ qfw_read_entry(dev, FW_CFG_INVALID,
+ sizeof(struct fw_cfg_file), &file->cfg);
+ file->addr = 0;
+ list_add_tail(&file->list, &qdev->fw_list);
+ }
+
+ return 0;
+
+err:
+ list_for_each(entry, &qdev->fw_list) {
+ file = list_entry(entry, struct fw_file, list);
+ free(file);
+ }
+
+ return -ENOMEM;
+}
+
+struct fw_file *qfw_find_file(struct udevice *dev, const char *name)
+{
+ struct list_head *entry;
+ struct fw_file *file;
+
+ struct qfw_dev *qdev = dev_get_uclass_priv(dev);
+
+ list_for_each(entry, &qdev->fw_list) {
+ file = list_entry(entry, struct fw_file, list);
+ if (!strcmp(file->cfg.name, name))
+ return file;
+ }
+
+ return NULL;
+}
+
+struct fw_file *qfw_file_iter_init(struct udevice *dev,
+ struct fw_cfg_file_iter *iter)
+{
+ struct qfw_dev *qdev = dev_get_uclass_priv(dev);
+
+ iter->entry = qdev->fw_list.next;
+ iter->end = &qdev->fw_list;
+ return list_entry((struct list_head *)iter->entry,
+ struct fw_file, list);
+}
+
+struct fw_file *qfw_file_iter_next(struct fw_cfg_file_iter *iter)
+{
+ iter->entry = ((struct list_head *)iter->entry)->next;
+ return list_entry((struct list_head *)iter->entry,
+ struct fw_file, list);
+}
+
+bool qfw_file_iter_end(struct fw_cfg_file_iter *iter)
+{
+ return iter->entry == iter->end;
+}
diff --git a/roms/u-boot/common/s_record.c b/roms/u-boot/common/s_record.c
new file mode 100644
index 000000000..2b7651fcf
--- /dev/null
+++ b/roms/u-boot/common/s_record.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <common.h>
+#include <s_record.h>
+
+static int hex1_bin (char c);
+static int hex2_bin (char *s);
+
+int srec_decode (char *input, int *count, ulong *addr, char *data)
+{
+ int i;
+ int v; /* conversion buffer */
+ int srec_type; /* S-Record type */
+ unsigned char chksum; /* buffer for checksum */
+
+ chksum = 0;
+
+ /* skip anything before 'S', and the 'S' itself.
+ * Return error if not found
+ */
+
+ for (; *input; ++input) {
+ if (*input == 'S') { /* skip 'S' */
+ ++input;
+ break;
+ }
+ }
+ if (*input == '\0') { /* no more data? */
+ return (SREC_EMPTY);
+ }
+
+ v = *input++; /* record type */
+
+ if ((*count = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+
+ chksum += *count;
+ input += 2;
+
+ switch (v) { /* record type */
+
+ case '0': /* start record */
+ srec_type = SREC_START; /* 2 byte addr field */
+ *count -= 3; /* - checksum and addr */
+ break;
+ case '1':
+ srec_type = SREC_DATA2; /* 2 byte addr field */
+ *count -= 3; /* - checksum and addr */
+ break;
+ case '2':
+ srec_type = SREC_DATA3; /* 3 byte addr field */
+ *count -= 4; /* - checksum and addr */
+ break;
+ case '3': /* data record with a */
+ srec_type = SREC_DATA4; /* 4 byte addr field */
+ *count -= 5; /* - checksum and addr */
+ break;
+/*** case '4' ***/
+ case '5': /* count record, addr field contains */
+ srec_type = SREC_COUNT; /* a 2 byte record counter */
+ *count = 0; /* no data */
+ break;
+/*** case '6' -- not used ***/
+ case '7': /* end record with a */
+ srec_type = SREC_END4; /* 4 byte addr field */
+ *count -= 5; /* - checksum and addr */
+ break;
+ case '8': /* end record with a */
+ srec_type = SREC_END3; /* 3 byte addr field */
+ *count -= 4; /* - checksum and addr */
+ break;
+ case '9': /* end record with a */
+ srec_type = SREC_END2; /* 2 byte addr field */
+ *count -= 3; /* - checksum and addr */
+ break;
+ default:
+ return (SREC_E_BADTYPE);
+ }
+
+ /* read address field */
+ *addr = 0;
+
+ switch (v) {
+ case '3': /* 4 byte addr field */
+ case '7':
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr += v;
+ chksum += v;
+ input += 2;
+ /* FALL THRU */
+ case '2': /* 3 byte addr field */
+ case '8':
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr <<= 8;
+ *addr += v;
+ chksum += v;
+ input += 2;
+ /* FALL THRU */
+ case '0': /* 2 byte addr field */
+ case '1':
+ case '5':
+ case '9':
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr <<= 8;
+ *addr += v;
+ chksum += v;
+ input += 2;
+
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr <<= 8;
+ *addr += v;
+ chksum += v;
+ input += 2;
+
+ break;
+ default:
+ return (SREC_E_BADTYPE);
+ }
+
+ /* convert data and calculate checksum */
+ for (i=0; i < *count; ++i) {
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ data[i] = v;
+ chksum += v;
+ input += 2;
+ }
+
+ /* read anc check checksum */
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+
+ if ((unsigned char)v != (unsigned char)~chksum) {
+ return (SREC_E_BADCHKS);
+ }
+
+ return (srec_type);
+}
+
+static int hex1_bin (char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return (c + 10 - 'a');
+ if (c >= 'A' && c <= 'F')
+ return (c + 10 - 'A');
+ return (-1);
+}
+
+static int hex2_bin (char *s)
+{
+ int i, j;
+
+ if ((i = hex1_bin(*s++)) < 0) {
+ return (-1);
+ }
+ if ((j = hex1_bin(*s)) < 0) {
+ return (-1);
+ }
+
+ return ((i<<4) + j);
+}
diff --git a/roms/u-boot/common/scp03.c b/roms/u-boot/common/scp03.c
new file mode 100644
index 000000000..09ef7b5ba
--- /dev/null
+++ b/roms/u-boot/common/scp03.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2021, Foundries.IO
+ *
+ */
+
+#include <common.h>
+#include <scp03.h>
+#include <tee.h>
+#include <tee/optee_ta_scp03.h>
+
+static int scp03_enable(bool provision)
+{
+ const struct tee_optee_ta_uuid uuid = PTA_SCP03_UUID;
+ struct tee_open_session_arg session;
+ struct tee_invoke_arg invoke;
+ struct tee_param param;
+ struct udevice *tee = NULL;
+
+ tee = tee_find_device(tee, NULL, NULL, NULL);
+ if (!tee)
+ return -ENODEV;
+
+ memset(&session, 0, sizeof(session));
+ tee_optee_ta_uuid_to_octets(session.uuid, &uuid);
+ if (tee_open_session(tee, &session, 0, NULL))
+ return -ENXIO;
+
+ memset(&param, 0, sizeof(param));
+ param.attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param.u.value.a = provision;
+
+ memset(&invoke, 0, sizeof(invoke));
+ invoke.func = PTA_CMD_ENABLE_SCP03;
+ invoke.session = session.session;
+
+ if (tee_invoke_func(tee, &invoke, 1, &param))
+ return -EIO;
+
+ tee_close_session(tee, session.session);
+
+ return 0;
+}
+
+int tee_enable_scp03(void)
+{
+ return scp03_enable(false);
+}
+
+int tee_provision_scp03(void)
+{
+ return scp03_enable(true);
+}
diff --git a/roms/u-boot/common/spl/Kconfig b/roms/u-boot/common/spl/Kconfig
new file mode 100644
index 000000000..fa80524cf
--- /dev/null
+++ b/roms/u-boot/common/spl/Kconfig
@@ -0,0 +1,1639 @@
+menu "SPL / TPL"
+
+config SUPPORT_SPL
+ bool
+
+config SUPPORT_TPL
+ bool
+
+config SPL_DFU_NO_RESET
+ bool
+
+config SPL
+ bool
+ depends on SUPPORT_SPL
+ prompt "Enable SPL"
+ help
+ If you want to build SPL as well as the normal image, say Y.
+
+config SPL_FRAMEWORK
+ bool "Support SPL based upon the common SPL framework"
+ depends on SPL
+ default y
+ help
+ Enable the SPL framework under common/spl/. This framework
+ supports MMC, NAND and YMODEM and other methods loading of U-Boot
+ and the Linux Kernel. If unsure, say Y.
+
+config SPL_FRAMEWORK_BOARD_INIT_F
+ bool "Define a generic function board_init_f"
+ depends on SPL_FRAMEWORK
+ help
+ Define a generic function board_init_f that:
+ - initialize the spl (spl_early_init)
+ - initialize the serial (preloader_console_init)
+ Unless you want to provide your own board_init_f, you should say Y.
+
+config SPL_SIZE_LIMIT
+ hex "Maximum size of SPL image"
+ depends on SPL
+ default 0x11000 if ARCH_MX6 && !MX6_OCRAM_256KB
+ default 0x31000 if ARCH_MX6 && MX6_OCRAM_256KB
+ default 0x0
+ help
+ Specifies the maximum length of the U-Boot SPL image.
+ If this value is zero, it is ignored.
+
+config SPL_SIZE_LIMIT_SUBTRACT_GD
+ bool "SPL image size check: provide space for global data"
+ depends on SPL_SIZE_LIMIT > 0
+ help
+ If enabled, aligned size of global data is reserved in
+ SPL_SIZE_LIMIT check to ensure such an image does not overflow SRAM
+ if SPL_SIZE_LIMIT describes the size of SRAM available for SPL when
+ pre-reloc global data is put into this SRAM, too.
+
+config SPL_SIZE_LIMIT_SUBTRACT_MALLOC
+ bool "SPL image size check: provide space for malloc() pool before relocation"
+ depends on SPL_SIZE_LIMIT > 0
+ help
+ If enabled, SPL_SYS_MALLOC_F_LEN is reserved in SPL_SIZE_LIMIT check
+ to ensure such an image does not overflow SRAM if SPL_SIZE_LIMIT
+ describes the size of SRAM available for SPL when pre-reloc malloc
+ pool is put into this SRAM, too.
+
+config SPL_SIZE_LIMIT_PROVIDE_STACK
+ hex "SPL image size check: provide stack space before relocation"
+ depends on SPL_SIZE_LIMIT > 0
+ default 0
+ help
+ If set, this size is reserved in SPL_SIZE_LIMIT check to ensure such
+ an image does not overflow SRAM if SPL_SIZE_LIMIT describes the size
+ of SRAM available for SPL when the stack required before reolcation
+ uses this SRAM, too.
+
+config SPL_SYS_STACK_F_CHECK_BYTE
+ hex
+ default 0xaa
+ help
+ Constant used to check the stack
+
+config SPL_SYS_REPORT_STACK_F_USAGE
+ depends on SPL_SIZE_LIMIT_PROVIDE_STACK != 0
+ bool "Check and report stack usage in SPL before relocation"
+ help
+ If this option is enabled, the initial SPL stack is filled with 0xaa
+ very early, up to the size configured with
+ SPL_SIZE_LIMIT_PROVIDE_STACK.
+ Later when SPL is done using this initial stack and switches to a
+ stack in DRAM, the actually used size of this initial stack is
+ reported by examining the memory and searching for the lowest
+ occurrence of non 0xaa bytes.
+ This default implementation works for stacks growing down only.
+
+menu "PowerPC and LayerScape SPL Boot options"
+
+config SPL_NAND_BOOT
+ bool "Load SPL from NAND flash"
+ depends on PPC && (SUPPORT_SPL && !SPL_FRAMEWORK)
+
+config SPL_MMC_BOOT
+ bool "Load SPL from SD Card / eMMC"
+ depends on PPC && (SUPPORT_SPL && !SPL_FRAMEWORK)
+
+config SPL_SPI_BOOT
+ bool "Load SPL from SPI flash"
+ depends on PPC && (SUPPORT_SPL && !SPL_FRAMEWORK)
+
+config SPL_FSL_PBL
+ bool "Create SPL in Freescale PBI format"
+ depends on (PPC || ARCH_LS1021A || ARCH_LS1043A || ARCH_LS1046A) && \
+ SUPPORT_SPL
+ help
+ Create boot binary having SPL binary in PBI format concatenated with
+ u-boot binary.
+
+endmenu
+
+config HANDOFF
+ bool "Pass hand-off information from SPL to U-Boot proper"
+ depends on SPL && BLOBLIST
+ help
+ It is useful to be able to pass information from SPL to U-Boot
+ proper to preserve state that is known in SPL and is needed in U-Boot.
+ Enable this to locate the handoff information in U-Boot proper, early
+ in boot. It is available in gd->handoff. The state state is set up
+ in SPL (or TPL if that is being used).
+
+if SPL
+
+config SPL_HANDOFF
+ bool "Pass hand-off information from SPL to U-Boot proper"
+ depends on HANDOFF && SPL_BLOBLIST
+ default y
+ help
+ This option enables SPL to write handoff information. This can be
+ used to pass information like the size of SDRAM from SPL to U-Boot
+ proper. Also SPL can receive information from TPL in the same place
+ if that is enabled.
+
+config SPL_LDSCRIPT
+ string "Linker script for the SPL stage"
+ default "arch/\$(ARCH)/cpu/u-boot-spl.lds"
+ help
+ The SPL stage will usually require a different linker-script
+ (as it runs from a different memory region) than the regular
+ U-Boot stage. Set this to the path of the linker-script to
+ be used for SPL.
+
+config SPL_TEXT_BASE
+ hex "SPL Text Base"
+ default ISW_ENTRY_ADDR if AM43XX || AM33XX || OMAP54XX || ARCH_KEYSTONE
+ default 0x10060 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN9I
+ default 0x20060 if SUN50I_GEN_H6
+ default 0x00060 if ARCH_SUNXI
+ default 0xfffc0000 if ARCH_ZYNQMP
+ default 0x0
+ help
+ The address in memory that SPL will be running from.
+
+config SPL_BOARD_INIT
+ bool "Call board-specific initialization in SPL"
+ help
+ If this option is enabled, U-Boot will call the function
+ spl_board_init() from board_init_r(). This function should be
+ provided by the board.
+
+config SPL_BOOTROM_SUPPORT
+ bool "Support returning to the BOOTROM"
+ help
+ Some platforms (e.g. the Rockchip RK3368) provide support in their
+ ROM for loading the next boot-stage after performing basic setup
+ from the SPL stage.
+
+ Enable this option, to return to the BOOTROM through the
+ BOOT_DEVICE_BOOTROM (or fall-through to the next boot device in the
+ boot device list, if not implemented for a given board)
+
+config SPL_BOOTCOUNT_LIMIT
+ bool "Support bootcount in SPL"
+ depends on SPL_ENV_SUPPORT && !TPL_BOOTCOUNT_LIMIT
+ help
+ On some boards, which use 'falcon' mode, it is necessary to check
+ and increment the number of boot attempts. Such boards do not
+ use proper U-Boot for normal boot flow and hence needs those
+ adjustments to be done in the SPL.
+
+config SPL_RAW_IMAGE_SUPPORT
+ bool "Support SPL loading and booting of RAW images"
+ default n if (ARCH_MX6 && (SPL_MMC_SUPPORT || SPL_SATA_SUPPORT))
+ default y if !TI_SECURE_DEVICE
+ help
+ SPL will support loading and booting a RAW image when this option
+ is y. If this is not set, SPL will move on to other available
+ boot media to find a suitable image.
+
+config SPL_LEGACY_IMAGE_SUPPORT
+ bool "Support SPL loading and booting of Legacy images"
+ default y if !TI_SECURE_DEVICE && !SPL_LOAD_FIT
+ help
+ SPL will support loading and booting Legacy images when this option
+ is y. If this is not set, SPL will move on to other available
+ boot media to find a suitable image.
+
+config SPL_LEGACY_IMAGE_CRC_CHECK
+ bool "Check CRC of Legacy images"
+ depends on SPL_LEGACY_IMAGE_SUPPORT
+ select SPL_CRC32_SUPPORT
+ help
+ Enable this to check the CRC of Legacy images. While this increases
+ reliability, it affects both code size and boot duration.
+ If disabled, Legacy images are booted if the image magic and size
+ are correct, without further integrity checks.
+
+config SPL_SYS_MALLOC_SIMPLE
+ bool
+ prompt "Only use malloc_simple functions in the SPL"
+ help
+ Say Y here to only use the *_simple malloc functions from
+ malloc_simple.c, rather then using the versions from dlmalloc.c;
+ this will make the SPL binary smaller at the cost of more heap
+ usage as the *_simple malloc functions do not re-use free-ed mem.
+
+config TPL_SYS_MALLOC_SIMPLE
+ bool
+ prompt "Only use malloc_simple functions in the TPL"
+ depends on TPL
+ help
+ Say Y here to only use the *_simple malloc functions from
+ malloc_simple.c, rather then using the versions from dlmalloc.c;
+ this will make the TPL binary smaller at the cost of more heap
+ usage as the *_simple malloc functions do not re-use free-ed mem.
+
+config SPL_STACK_R
+ bool "Enable SDRAM location for SPL stack"
+ help
+ SPL starts off execution in SRAM and thus typically has only a small
+ stack available. Since SPL sets up DRAM while in its board_init_f()
+ function, it is possible for the stack to move there before
+ board_init_r() is reached. This option enables a special SDRAM
+ location for the SPL stack. U-Boot SPL switches to this after
+ board_init_f() completes, and before board_init_r() starts.
+
+config SPL_STACK_R_ADDR
+ depends on SPL_STACK_R
+ hex "SDRAM location for SPL stack"
+ default 0x82000000 if ARCH_OMAP2PLUS
+ help
+ Specify the address in SDRAM for the SPL stack. This will be set up
+ before board_init_r() is called.
+
+config SPL_STACK_R_MALLOC_SIMPLE_LEN
+ depends on SPL_STACK_R && SPL_SYS_MALLOC_SIMPLE
+ hex "Size of malloc_simple heap after switching to DRAM SPL stack"
+ default 0x100000
+ help
+ Specify the amount of the stack to use as memory pool for
+ malloc_simple after switching the stack to DRAM. This may be set
+ to give board_init_r() a larger heap then the initial heap in
+ SRAM which is limited to SYS_MALLOC_F_LEN bytes.
+
+config SPL_SEPARATE_BSS
+ bool "BSS section is in a different memory region from text"
+ help
+ Some platforms need a large BSS region in SPL and can provide this
+ because RAM is already set up. In this case BSS can be moved to RAM.
+ This option should then be enabled so that the correct device tree
+ location is used. Normally we put the device tree at the end of BSS
+ but with this option enabled, it goes at _image_binary_end.
+
+config SPL_READ_ONLY
+ bool
+ depends on SPL_OF_PLATDATA
+ # Bind cannot be supported because the udevice structs are in read-only
+ # memory so we cannot update the linked lists.
+ select SPL_OF_PLATDATA_NO_BIND
+ select SPL_OF_PLATDATA_RT
+ help
+ Some platforms (e.g. x86 Apollo Lake) load SPL into a read-only
+ section of memory. This means that of-platdata must make a copy (in
+ writeable memory) of anything it wants to modify, such as
+ device-private data.
+
+config SPL_BANNER_PRINT
+ bool "Enable output of the SPL banner 'U-Boot SPL ...'"
+ default y
+ help
+ If this option is enabled, SPL will print the banner with version
+ info. Disabling this option could be useful to reduce SPL boot time
+ (e.g. approx. 6 ms faster, when output on i.MX6 with 115200 baud).
+
+config TPL_BANNER_PRINT
+ bool "Enable output of the TPL banner 'U-Boot TPL ...'"
+ depends on TPL
+ default y
+ help
+ If this option is enabled, TPL will print the banner with version
+ info. Disabling this option could be useful to reduce TPL boot time
+ (e.g. approx. 6 ms faster, when output on i.MX6 with 115200 baud).
+
+config SPL_EARLY_BSS
+ depends on ARM && !ARM64
+ bool "Allows initializing BSS early before entering board_init_f"
+ help
+ On some platform we have sufficient memory available early on to
+ allow setting up and using a basic BSS prior to entering
+ board_init_f. Activating this option will also de-activate the
+ clearing of BSS during the SPL relocation process, thus allowing
+ to carry state from board_init_f to board_init_r by way of BSS.
+
+config SPL_DISPLAY_PRINT
+ bool "Display a board-specific message in SPL"
+ help
+ If this option is enabled, U-Boot will call the function
+ spl_display_print() immediately after displaying the SPL console
+ banner ("U-Boot SPL ..."). This function should be provided by
+ the board.
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+ bool "MMC raw mode: by sector"
+ default y if ARCH_SUNXI || ARCH_DAVINCI || ARCH_UNIPHIER || \
+ ARCH_MX6 || ARCH_MX7 || \
+ ARCH_ROCKCHIP || ARCH_MVEBU || ARCH_SOCFPGA || \
+ ARCH_AT91 || ARCH_ZYNQ || ARCH_KEYSTONE || OMAP34XX || \
+ OMAP44XX || OMAP54XX || AM33XX || AM43XX || \
+ TARGET_SIFIVE_UNLEASHED || TARGET_SIFIVE_UNMATCHED
+ help
+ Use sector number for specifying U-Boot location on MMC/SD in
+ raw mode.
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
+ hex "Address on the MMC to load U-Boot from"
+ depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+ default 0x40 if ARCH_SUNXI
+ default 0x75 if ARCH_DAVINCI
+ default 0x8a if ARCH_MX6 || ARCH_MX7
+ default 0x100 if ARCH_UNIPHIER
+ default 0x140 if ARCH_MVEBU
+ default 0x200 if ARCH_SOCFPGA || ARCH_AT91
+ default 0x300 if ARCH_ZYNQ || ARCH_KEYSTONE || OMAP34XX || OMAP44XX || \
+ OMAP54XX || AM33XX || AM43XX || ARCH_K3
+ default 0x4000 if ARCH_ROCKCHIP
+ default 0x822 if TARGET_SIFIVE_UNLEASHED || TARGET_SIFIVE_UNMATCHED
+ help
+ Address on the MMC to load U-Boot from, when the MMC is being used
+ in raw mode. Units: MMC sectors (1 sector = 512 bytes).
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_DATA_PART_OFFSET
+ hex "U-Boot main hardware partition image offset"
+ depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+ default 0x10 if ARCH_SUNXI
+ default 0x0
+ help
+ On some platforms SPL location depends on hardware partition. The ROM
+ code skips the MBR sector when loading SPL from main hardware data
+ partition. This adds offset to the main U-Boot image. Set this symbol
+ to the number of skipped sectors.
+
+ If unsure, leave the default.
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+ bool "MMC Raw mode: by partition"
+ help
+ Use a partition for loading U-Boot when using MMC/SD in raw mode.
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION
+ hex "Partition to use to load U-Boot from"
+ depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+ default 1
+ help
+ Partition on the MMC to load U-Boot from when the MMC is being
+ used in raw mode
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE
+ bool "MMC raw mode: by partition type"
+ depends on DOS_PARTITION && SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+ help
+ Use partition type for specifying U-Boot partition on MMC/SD in
+ raw mode. U-Boot will be loaded from the first partition of this
+ type to be found.
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_TYPE
+ hex "Partition Type on the MMC to load U-Boot from"
+ depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE
+ help
+ Partition Type on the MMC to load U-Boot from, when the MMC is being
+ used in raw mode.
+
+config SUPPORT_EMMC_BOOT_OVERRIDE_PART_CONFIG
+ bool "Override eMMC EXT_CSC_PART_CONFIG by user defined partition"
+ depends on SUPPORT_EMMC_BOOT
+ help
+ eMMC boot partition is normally configured by the bits of the EXT_CSD
+ register (EXT_CSC_PART_CONFIG), BOOT_PARTITION_ENABLE field. In some
+ cases it might be required in SPL to load the image from different
+ partition than the partition selected by EXT_CSC_PART_CONFIG register.
+ Enable this option if you intend to use an eMMC boot partition other
+ then selected via EXT_CSC_PART_CONFIG register and specify the custom
+ partition number by the CONFIG_SYS_MMCSD_RAW_MODE_EMMC_BOOT_PARTITION
+ option.
+
+config SYS_MMCSD_RAW_MODE_EMMC_BOOT_PARTITION
+ int "Number of the eMMC boot partition to use"
+ depends on SUPPORT_EMMC_BOOT_OVERRIDE_PART_CONFIG
+ default 1
+ help
+ eMMC boot partition number to use when the eMMC in raw mode and
+ the eMMC EXT_CSC_PART_CONFIG selection should be overridden in SPL
+ by user defined partition number.
+
+config SPL_CRC32_SUPPORT
+ bool "Support CRC32"
+ default y if SPL_LEGACY_IMAGE_SUPPORT
+ help
+ Enable this to support CRC32 in uImages or FIT images within SPL.
+ This is a 32-bit checksum value that can be used to verify images.
+ For FIT images, this is the least secure type of checksum, suitable
+ for detected accidental image corruption. For secure applications you
+ should consider SHA1 or SHA256.
+
+config SPL_MD5_SUPPORT
+ bool "Support MD5"
+ depends on SPL_FIT
+ help
+ Enable this to support MD5 in FIT images within SPL. An MD5
+ checksum is a 128-bit hash value used to check that the image
+ contents have not been corrupted. Note that MD5 is not considered
+ secure as it is possible (with a brute-force attack) to adjust the
+ image while still retaining the same MD5 hash value. For secure
+ applications where images may be changed maliciously, you should
+ consider SHA256 or SHA384.
+
+config SPL_SHA1_SUPPORT
+ bool "Support SHA1"
+ depends on SPL_FIT
+ select SHA1
+ help
+ Enable this to support SHA1 in FIT images within SPL. A SHA1
+ checksum is a 160-bit (20-byte) hash value used to check that the
+ image contents have not been corrupted or maliciously altered.
+ While SHA1 is fairly secure it is coming to the end of its life
+ due to the expanding computing power available to brute-force
+ attacks. For more security, consider SHA256 or SHA384.
+
+config SPL_SHA256_SUPPORT
+ bool "Support SHA256"
+ depends on SPL_FIT
+ select SHA256
+ help
+ Enable this to support SHA256 in FIT images within SPL. A SHA256
+ checksum is a 256-bit (32-byte) hash value used to check that the
+ image contents have not been corrupted.
+
+config SPL_SHA384_SUPPORT
+ bool "Support SHA384"
+ depends on SPL_FIT
+ select SHA384
+ select SHA512_ALGO
+ help
+ Enable this to support SHA384 in FIT images within SPL. A SHA384
+ checksum is a 384-bit (48-byte) hash value used to check that the
+ image contents have not been corrupted. Use this for the highest
+ security.
+
+config SPL_SHA512_SUPPORT
+ bool "Support SHA512"
+ depends on SPL_FIT
+ select SHA512
+ select SHA512_ALGO
+ help
+ Enable this to support SHA512 in FIT images within SPL. A SHA512
+ checksum is a 512-bit (64-byte) hash value used to check that the
+ image contents have not been corrupted.
+
+config SPL_FIT_IMAGE_TINY
+ bool "Remove functionality from SPL FIT loading to reduce size"
+ depends on SPL_FIT
+ default y if MACH_SUN50I || MACH_SUN50I_H5 || SUN50I_GEN_H6
+ default y if ARCH_IMX8M
+ help
+ Enable this to reduce the size of the FIT image loading code
+ in SPL, if space for the SPL binary is very tight.
+
+ This skips the recording of each loaded payload
+ (i.e. loadable) into the FDT (modifying the loaded FDT to
+ ensure this information is available to the next image
+ invoked).
+
+config SPL_CACHE_SUPPORT
+ bool "Support CACHE drivers"
+ help
+ Enable CACHE drivers in SPL. These drivers can keep data so that
+ future requests for that data can be served faster. Enable this option
+ to build the drivers in drivers/cache as part of an SPL build.
+
+config SPL_CPU
+ bool "Support CPU drivers"
+ help
+ Enable this to support CPU drivers in SPL. These drivers can set
+ up CPUs and provide information about them such as the model and
+ name. This can be useful in SPL since setting up the CPUs earlier
+ may improve boot performance. Enable this option to build the
+ drivers in drivers/cpu as part of an SPL build.
+
+config SPL_CRYPTO_SUPPORT
+ bool "Support crypto drivers"
+ help
+ Enable crypto drivers in SPL. These drivers can be used to
+ accelerate secure boot processing in secure applications. Enable
+ this option to build the drivers in drivers/crypto as part of an
+ SPL build.
+
+config SPL_HASH_SUPPORT
+ bool "Support hashing drivers"
+ select SHA1
+ select SHA256
+ help
+ Enable hashing drivers in SPL. These drivers can be used to
+ accelerate secure boot processing in secure applications. Enable
+ this option to build system-specific drivers for hash acceleration
+ as part of an SPL build.
+
+config TPL_HASH_SUPPORT
+ bool "Support hashing drivers in TPL"
+ depends on TPL
+ select SHA1
+ select SHA256
+ help
+ Enable hashing drivers in SPL. These drivers can be used to
+ accelerate secure boot processing in secure applications. Enable
+ this option to build system-specific drivers for hash acceleration
+ as part of an SPL build.
+
+config SPL_DMA
+ bool "Support DMA drivers"
+ help
+ Enable DMA (direct-memory-access) drivers in SPL. These drivers
+ can be used to handle memory-to-peripheral data transfer without
+ the CPU moving the data. Enable this option to build the drivers
+ in drivers/dma as part of an SPL build.
+
+config SPL_DRIVERS_MISC_SUPPORT
+ bool "Support misc drivers"
+ help
+ Enable miscellaneous drivers in SPL. These drivers perform various
+ tasks that don't fall nicely into other categories, Enable this
+ option to build the drivers in drivers/misc as part of an SPL
+ build, for those that support building in SPL (not all drivers do).
+
+config SPL_ENV_SUPPORT
+ bool "Support an environment"
+ help
+ Enable environment support in SPL. The U-Boot environment provides
+ a number of settings (essentially name/value pairs) which can
+ control many aspects of U-Boot's operation. Normally this is not
+ needed in SPL as it has a much simpler task with less
+ configuration. But some boards use this to support 'Falcon' boot
+ on EXT2 and FAT, where SPL boots directly into Linux without
+ starting U-Boot first. Enabling this option will make env_get()
+ and env_set() available in SPL.
+
+config SPL_SAVEENV
+ bool "Support save environment"
+ depends on SPL_ENV_SUPPORT
+ select SPL_MMC_WRITE if ENV_IS_IN_MMC
+ help
+ Enable save environment support in SPL after setenv. By default
+ the saveenv option is not provided in SPL, but some boards need
+ this support in 'Falcon' boot, where SPL need to boot from
+ different images based on environment variable set by OS. For
+ example OS may set "reboot_image" environment variable to
+ "recovery" inorder to boot recovery image by SPL. The SPL read
+ "reboot_image" and act accordingly and change the reboot_image
+ to default mode using setenv and save the environment.
+
+config SPL_ETH_SUPPORT
+ bool "Support Ethernet"
+ depends on SPL_ENV_SUPPORT
+ help
+ Enable access to the network subsystem and associated Ethernet
+ drivers in SPL. This permits SPL to load U-Boot over an Ethernet
+ link rather than from an on-board peripheral. Environment support
+ is required since the network stack uses a number of environment
+ variables. See also SPL_NET_SUPPORT.
+
+config SPL_FS_EXT4
+ bool "Support EXT filesystems"
+ help
+ Enable support for EXT2/3/4 filesystems with SPL. This permits
+ U-Boot (or Linux in Falcon mode) to be loaded from an EXT
+ filesystem from within SPL. Support for the underlying block
+ device (e.g. MMC or USB) must be enabled separately.
+
+config SPL_FS_SQUASHFS
+ bool "Support SquashFS filesystems"
+ select FS_SQUASHFS
+ help
+ Enable support for SquashFS filesystems with SPL. This permits
+ U-Boot (or Linux in Falcon mode) to be loaded from a SquashFS
+ filesystem from within SPL. Support for the underlying block
+ device (e.g. MMC or USB) must be enabled separately.
+
+config SPL_FS_FAT
+ bool "Support FAT filesystems"
+ select FS_FAT
+ help
+ Enable support for FAT and VFAT filesystems with SPL. This
+ permits U-Boot (or Linux in Falcon mode) to be loaded from a FAT
+ filesystem from within SPL. Support for the underlying block
+ device (e.g. MMC or USB) must be enabled separately.
+
+config SPL_FAT_WRITE
+ bool "Support write for FAT filesystems"
+ help
+ Enable write support for FAT and VFAT filesystems with SPL.
+ Support for the underlying block device (e.g. MMC or USB) must be
+ enabled separately.
+
+config SPL_FPGA
+ bool "Support FPGAs"
+ help
+ Enable support for FPGAs in SPL. Field-programmable Gate Arrays
+ provide software-configurable hardware which is typically used to
+ implement peripherals (such as UARTs, LCD displays, MMC) or
+ accelerate custom processing functions, such as image processing
+ or machine learning. Sometimes it is useful to program the FPGA
+ as early as possible during boot, and this option can enable that
+ within SPL.
+
+config SPL_GPIO_SUPPORT
+ bool "Support GPIO in SPL"
+ help
+ Enable support for GPIOs (General-purpose Input/Output) in SPL.
+ GPIOs allow U-Boot to read the state of an input line (high or
+ low) and set the state of an output line. This can be used to
+ drive LEDs, control power to various system parts and read user
+ input. GPIOs can be useful in SPL to enable a 'sign-of-life' LED,
+ for example. Enable this option to build the drivers in
+ drivers/gpio as part of an SPL build.
+
+config SPL_I2C_SUPPORT
+ bool "Support I2C"
+ help
+ Enable support for the I2C (Inter-Integrated Circuit) bus in SPL.
+ I2C works with a clock and data line which can be driven by a
+ one or more masters or slaves. It is a fairly complex bus but is
+ widely used as it only needs two lines for communication. Speeds of
+ 400kbps are typical but up to 3.4Mbps is supported by some
+ hardware. I2C can be useful in SPL to configure power management
+ ICs (PMICs) before raising the CPU clock speed, for example.
+ Enable this option to build the drivers in drivers/i2c as part of
+ an SPL build.
+
+config SPL_LIBCOMMON_SUPPORT
+ bool "Support common libraries"
+ help
+ Enable support for common U-Boot libraries within SPL. These
+ libraries include common code to deal with U-Boot images,
+ environment and USB, for example. This option is enabled on many
+ boards. Enable this option to build the code in common/ as part of
+ an SPL build.
+
+config SPL_LIBDISK_SUPPORT
+ bool "Support disk partitions"
+ select PARTITIONS
+ help
+ Enable support for disk partitions within SPL. 'Disk' is something
+ of a misnomer as it includes non-spinning media such as flash (as
+ used in MMC and USB sticks). Partitions provide a way for a disk
+ to be split up into separate regions, with a partition table placed
+ at the start or end which describes the location and size of each
+ 'partition'. These partitions are typically uses as individual block
+ devices, typically with an EXT2 or FAT filesystem in each. This
+ option enables whatever partition support has been enabled in
+ U-Boot to also be used in SPL. It brings in the code in disk/.
+
+config SPL_LIBGENERIC_SUPPORT
+ bool "Support generic libraries"
+ help
+ Enable support for generic U-Boot libraries within SPL. These
+ libraries include generic code to deal with device tree, hashing,
+ printf(), compression and the like. This option is enabled on many
+ boards. Enable this option to build the code in lib/ as part of an
+ SPL build.
+
+config SPL_DM_MAILBOX
+ bool "Support Mailbox"
+ help
+ Enable support for Mailbox within SPL. This enable the inter
+ processor communication protocols tobe used within SPL. Enable
+ this option to build the drivers in drivers/mailbox as part of
+ SPL build.
+
+config SPL_MMC_SUPPORT
+ bool "Support MMC"
+ depends on MMC
+ select HAVE_BLOCK_DEVICE
+ help
+ Enable support for MMC (Multimedia Card) within SPL. This enables
+ the MMC protocol implementation and allows any enabled drivers to
+ be used within SPL. MMC can be used with or without disk partition
+ support depending on the application (SPL_LIBDISK_SUPPORT). Enable
+ this option to build the drivers in drivers/mmc as part of an SPL
+ build.
+
+config SYS_MMCSD_FS_BOOT_PARTITION
+ int "MMC Boot Partition"
+ default 1
+ help
+ Partition on the MMC to load U-Boot from when the MMC is being
+ used in fs mode
+
+config SPL_MMC_TINY
+ bool "Tiny MMC framework in SPL"
+ depends on SPL_MMC_SUPPORT
+ default n
+ help
+ Enable MMC framework tinification support. This option is useful if
+ if your SPL is extremely size constrained. Heed the warning, enable
+ this option if and only if you know exactly what you are doing, if
+ you are reading this help text, you most likely have no idea :-)
+
+ The MMC framework is reduced to bare minimum to be useful. No malloc
+ support is needed for the MMC framework operation with this option
+ enabled. The framework supports exactly one MMC device and exactly
+ one MMC driver. The MMC driver can be adjusted to avoid any malloc
+ operations too, which can remove the need for malloc support in SPL
+ and thus further reduce footprint.
+
+config SPL_MMC_WRITE
+ bool "MMC/SD/SDIO card support for write operations in SPL"
+ depends on SPL_MMC_SUPPORT
+ default n
+ help
+ Enable write access to MMC and SD Cards in SPL
+
+
+config SPL_MPC8XXX_INIT_DDR_SUPPORT
+ bool "Support MPC8XXX DDR init"
+ help
+ Enable support for DDR-SDRAM (double-data-rate synchronous dynamic
+ random-access memory) on the MPC8XXX family within SPL. This
+ allows DRAM to be set up before loading U-Boot into that DRAM,
+ where it can run.
+
+config SPL_MTD_SUPPORT
+ bool "Support MTD drivers"
+ help
+ Enable support for MTD (Memory Technology Device) within SPL. MTD
+ provides a block interface over raw NAND and can also be used with
+ SPI flash. This allows SPL to load U-Boot from supported MTD
+ devices. See SPL_NAND_SUPPORT and SPL_ONENAND_SUPPORT for how
+ to enable specific MTD drivers.
+
+config SPL_MUSB_NEW_SUPPORT
+ bool "Support new Mentor Graphics USB"
+ help
+ Enable support for Mentor Graphics USB in SPL. This is a new
+ driver used by some boards. Enable this option to build
+ the drivers in drivers/usb/musb-new as part of an SPL build. The
+ old drivers are in drivers/usb/musb.
+
+config SPL_NAND_SUPPORT
+ bool "Support NAND flash"
+ help
+ Enable support for NAND (Negative AND) flash in SPL. NAND flash
+ can be used to allow SPL to load U-Boot from supported devices.
+ This enables the drivers in drivers/mtd/nand/raw as part of an SPL
+ build.
+
+config SPL_NAND_DRIVERS
+ bool "Use standard NAND driver"
+ help
+ SPL uses normal NAND drivers, not minimal drivers.
+
+config SPL_NAND_ECC
+ bool "Include standard software ECC in the SPL"
+
+config SPL_NAND_SIMPLE
+ bool "Support simple NAND drivers in SPL"
+ help
+ Support for NAND boot using simple NAND drivers that
+ expose the cmd_ctrl() interface.
+
+config SPL_NAND_BASE
+ depends on SPL_NAND_DRIVERS
+ bool "Use Base NAND Driver"
+ help
+ Include nand_base.c in the SPL.
+
+config SPL_NAND_IDENT
+ depends on SPL_NAND_BASE
+ bool "Use chip ID to identify NAND flash"
+ help
+ SPL uses the chip ID list to identify the NAND flash.
+
+config SPL_UBI
+ bool "Support UBI"
+ help
+ Enable support for loading payloads from UBI. See
+ README.ubispl for more info.
+
+if SPL_DM
+config SPL_CACHE
+ depends on CACHE
+ bool "Support cache drivers in SPL"
+ help
+ Enable support for cache drivers in SPL.
+
+config SPL_DM_SPI
+ bool "Support SPI DM drivers in SPL"
+ help
+ Enable support for SPI DM drivers in SPL.
+
+config SPL_DM_SPI_FLASH
+ bool "Support SPI DM FLASH drivers in SPL"
+ help
+ Enable support for SPI DM flash drivers in SPL.
+
+endif
+if SPL_UBI
+config SPL_UBI_LOAD_BY_VOLNAME
+ bool "Support loading volumes by name"
+ help
+ This enables support for loading UBI volumes by name. When this
+ is set, CONFIG_SPL_UBI_LOAD_MONITOR_VOLNAME can be used to
+ configure the volume name from which to load U-Boot.
+
+config SPL_UBI_MAX_VOL_LEBS
+ int "Maximum number of LEBs per volume"
+ depends on SPL_UBI
+ help
+ The maximum number of logical eraseblocks which a static volume
+ to load can contain. Used for sizing the scan data structure.
+
+config SPL_UBI_MAX_PEB_SIZE
+ int "Maximum PEB size"
+ depends on SPL_UBI
+ help
+ The maximum physical erase block size.
+
+config SPL_UBI_MAX_PEBS
+ int "Maximum number of PEBs"
+ depends on SPL_UBI
+ help
+ The maximum physical erase block size. If not overridden by
+ board code, this value will be used as the actual number of PEBs.
+
+config SPL_UBI_PEB_OFFSET
+ int "Offset to first UBI PEB"
+ depends on SPL_UBI
+ help
+ The offset in number of PEBs from the start of flash to the first
+ PEB part of the UBI image.
+
+config SPL_UBI_VID_OFFSET
+ int "Offset to VID header"
+ depends on SPL_UBI
+
+config SPL_UBI_LEB_START
+ int "Offset to LEB in PEB"
+ depends on SPL_UBI
+ help
+ The offset in bytes to the LEB within a PEB.
+
+config SPL_UBI_INFO_ADDR
+ hex "Address to place UBI scan info"
+ depends on SPL_UBI
+ help
+ Address for ubispl to place the scan info. Read README.ubispl to
+ determine the required size
+
+config SPL_UBI_VOL_IDS
+ int "Maximum volume id"
+ depends on SPL_UBI
+ help
+ The maximum volume id which can be loaded. Used for sizing the
+ scan data structure.
+
+config SPL_UBI_LOAD_MONITOR_ID
+ int "id of U-Boot volume"
+ depends on SPL_UBI
+ help
+ The UBI volume id from which to load U-Boot
+
+config SPL_UBI_LOAD_MONITOR_VOLNAME
+ string "volume name of U-Boot volume"
+ depends on SPL_UBI_LOAD_BY_VOLNAME
+ help
+ The UBI volume name from which to load U-Boot
+
+config SPL_UBI_LOAD_KERNEL_ID
+ int "id of kernel volume"
+ depends on SPL_OS_BOOT && SPL_UBI
+ help
+ The UBI volume id from which to load the kernel
+
+config SPL_UBI_LOAD_ARGS_ID
+ int "id of kernel args volume"
+ depends on SPL_OS_BOOT && SPL_UBI
+ help
+ The UBI volume id from which to load the device tree
+
+config UBI_SPL_SILENCE_MSG
+ bool "silence UBI SPL messages"
+ default n
+ help
+ Disable messages from UBI SPL. This leaves warnings
+ and errors enabled.
+
+endif # if SPL_UBI
+
+config SPL_NET_SUPPORT
+ bool "Support networking"
+ help
+ Enable support for network devices (such as Ethernet) in SPL.
+ This permits SPL to load U-Boot over a network link rather than
+ from an on-board peripheral. Environment support is required since
+ the network stack uses a number of environment variables. See also
+ SPL_ETH_SUPPORT.
+
+if SPL_NET_SUPPORT
+config SPL_NET_VCI_STRING
+ string "BOOTP Vendor Class Identifier string sent by SPL"
+ help
+ As defined by RFC 2132 the vendor class identifier field can be
+ sent by the client to identify the vendor type and configuration
+ of a client. This is often used in practice to allow for the DHCP
+ server to specify different files to load depending on if the ROM,
+ SPL or U-Boot itself makes the request
+endif # if SPL_NET_SUPPORT
+
+config SPL_NO_CPU_SUPPORT
+ bool "Drop CPU code in SPL"
+ help
+ This is specific to the ARM926EJ-S CPU. It disables the standard
+ start.S start-up code, presumably so that a replacement can be
+ used on that CPU. You should not enable it unless you know what
+ you are doing.
+
+config SPL_NOR_SUPPORT
+ bool "Support NOR flash"
+ help
+ Enable support for loading U-Boot from memory-mapped NOR (Negative
+ OR) flash in SPL. NOR flash is slow to write but fast to read, and
+ a memory-mapped device makes it very easy to access. Loading from
+ NOR is typically achieved with just a memcpy().
+
+config SPL_XIP_SUPPORT
+ bool "Support XIP"
+ depends on SPL
+ help
+ Enable support for execute in place of U-Boot or kernel image. There
+ is no need to copy image from flash to ram if flash supports execute
+ in place. Its very useful in systems having enough flash but not
+ enough ram to load the image.
+
+config SPL_ONENAND_SUPPORT
+ bool "Support OneNAND flash"
+ help
+ Enable support for OneNAND (Negative AND) flash in SPL. OneNAND is
+ a type of NAND flash and therefore can be used to allow SPL to
+ load U-Boot from supported devices. This enables the drivers in
+ drivers/mtd/onenand as part of an SPL build.
+
+config SPL_OS_BOOT
+ bool "Activate Falcon Mode"
+ depends on !TI_SECURE_DEVICE
+ default n
+ help
+ Enable booting directly to an OS from SPL.
+ for more info read doc/README.falcon
+
+if SPL_OS_BOOT
+config SYS_OS_BASE
+ hex "addr, where OS is found"
+ depends on SPL_NOR_SUPPORT
+ help
+ Specify the address, where the OS image is found, which
+ gets booted.
+
+endif # SPL_OS_BOOT
+
+config SPL_PAYLOAD
+ string "SPL payload"
+ default "tpl/u-boot-with-tpl.bin" if TPL
+ default "u-boot.bin"
+ help
+ Payload for SPL boot. For backward compatibility, default to
+ u-boot.bin, i.e. RAW image without any header. In case of
+ TPL, tpl/u-boot-with-tpl.bin. For new boards, suggest to
+ use u-boot.img.
+
+config SPL_PCI
+ bool "Support PCI drivers"
+ help
+ Enable support for PCI in SPL. For platforms that need PCI to boot,
+ or must perform some init using PCI in SPL, this provides the
+ necessary driver support. This enables the drivers in drivers/pci
+ as part of an SPL build.
+
+config SPL_PCH_SUPPORT
+ bool "Support PCH drivers"
+ help
+ Enable support for PCH (Platform Controller Hub) devices in SPL.
+ These are used to set up GPIOs and the SPI peripheral early in
+ boot. This enables the drivers in drivers/pch as part of an SPL
+ build.
+
+config SPL_POST_MEM_SUPPORT
+ bool "Support POST drivers"
+ help
+ Enable support for POST (Power-on Self Test) in SPL. POST is a
+ procedure that checks that the hardware (CPU or board) appears to
+ be functionally correctly. It is a sanity check that can be
+ performed before booting. This enables the drivers in post/drivers
+ as part of an SPL build.
+
+config SPL_DM_RESET
+ bool "Support reset drivers"
+ depends on SPL
+ help
+ Enable support for reset control in SPL.
+ That can be useful in SPL to handle IP reset in driver, as in U-Boot,
+ by using the generic reset API provided by driver model.
+ This enables the drivers in drivers/reset as part of an SPL build.
+
+config SPL_POWER_SUPPORT
+ bool "Support power drivers"
+ help
+ Enable support for power control in SPL. This includes support
+ for PMICs (Power-management Integrated Circuits) and some of the
+ features provided by PMICs. In particular, voltage regulators can
+ be used to enable/disable power and vary its voltage. That can be
+ useful in SPL to turn on boot peripherals and adjust CPU voltage
+ so that the clock speed can be increased. This enables the drivers
+ in drivers/power, drivers/power/pmic and drivers/power/regulator
+ as part of an SPL build.
+
+config SPL_POWER_DOMAIN
+ bool "Support power domain drivers"
+ help
+ Enable support for power domain control in SPL. Many SoCs allow
+ power to be applied to or removed from portions of the SoC (power
+ domains). This may be used to save power. This API provides the
+ means to control such power management hardware. This enables
+ the drivers in drivers/power/domain as part of a SPL build.
+
+config SPL_RAM_SUPPORT
+ bool "Support booting from RAM"
+ default y if MICROBLAZE || ARCH_SOCFPGA || ARCH_TEGRA || ARCH_ZYNQ
+ help
+ Enable booting of an image in RAM. The image can be preloaded or
+ it can be loaded by SPL directly into RAM (e.g. using USB).
+
+config SPL_RAM_DEVICE
+ bool "Support booting from preloaded image in RAM"
+ depends on SPL_RAM_SUPPORT
+ default y if MICROBLAZE || ARCH_SOCFPGA || ARCH_TEGRA || ARCH_ZYNQ
+ help
+ Enable booting of an image already loaded in RAM. The image has to
+ be already in memory when SPL takes over, e.g. loaded by the boot
+ ROM.
+
+config SPL_REMOTEPROC
+ bool "Support REMOTEPROCS"
+ help
+ Enable support for REMOTEPROCs in SPL. This permits to load
+ a remote processor firmware in SPL.
+
+config SPL_RTC_SUPPORT
+ bool "Support RTC drivers"
+ help
+ Enable RTC (Real-time Clock) support in SPL. This includes support
+ for reading and setting the time. Some RTC devices also have some
+ non-volatile (battery-backed) memory which is accessible if
+ needed. This enables the drivers in drivers/rtc as part of an SPL
+ build.
+
+config SPL_SATA_SUPPORT
+ bool "Support loading from SATA"
+ help
+ Enable support for SATA (Serial AT attachment) in SPL. This allows
+ use of SATA devices such as hard drives and flash drivers for
+ loading U-Boot. SATA is used in higher-end embedded systems and
+ can provide higher performance than MMC , at somewhat higher
+ expense and power consumption. This enables loading from SATA
+ using a configured device.
+
+config SPL_SATA_RAW_U_BOOT_USE_SECTOR
+ bool "SATA raw mode: by sector"
+ depends on SPL_SATA_SUPPORT
+ help
+ Use sector number for specifying U-Boot location on SATA disk in
+ raw mode.
+
+config SPL_SATA_RAW_U_BOOT_SECTOR
+ hex "Sector on the SATA disk to load U-Boot from"
+ depends on SPL_SATA_RAW_U_BOOT_USE_SECTOR
+ help
+ Sector on the SATA disk to load U-Boot from, when the SATA disk is being
+ used in raw mode. Units: SATA disk sectors (1 sector = 512 bytes).
+
+config SPL_SERIAL_SUPPORT
+ bool "Support serial"
+ select SPL_PRINTF
+ select SPL_STRTO
+ help
+ Enable support for serial in SPL. This allows use of a serial UART
+ for displaying messages while SPL is running. It also brings in
+ printf() and panic() functions. This should normally be enabled
+ unless there are space reasons not to. Even then, consider
+ enabling SPL_USE_TINY_PRINTF which is a small printf() version.
+
+config SPL_SPI_SUPPORT
+ bool "Support SPI drivers"
+ help
+ Enable support for using SPI in SPL. This is used for connecting
+ to SPI flash for loading U-Boot. See SPL_SPI_FLASH_SUPPORT for
+ more details on that. The SPI driver provides the transport for
+ data between the SPI flash and the CPU. This option can be used to
+ enable SPI drivers that are needed for other purposes also, such
+ as a SPI PMIC.
+
+config SPL_SPI_FLASH_SUPPORT
+ bool "Support SPI flash drivers"
+ depends on SPL_SPI_SUPPORT
+ help
+ Enable support for using SPI flash in SPL, and loading U-Boot from
+ SPI flash. SPI flash (Serial Peripheral Bus flash) is named after
+ the SPI bus that is used to connect it to a system. It is a simple
+ but fast bidirectional 4-wire bus (clock, chip select and two data
+ lines). This enables the drivers in drivers/mtd/spi as part of an
+ SPL build. This normally requires SPL_SPI_SUPPORT.
+
+if SPL_SPI_FLASH_SUPPORT
+
+config SPL_SPI_FLASH_TINY
+ bool "Enable low footprint SPL SPI Flash support"
+ depends on !SPI_FLASH_BAR
+ default y if SPI_FLASH
+ help
+ Enable lightweight SPL SPI Flash support that supports just reading
+ data/images from flash. No support to write/erase flash. Enable
+ this if you have SPL size limitations and don't need full
+ fledged SPI flash support.
+
+config SPL_SPI_FLASH_SFDP_SUPPORT
+ bool "SFDP table parsing support for SPI NOR flashes"
+ depends on !SPI_FLASH_BAR && !SPL_SPI_FLASH_TINY
+ help
+ Enable support for parsing and auto discovery of parameters for
+ SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP)
+ tables as per JESD216 standard in SPL.
+
+config SPL_SPI_FLASH_MTD
+ bool "Support for SPI flash MTD drivers in SPL"
+ help
+ Enable support for SPI flash MTD drivers in SPL.
+
+config SPL_SPI_LOAD
+ bool "Support loading from SPI flash"
+ help
+ Enable support for loading next stage, U-Boot or otherwise, from
+ SPI NOR in U-Boot SPL.
+
+endif # SPL_SPI_FLASH_SUPPORT
+
+config SYS_SPI_U_BOOT_OFFS
+ hex "address of u-boot payload in SPI flash"
+ default 0x8000 if ARCH_SUNXI
+ default 0x0
+ depends on SPL_SPI_LOAD || SPL_SPI_SUNXI
+ help
+ Address within SPI-Flash from where the u-boot payload is fetched
+ from.
+
+config SPL_THERMAL
+ bool "Driver support for thermal devices"
+ help
+ Enable support for temperature-sensing devices. Some SoCs have on-chip
+ temperature sensors to permit warnings, speed throttling or even
+ automatic power-off when the temperature gets too high or low. Other
+ devices may be discrete but connected on a suitable bus.
+
+config SPL_USB_HOST_SUPPORT
+ bool "Support USB host drivers"
+ select HAVE_BLOCK_DEVICE
+ help
+ Enable access to USB (Universal Serial Bus) host devices so that
+ SPL can load U-Boot from a connected USB peripheral, such as a USB
+ flash stick. While USB takes a little longer to start up than most
+ buses, it is very flexible since many different types of storage
+ device can be attached. This option enables the drivers in
+ drivers/usb/host as part of an SPL build.
+
+config SPL_USB_STORAGE
+ bool "Support loading from USB"
+ depends on SPL_USB_HOST_SUPPORT && !(BLK && !DM_USB)
+ help
+ Enable support for USB devices in SPL. This allows use of USB
+ devices such as hard drives and flash drivers for loading U-Boot.
+ The actual drivers are enabled separately using the normal U-Boot
+ config options. This enables loading from USB using a configured
+ device.
+
+config SPL_USB_GADGET
+ bool "Suppport USB Gadget drivers"
+ help
+ Enable USB Gadget API which allows to enable USB device functions
+ in SPL.
+
+if SPL_USB_GADGET
+
+config SPL_USB_ETHER
+ bool "Support USB Ethernet drivers"
+ help
+ Enable access to the USB network subsystem and associated
+ drivers in SPL. This permits SPL to load U-Boot over a
+ USB-connected Ethernet link (such as a USB Ethernet dongle) rather
+ than from an onboard peripheral. Environment support is required
+ since the network stack uses a number of environment variables.
+ See also SPL_NET_SUPPORT and SPL_ETH_SUPPORT.
+
+config SPL_DFU
+ bool "Support DFU (Device Firmware Upgrade)"
+ select SPL_HASH_SUPPORT
+ select SPL_DFU_NO_RESET
+ depends on SPL_RAM_SUPPORT
+ help
+ This feature enables the DFU (Device Firmware Upgrade) in SPL with
+ RAM memory device support. The ROM code will load and execute
+ the SPL built with dfu. The user can load binaries (u-boot/kernel) to
+ selected device partition from host-pc using dfu-utils.
+ This feature is useful to flash the binaries to factory or bare-metal
+ boards using USB interface.
+
+choice
+ bool "DFU device selection"
+ depends on SPL_DFU
+
+config SPL_DFU_RAM
+ bool "RAM device"
+ depends on SPL_DFU && SPL_RAM_SUPPORT
+ help
+ select RAM/DDR memory device for loading binary images
+ (u-boot/kernel) to the selected device partition using
+ DFU and execute the u-boot/kernel from RAM.
+
+endchoice
+
+config SPL_USB_SDP_SUPPORT
+ bool "Support SDP (Serial Download Protocol)"
+ depends on SPL_SERIAL_SUPPORT
+ help
+ Enable Serial Download Protocol (SDP) device support in SPL. This
+ allows to download images into memory and execute (jump to) them
+ using the same protocol as implemented by the i.MX family's boot ROM.
+
+config SPL_SDP_USB_DEV
+ int "SDP USB controller index"
+ default 0
+ depends on SPL_USB_SDP_SUPPORT
+ help
+ Some boards have USB controller other than 0. Define this option
+ so it can be used in compiled environment.
+endif
+
+config SPL_WATCHDOG_SUPPORT
+ bool "Support watchdog drivers"
+ imply SPL_WDT if !HW_WATCHDOG
+ help
+ Enable support for watchdog drivers in SPL. A watchdog is
+ typically a hardware peripheral which can reset the system when it
+ detects no activity for a while (such as a software crash). This
+ enables the drivers in drivers/watchdog as part of an SPL build.
+
+config SPL_YMODEM_SUPPORT
+ bool "Support loading using Ymodem"
+ depends on SPL_SERIAL_SUPPORT
+ help
+ While loading from serial is slow it can be a useful backup when
+ there is no other option. The Ymodem protocol provides a reliable
+ means of transmitting U-Boot over a serial line for using in SPL,
+ with a checksum to ensure correctness.
+
+config SPL_ATF
+ bool "Support ARM Trusted Firmware"
+ depends on ARM64 && SPL_FIT
+ help
+ ATF(ARM Trusted Firmware) is a component for ARM AArch64 which
+ is loaded by SPL (which is considered as BL2 in ATF terminology).
+ More detail at: https://github.com/ARM-software/arm-trusted-firmware
+
+config SPL_ATF_LOAD_IMAGE_V2
+ bool "Use the new LOAD_IMAGE_V2 parameter passing"
+ depends on SPL_ATF
+ help
+ Some platforms use the newer LOAD_IMAGE_V2 parameter passing.
+
+ If you want to load a bl31 image from the SPL and need the new
+ method, say Y.
+
+config SPL_ATF_NO_PLATFORM_PARAM
+ bool "Pass no platform parameter"
+ depends on SPL_ATF
+ help
+ While we expect to call a pointer to a valid FDT (or NULL)
+ as the platform parameter to an ATF, some ATF versions are
+ not U-Boot aware and have an insufficiently robust parameter
+ validation to gracefully reject a FDT being passed.
+
+ If this option is enabled, the spl_atf os-type handler will
+ always pass NULL for the platform parameter.
+
+ If your ATF is affected, say Y.
+
+config SPL_AM33XX_ENABLE_RTC32K_OSC
+ bool "Enable the RTC32K OSC on AM33xx based platforms"
+ default y if AM33XX
+ help
+ Enable access to the AM33xx RTC and select the external 32kHz clock
+ source.
+
+config SPL_OPTEE
+ bool "Support OP-TEE Trusted OS"
+ depends on ARM
+ help
+ OP-TEE is an open source Trusted OS which is loaded by SPL.
+ More detail at: https://github.com/OP-TEE/optee_os
+
+config SPL_OPENSBI
+ bool "Support RISC-V OpenSBI"
+ depends on RISCV && SPL_RISCV_MMODE && RISCV_SMODE
+ help
+ OpenSBI is an open-source implementation of the RISC-V Supervisor Binary
+ Interface (SBI) specification. U-Boot supports the OpenSBI FW_DYNAMIC
+ firmware. It is loaded and started by U-Boot SPL.
+
+ More details are available at https://github.com/riscv/opensbi and
+ https://github.com/riscv/riscv-sbi-doc
+
+config SPL_OPENSBI_LOAD_ADDR
+ hex "OpenSBI load address"
+ depends on SPL_OPENSBI
+ help
+ Load address of the OpenSBI binary.
+
+config TPL
+ bool
+ depends on SUPPORT_TPL
+ prompt "Enable TPL"
+ help
+ If you want to build TPL as well as the normal image and SPL, say Y.
+
+if TPL
+
+config TPL_SIZE_LIMIT
+ hex "Maximum size of TPL image"
+ depends on TPL
+ default 0x0
+ help
+ Specifies the maximum length of the U-Boot TPL image.
+ If this value is zero, it is ignored.
+
+config TPL_FRAMEWORK
+ bool "Support TPL based upon the common SPL framework"
+ default y if SPL_FRAMEWORK
+ help
+ Enable the SPL framework under common/spl/ for TPL builds.
+ This framework supports MMC, NAND and YMODEM and other methods
+ loading of U-Boot's SPL stage. If unsure, say Y.
+
+config TPL_HANDOFF
+ bool "Pass hand-off information from TPL to SPL and U-Boot proper"
+ depends on HANDOFF && TPL_BLOBLIST
+ default y
+ help
+ This option enables TPL to write handoff information. This can be
+ used to pass information like the size of SDRAM from TPL to U-Boot
+ proper. The information is also available to SPL if it is useful
+ there.
+
+config TPL_BOARD_INIT
+ bool "Call board-specific initialization in TPL"
+ help
+ If this option is enabled, U-Boot will call the function
+ spl_board_init() from board_init_r(). This function should be
+ provided by the board.
+
+config TPL_BOOTCOUNT_LIMIT
+ bool "Support bootcount in TPL"
+ depends on TPL_ENV_SUPPORT
+ help
+ If this option is enabled, the TPL will support bootcount.
+ For example, it may be useful to choose the device to boot.
+
+config TPL_LDSCRIPT
+ string "Linker script for the TPL stage"
+ depends on TPL
+ default "arch/arm/cpu/armv8/u-boot-spl.lds" if ARM64
+ default "arch/\$(ARCH)/cpu/u-boot-spl.lds"
+ help
+ The TPL stage will usually require a different linker-script
+ (as it runs from a different memory region) than the regular
+ U-Boot stage. Set this to the path of the linker-script to
+ be used for TPL.
+
+ May be left empty to trigger the Makefile infrastructure to
+ fall back to the linker-script used for the SPL stage.
+
+config TPL_NEEDS_SEPARATE_TEXT_BASE
+ bool "TPL needs a separate text-base"
+ default n
+ depends on TPL
+ help
+ Enable, if the TPL stage should not inherit its text-base
+ from the SPL stage. When enabled, a base address for the
+ .text sections of the TPL stage has to be set below.
+
+config TPL_NEEDS_SEPARATE_STACK
+ bool "TPL needs a separate initial stack-pointer"
+ default n
+ depends on TPL
+ help
+ Enable, if the TPL stage should not inherit its initial
+ stack-pointer from the settings for the SPL stage.
+
+config TPL_TEXT_BASE
+ hex "Base address for the .text section of the TPL stage"
+ depends on TPL_NEEDS_SEPARATE_TEXT_BASE
+ help
+ The base address for the .text section of the TPL stage.
+
+config TPL_MAX_SIZE
+ int "Maximum size (in bytes) for the TPL stage"
+ default 0
+ depends on TPL
+ help
+ The maximum size (in bytes) of the TPL stage.
+
+config TPL_STACK
+ hex "Address of the initial stack-pointer for the TPL stage"
+ depends on TPL_NEEDS_SEPARATE_STACK
+ help
+ The address of the initial stack-pointer for the TPL stage.
+ Usually this will be the (aligned) top-of-stack.
+
+config TPL_READ_ONLY
+ bool
+ depends on TPL_OF_PLATDATA
+ select TPL_OF_PLATDATA_NO_BIND
+ select TPL_OF_PLATDATA_RT
+ help
+ Some platforms (e.g. x86 Apollo Lake) load SPL into a read-only
+ section of memory. This means that of-platdata must make a copy (in
+ writeable memory) of anything it wants to modify, such as
+ device-private data.
+
+config TPL_BOOTROM_SUPPORT
+ bool "Support returning to the BOOTROM (from TPL)"
+ help
+ Some platforms (e.g. the Rockchip RK3368) provide support in their
+ ROM for loading the next boot-stage after performing basic setup
+ from the TPL stage.
+
+ Enable this option, to return to the BOOTROM through the
+ BOOT_DEVICE_BOOTROM (or fall-through to the next boot device in the
+ boot device list, if not implemented for a given board)
+
+config TPL_DRIVERS_MISC_SUPPORT
+ bool "Support misc drivers in TPL"
+ help
+ Enable miscellaneous drivers in TPL. These drivers perform various
+ tasks that don't fall nicely into other categories, Enable this
+ option to build the drivers in drivers/misc as part of an TPL
+ build, for those that support building in TPL (not all drivers do).
+
+config TPL_ENV_SUPPORT
+ bool "Support an environment"
+ help
+ Enable environment support in TPL. See SPL_ENV_SUPPORT for details.
+
+config TPL_GPIO_SUPPORT
+ bool "Support GPIO in TPL"
+ help
+ Enable support for GPIOs (General-purpose Input/Output) in TPL.
+ GPIOs allow U-Boot to read the state of an input line (high or
+ low) and set the state of an output line. This can be used to
+ drive LEDs, control power to various system parts and read user
+ input. GPIOs can be useful in TPL to enable a 'sign-of-life' LED,
+ for example. Enable this option to build the drivers in
+ drivers/gpio as part of an TPL build.
+
+config TPL_I2C_SUPPORT
+ bool "Support I2C"
+ help
+ Enable support for the I2C bus in TPL. See SPL_I2C_SUPPORT for
+ details.
+
+config TPL_LIBCOMMON_SUPPORT
+ bool "Support common libraries"
+ help
+ Enable support for common U-Boot libraries within TPL. See
+ SPL_LIBCOMMON_SUPPORT for details.
+
+config TPL_LIBGENERIC_SUPPORT
+ bool "Support generic libraries"
+ help
+ Enable support for generic U-Boot libraries within TPL. See
+ SPL_LIBGENERIC_SUPPORT for details.
+
+config TPL_MPC8XXX_INIT_DDR_SUPPORT
+ bool "Support MPC8XXX DDR init"
+ help
+ Enable support for DDR-SDRAM on the MPC8XXX family within TPL. See
+ SPL_MPC8XXX_INIT_DDR_SUPPORT for details.
+
+config TPL_MMC_SUPPORT
+ bool "Support MMC"
+ depends on MMC
+ help
+ Enable support for MMC within TPL. See SPL_MMC_SUPPORT for details.
+
+config TPL_NAND_SUPPORT
+ bool "Support NAND flash"
+ help
+ Enable support for NAND in TPL. See SPL_NAND_SUPPORT for details.
+
+config TPL_PCI
+ bool "Support PCI drivers"
+ help
+ Enable support for PCI in TPL. For platforms that need PCI to boot,
+ or must perform some init using PCI in SPL, this provides the
+ necessary driver support. This enables the drivers in drivers/pci
+ as part of a TPL build.
+
+config TPL_PCH_SUPPORT
+ bool "Support PCH drivers"
+ help
+ Enable support for PCH (Platform Controller Hub) devices in TPL.
+ These are used to set up GPIOs and the SPI peripheral early in
+ boot. This enables the drivers in drivers/pch as part of a TPL
+ build.
+
+config TPL_RAM_SUPPORT
+ bool "Support booting from RAM"
+ help
+ Enable booting of an image in RAM. The image can be preloaded or
+ it can be loaded by TPL directly into RAM (e.g. using USB).
+
+config TPL_RAM_DEVICE
+ bool "Support booting from preloaded image in RAM"
+ depends on TPL_RAM_SUPPORT
+ help
+ Enable booting of an image already loaded in RAM. The image has to
+ be already in memory when TPL takes over, e.g. loaded by the boot
+ ROM.
+
+config TPL_RTC_SUPPORT
+ bool "Support RTC drivers"
+ help
+ Enable RTC (Real-time Clock) support in TPL. This includes support
+ for reading and setting the time. Some RTC devices also have some
+ non-volatile (battery-backed) memory which is accessible if
+ needed. This enables the drivers in drivers/rtc as part of an TPL
+ build.
+
+config TPL_SERIAL_SUPPORT
+ bool "Support serial"
+ select TPL_PRINTF
+ select TPL_STRTO
+ help
+ Enable support for serial in TPL. See SPL_SERIAL_SUPPORT for
+ details.
+
+config TPL_SPI_FLASH_SUPPORT
+ bool "Support SPI flash drivers"
+ help
+ Enable support for using SPI flash in TPL. See SPL_SPI_FLASH_SUPPORT
+ for details.
+
+config TPL_SPI_FLASH_TINY
+ bool "Enable low footprint TPL SPI Flash support"
+ depends on TPL_SPI_FLASH_SUPPORT && !SPI_FLASH_BAR
+ default y if SPI_FLASH
+ help
+ Enable lightweight TPL SPI Flash support that supports just reading
+ data/images from flash. No support to write/erase flash. Enable
+ this if you have TPL size limitations and don't need full-fledged
+ SPI flash support.
+
+config TPL_SPI_LOAD
+ bool "Support loading from SPI flash"
+ depends on TPL_SPI_FLASH_SUPPORT
+ help
+ Enable support for loading next stage, U-Boot or otherwise, from
+ SPI NOR in U-Boot TPL.
+
+config TPL_SPI_SUPPORT
+ bool "Support SPI drivers"
+ help
+ Enable support for using SPI in TPL. See SPL_SPI_SUPPORT for
+ details.
+
+config TPL_DM_SPI
+ bool "Support SPI DM drivers in TPL"
+ help
+ Enable support for SPI DM drivers in TPL.
+
+config TPL_DM_SPI_FLASH
+ bool "Support SPI DM FLASH drivers in TPL"
+ help
+ Enable support for SPI DM flash drivers in TPL.
+
+config TPL_YMODEM_SUPPORT
+ bool "Support loading using Ymodem"
+ depends on TPL_SERIAL_SUPPORT
+ help
+ While loading from serial is slow it can be a useful backup when
+ there is no other option. The Ymodem protocol provides a reliable
+ means of transmitting U-Boot over a serial line for using in TPL,
+ with a checksum to ensure correctness.
+
+endif # TPL
+
+config SPL_AT91_MCK_BYPASS
+ bool "Use external clock signal as a source of main clock for AT91 platforms"
+ depends on ARCH_AT91
+ default n
+ help
+ Use external 8 to 24 Mhz clock signal as source of main clock instead
+ of an external crystal oscillator.
+ This option disables the internal driving on the XOUT pin.
+ The external source has to provide a stable clock on the XIN pin.
+ If this option is disabled, the SoC expects a crystal oscillator
+ that needs driving on both XIN and XOUT lines.
+
+endif # SPL
+endmenu
diff --git a/roms/u-boot/common/spl/Makefile b/roms/u-boot/common/spl/Makefile
new file mode 100644
index 000000000..c576a7812
--- /dev/null
+++ b/roms/u-boot/common/spl/Makefile
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2012
+# Texas Instruments Incorporated - http://www.ti.com/
+# Aneesh V <aneesh@ti.com>
+# Based on common/Makefile.
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_$(SPL_TPL_)FRAMEWORK) += spl.o
+obj-$(CONFIG_$(SPL_TPL_)BOOTROM_SUPPORT) += spl_bootrom.o
+obj-$(CONFIG_$(SPL_TPL_)LOAD_FIT) += spl_fit.o
+obj-$(CONFIG_$(SPL_TPL_)LEGACY_IMAGE_SUPPORT) += spl_legacy.o
+obj-$(CONFIG_$(SPL_TPL_)NOR_SUPPORT) += spl_nor.o
+obj-$(CONFIG_$(SPL_TPL_)XIP_SUPPORT) += spl_xip.o
+obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += spl_ymodem.o
+ifndef CONFIG_SPL_UBI
+obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += spl_nand.o
+obj-$(CONFIG_$(SPL_TPL_)ONENAND_SUPPORT) += spl_onenand.o
+endif
+obj-$(CONFIG_$(SPL_TPL_)UBI) += spl_ubi.o
+obj-$(CONFIG_$(SPL_TPL_)NET_SUPPORT) += spl_net.o
+obj-$(CONFIG_$(SPL_TPL_)MMC_SUPPORT) += spl_mmc.o
+obj-$(CONFIG_$(SPL_TPL_)ATF) += spl_atf.o
+obj-$(CONFIG_$(SPL_TPL_)OPTEE) += spl_optee.o
+obj-$(CONFIG_$(SPL_TPL_)OPENSBI) += spl_opensbi.o
+obj-$(CONFIG_$(SPL_TPL_)USB_STORAGE) += spl_usb.o
+obj-$(CONFIG_$(SPL_TPL_)FS_FAT) += spl_fat.o
+obj-$(CONFIG_$(SPL_TPL_)FS_EXT4) += spl_ext.o
+obj-$(CONFIG_$(SPL_TPL_)SATA_SUPPORT) += spl_sata.o
+obj-$(CONFIG_$(SPL_TPL_)DFU) += spl_dfu.o
+obj-$(CONFIG_$(SPL_TPL_)SPI_LOAD) += spl_spi.o
+obj-$(CONFIG_$(SPL_TPL_)RAM_SUPPORT) += spl_ram.o
+obj-$(CONFIG_$(SPL_TPL_)USB_SDP_SUPPORT) += spl_sdp.o
+endif
diff --git a/roms/u-boot/common/spl/spl.c b/roms/u-boot/common/spl/spl.c
new file mode 100644
index 000000000..a0a608fd7
--- /dev/null
+++ b/roms/u-boot/common/spl/spl.c
@@ -0,0 +1,895 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *
+ * Aneesh V <aneesh@ti.com>
+ */
+
+#include <common.h>
+#include <bloblist.h>
+#include <binman_sym.h>
+#include <bootstage.h>
+#include <dm.h>
+#include <handoff.h>
+#include <hang.h>
+#include <init.h>
+#include <irq_func.h>
+#include <log.h>
+#include <mapmem.h>
+#include <serial.h>
+#include <spl.h>
+#include <asm/global_data.h>
+#include <asm/u-boot.h>
+#include <nand.h>
+#include <fat.h>
+#include <u-boot/crc.h>
+#include <version.h>
+#include <image.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <dm/root.h>
+#include <linux/compiler.h>
+#include <fdt_support.h>
+#include <bootcount.h>
+#include <wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SYS_UBOOT_START
+#define CONFIG_SYS_UBOOT_START CONFIG_SYS_TEXT_BASE
+#endif
+#ifndef CONFIG_SYS_MONITOR_LEN
+/* Unknown U-Boot size, let's assume it will not be more than 200 KB */
+#define CONFIG_SYS_MONITOR_LEN (200 * 1024)
+#endif
+
+u32 *boot_params_ptr = NULL;
+
+/* See spl.h for information about this */
+binman_sym_declare(ulong, u_boot_any, image_pos);
+binman_sym_declare(ulong, u_boot_any, size);
+
+#ifdef CONFIG_TPL
+binman_sym_declare(ulong, spl, image_pos);
+binman_sym_declare(ulong, spl, size);
+#endif
+
+/* Define board data structure */
+static struct bd_info bdata __attribute__ ((section(".data")));
+
+/*
+ * Board-specific Platform code can reimplement show_boot_progress () if needed
+ */
+__weak void show_boot_progress(int val) {}
+
+#if defined(CONFIG_SPL_OS_BOOT) || CONFIG_IS_ENABLED(HANDOFF) || \
+ defined(CONFIG_SPL_ATF)
+/* weak, default platform-specific function to initialize dram banks */
+__weak int dram_init_banksize(void)
+{
+ return 0;
+}
+#endif
+
+/*
+ * Default function to determine if u-boot or the OS should
+ * be started. This implementation always returns 1.
+ *
+ * Please implement your own board specific funcion to do this.
+ *
+ * RETURN
+ * 0 to not start u-boot
+ * positive if u-boot should start
+ */
+#ifdef CONFIG_SPL_OS_BOOT
+__weak int spl_start_uboot(void)
+{
+ puts(SPL_TPL_PROMPT
+ "Please implement spl_start_uboot() for your board\n");
+ puts(SPL_TPL_PROMPT "Direct Linux boot not active!\n");
+ return 1;
+}
+
+/*
+ * Weak default function for arch specific zImage check. Return zero
+ * and fill start and end address if image is recognized.
+ */
+int __weak bootz_setup(ulong image, ulong *start, ulong *end)
+{
+ return 1;
+}
+#endif
+
+/* Weak default function for arch/board-specific fixups to the spl_image_info */
+void __weak spl_perform_fixups(struct spl_image_info *spl_image)
+{
+}
+
+void spl_fixup_fdt(void *fdt_blob)
+{
+#if defined(CONFIG_SPL_OF_LIBFDT)
+ int err;
+
+ if (!fdt_blob)
+ return;
+
+ err = fdt_check_header(fdt_blob);
+ if (err < 0) {
+ printf("fdt_root: %s\n", fdt_strerror(err));
+ return;
+ }
+
+ /* fixup the memory dt node */
+ err = fdt_shrink_to_minimum(fdt_blob, 0);
+ if (err == 0) {
+ printf(SPL_TPL_PROMPT "fdt_shrink_to_minimum err - %d\n", err);
+ return;
+ }
+
+ err = arch_fixup_fdt(fdt_blob);
+ if (err) {
+ printf(SPL_TPL_PROMPT "arch_fixup_fdt err - %d\n", err);
+ return;
+ }
+#endif
+}
+
+ulong spl_get_image_pos(void)
+{
+ return spl_phase() == PHASE_TPL ?
+ binman_sym(ulong, spl, image_pos) :
+ binman_sym(ulong, u_boot_any, image_pos);
+}
+
+ulong spl_get_image_size(void)
+{
+ return spl_phase() == PHASE_TPL ?
+ binman_sym(ulong, spl, size) :
+ binman_sym(ulong, u_boot_any, size);
+}
+
+ulong spl_get_image_text_base(void)
+{
+ return spl_phase() == PHASE_TPL ? CONFIG_SPL_TEXT_BASE :
+ CONFIG_SYS_TEXT_BASE;
+}
+
+/*
+ * Weak default function for board specific cleanup/preparation before
+ * Linux boot. Some boards/platforms might not need it, so just provide
+ * an empty stub here.
+ */
+__weak void spl_board_prepare_for_linux(void)
+{
+ /* Nothing to do! */
+}
+
+__weak void spl_board_prepare_for_boot(void)
+{
+ /* Nothing to do! */
+}
+
+__weak struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+{
+ return map_sysmem(CONFIG_SYS_TEXT_BASE + offset, 0);
+}
+
+void spl_set_header_raw_uboot(struct spl_image_info *spl_image)
+{
+ ulong u_boot_pos = binman_sym(ulong, u_boot_any, image_pos);
+
+ spl_image->size = CONFIG_SYS_MONITOR_LEN;
+
+ /*
+ * Binman error cases: address of the end of the previous region or the
+ * start of the image's entry area (usually 0) if there is no previous
+ * region.
+ */
+ if (u_boot_pos && u_boot_pos != BINMAN_SYM_MISSING) {
+ /* Binman does not support separated entry addresses */
+ spl_image->entry_point = u_boot_pos;
+ spl_image->load_addr = u_boot_pos;
+ } else {
+ spl_image->entry_point = CONFIG_SYS_UBOOT_START;
+ spl_image->load_addr = CONFIG_SYS_TEXT_BASE;
+ }
+ spl_image->os = IH_OS_U_BOOT;
+ spl_image->name = "U-Boot";
+}
+
+#ifdef CONFIG_SPL_LOAD_FIT_FULL
+/* Parse and load full fitImage in SPL */
+static int spl_load_fit_image(struct spl_image_info *spl_image,
+ const struct image_header *header)
+{
+ bootm_headers_t images;
+ const char *fit_uname_config = NULL;
+ uintptr_t fdt_hack;
+ const char *uname;
+ ulong fw_data = 0, dt_data = 0, img_data = 0;
+ ulong fw_len = 0, dt_len = 0, img_len = 0;
+ int idx, conf_noffset;
+ int ret;
+
+#ifdef CONFIG_SPL_FIT_SIGNATURE
+ images.verify = 1;
+#endif
+ ret = fit_image_load(&images, (ulong)header,
+ NULL, &fit_uname_config,
+ IH_ARCH_DEFAULT, IH_TYPE_STANDALONE, -1,
+ FIT_LOAD_OPTIONAL, &fw_data, &fw_len);
+ if (ret >= 0) {
+ printf("DEPRECATED: 'standalone = ' property.");
+ printf("Please use either 'firmware =' or 'kernel ='\n");
+ } else {
+ ret = fit_image_load(&images, (ulong)header, NULL,
+ &fit_uname_config, IH_ARCH_DEFAULT,
+ IH_TYPE_FIRMWARE, -1, FIT_LOAD_OPTIONAL,
+ &fw_data, &fw_len);
+ }
+
+ if (ret < 0) {
+ ret = fit_image_load(&images, (ulong)header, NULL,
+ &fit_uname_config, IH_ARCH_DEFAULT,
+ IH_TYPE_KERNEL, -1, FIT_LOAD_OPTIONAL,
+ &fw_data, &fw_len);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ spl_image->size = fw_len;
+ spl_image->entry_point = fw_data;
+ spl_image->load_addr = fw_data;
+ if (fit_image_get_os(header, ret, &spl_image->os))
+ spl_image->os = IH_OS_INVALID;
+ spl_image->name = genimg_get_os_name(spl_image->os);
+
+ debug(SPL_TPL_PROMPT "payload image: %32s load addr: 0x%lx size: %d\n",
+ spl_image->name, spl_image->load_addr, spl_image->size);
+
+#ifdef CONFIG_SPL_FIT_SIGNATURE
+ images.verify = 1;
+#endif
+ ret = fit_image_load(&images, (ulong)header, NULL, &fit_uname_config,
+ IH_ARCH_DEFAULT, IH_TYPE_FLATDT, -1,
+ FIT_LOAD_OPTIONAL, &dt_data, &dt_len);
+ if (ret >= 0) {
+ spl_image->fdt_addr = (void *)dt_data;
+
+ if (spl_image->os == IH_OS_U_BOOT) {
+ /* HACK: U-boot expects FDT at a specific address */
+ fdt_hack = spl_image->load_addr + spl_image->size;
+ fdt_hack = (fdt_hack + 3) & ~3;
+ debug("Relocating FDT to %p\n", spl_image->fdt_addr);
+ memcpy((void *)fdt_hack, spl_image->fdt_addr, dt_len);
+ }
+ }
+
+ conf_noffset = fit_conf_get_node((const void *)header,
+ fit_uname_config);
+ if (conf_noffset <= 0)
+ return 0;
+
+ for (idx = 0;
+ uname = fdt_stringlist_get((const void *)header, conf_noffset,
+ FIT_LOADABLE_PROP, idx,
+ NULL), uname;
+ idx++)
+ {
+#ifdef CONFIG_SPL_FIT_SIGNATURE
+ images.verify = 1;
+#endif
+ ret = fit_image_load(&images, (ulong)header,
+ &uname, &fit_uname_config,
+ IH_ARCH_DEFAULT, IH_TYPE_LOADABLE, -1,
+ FIT_LOAD_OPTIONAL_NON_ZERO,
+ &img_data, &img_len);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+__weak int spl_parse_legacy_header(struct spl_image_info *spl_image,
+ const struct image_header *header)
+{
+ /* LEGACY image not supported */
+ debug("Legacy boot image support not enabled, proceeding to other boot methods\n");
+ return -EINVAL;
+}
+
+int spl_parse_image_header(struct spl_image_info *spl_image,
+ const struct image_header *header)
+{
+#ifdef CONFIG_SPL_LOAD_FIT_FULL
+ int ret = spl_load_fit_image(spl_image, header);
+
+ if (!ret)
+ return ret;
+#endif
+ if (image_get_magic(header) == IH_MAGIC) {
+ int ret;
+
+ ret = spl_parse_legacy_header(spl_image, header);
+ if (ret)
+ return ret;
+ } else {
+#ifdef CONFIG_SPL_PANIC_ON_RAW_IMAGE
+ /*
+ * CONFIG_SPL_PANIC_ON_RAW_IMAGE is defined when the
+ * code which loads images in SPL cannot guarantee that
+ * absolutely all read errors will be reported.
+ * An example is the LPC32XX MLC NAND driver, which
+ * will consider that a completely unreadable NAND block
+ * is bad, and thus should be skipped silently.
+ */
+ panic("** no mkimage signature but raw image not supported");
+#endif
+
+#ifdef CONFIG_SPL_OS_BOOT
+ ulong start, end;
+
+ if (!bootz_setup((ulong)header, &start, &end)) {
+ spl_image->name = "Linux";
+ spl_image->os = IH_OS_LINUX;
+ spl_image->load_addr = CONFIG_SYS_LOAD_ADDR;
+ spl_image->entry_point = CONFIG_SYS_LOAD_ADDR;
+ spl_image->size = end - start;
+ debug(SPL_TPL_PROMPT
+ "payload zImage, load addr: 0x%lx size: %d\n",
+ spl_image->load_addr, spl_image->size);
+ return 0;
+ }
+#endif
+
+#ifdef CONFIG_SPL_RAW_IMAGE_SUPPORT
+ /* Signature not found - assume u-boot.bin */
+ debug("mkimage signature not found - ih_magic = %x\n",
+ header->ih_magic);
+ spl_set_header_raw_uboot(spl_image);
+#else
+ /* RAW image not supported, proceed to other boot methods. */
+ debug("Raw boot image support not enabled, proceeding to other boot methods\n");
+ return -EINVAL;
+#endif
+ }
+
+ return 0;
+}
+
+__weak void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
+{
+ typedef void __noreturn (*image_entry_noargs_t)(void);
+
+ image_entry_noargs_t image_entry =
+ (image_entry_noargs_t)spl_image->entry_point;
+
+ debug("image entry point: 0x%lx\n", spl_image->entry_point);
+ image_entry();
+}
+
+#if CONFIG_IS_ENABLED(HANDOFF)
+/**
+ * Set up the SPL hand-off information
+ *
+ * This is initially empty (zero) but can be written by
+ */
+static int setup_spl_handoff(void)
+{
+ struct spl_handoff *ho;
+
+ ho = bloblist_ensure(BLOBLISTT_SPL_HANDOFF, sizeof(struct spl_handoff));
+ if (!ho)
+ return -ENOENT;
+
+ return 0;
+}
+
+__weak int handoff_arch_save(struct spl_handoff *ho)
+{
+ return 0;
+}
+
+static int write_spl_handoff(void)
+{
+ struct spl_handoff *ho;
+ int ret;
+
+ ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(struct spl_handoff));
+ if (!ho)
+ return -ENOENT;
+ handoff_save_dram(ho);
+ ret = handoff_arch_save(ho);
+ if (ret)
+ return ret;
+ debug(SPL_TPL_PROMPT "Wrote SPL handoff\n");
+
+ return 0;
+}
+#else
+static inline int setup_spl_handoff(void) { return 0; }
+static inline int write_spl_handoff(void) { return 0; }
+
+#endif /* HANDOFF */
+
+/**
+ * get_bootstage_id() - Get the bootstage ID to emit
+ *
+ * @start: true if this is for starting SPL, false for ending it
+ * @return bootstage ID to use
+ */
+static enum bootstage_id get_bootstage_id(bool start)
+{
+ enum u_boot_phase phase = spl_phase();
+
+ if (IS_ENABLED(CONFIG_TPL_BUILD) && phase == PHASE_TPL)
+ return start ? BOOTSTAGE_ID_START_TPL : BOOTSTAGE_ID_END_TPL;
+ else
+ return start ? BOOTSTAGE_ID_START_SPL : BOOTSTAGE_ID_END_SPL;
+}
+
+static int spl_common_init(bool setup_malloc)
+{
+ int ret;
+
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ if (setup_malloc) {
+#ifdef CONFIG_MALLOC_F_ADDR
+ gd->malloc_base = CONFIG_MALLOC_F_ADDR;
+#endif
+ gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN);
+ gd->malloc_ptr = 0;
+ }
+#endif
+ ret = bootstage_init(u_boot_first_phase());
+ if (ret) {
+ debug("%s: Failed to set up bootstage: ret=%d\n", __func__,
+ ret);
+ return ret;
+ }
+#ifdef CONFIG_BOOTSTAGE_STASH
+ if (!u_boot_first_phase()) {
+ const void *stash = map_sysmem(CONFIG_BOOTSTAGE_STASH_ADDR,
+ CONFIG_BOOTSTAGE_STASH_SIZE);
+
+ ret = bootstage_unstash(stash, CONFIG_BOOTSTAGE_STASH_SIZE);
+ if (ret)
+ debug("%s: Failed to unstash bootstage: ret=%d\n",
+ __func__, ret);
+ }
+#endif /* CONFIG_BOOTSTAGE_STASH */
+ bootstage_mark_name(get_bootstage_id(true),
+ spl_phase_name(spl_phase()));
+#if CONFIG_IS_ENABLED(LOG)
+ ret = log_init();
+ if (ret) {
+ debug("%s: Failed to set up logging\n", __func__);
+ return ret;
+ }
+#endif
+ if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ ret = fdtdec_setup();
+ if (ret) {
+ debug("fdtdec_setup() returned error %d\n", ret);
+ return ret;
+ }
+ }
+ if (CONFIG_IS_ENABLED(DM)) {
+ bootstage_start(BOOTSTAGE_ID_ACCUM_DM_SPL,
+ spl_phase() == PHASE_TPL ? "dm tpl" : "dm_spl");
+ /* With CONFIG_SPL_OF_PLATDATA, bring in all devices */
+ ret = dm_init_and_scan(!CONFIG_IS_ENABLED(OF_PLATDATA));
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_SPL);
+ if (ret) {
+ debug("dm_init_and_scan() returned error %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void spl_set_bd(void)
+{
+ /*
+ * NOTE: On some platforms (e.g. x86) bdata may be in flash and not
+ * writeable.
+ */
+ if (!gd->bd)
+ gd->bd = &bdata;
+}
+
+int spl_early_init(void)
+{
+ int ret;
+
+ debug("%s\n", __func__);
+
+ ret = spl_common_init(true);
+ if (ret)
+ return ret;
+ gd->flags |= GD_FLG_SPL_EARLY_INIT;
+
+ return 0;
+}
+
+int spl_init(void)
+{
+ int ret;
+ bool setup_malloc = !(IS_ENABLED(CONFIG_SPL_STACK_R) &&
+ IS_ENABLED(CONFIG_SPL_SYS_MALLOC_SIMPLE));
+
+ debug("%s\n", __func__);
+
+ if (!(gd->flags & GD_FLG_SPL_EARLY_INIT)) {
+ ret = spl_common_init(setup_malloc);
+ if (ret)
+ return ret;
+ }
+ gd->flags |= GD_FLG_SPL_INIT;
+
+ return 0;
+}
+
+#ifndef BOOT_DEVICE_NONE
+#define BOOT_DEVICE_NONE 0xdeadbeef
+#endif
+
+__weak void board_boot_order(u32 *spl_boot_list)
+{
+ spl_boot_list[0] = spl_boot_device();
+}
+
+static struct spl_image_loader *spl_ll_find_loader(uint boot_device)
+{
+ struct spl_image_loader *drv =
+ ll_entry_start(struct spl_image_loader, spl_image_loader);
+ const int n_ents =
+ ll_entry_count(struct spl_image_loader, spl_image_loader);
+ struct spl_image_loader *entry;
+
+ for (entry = drv; entry != drv + n_ents; entry++) {
+ if (boot_device == entry->boot_device)
+ return entry;
+ }
+
+ /* Not found */
+ return NULL;
+}
+
+static int spl_load_image(struct spl_image_info *spl_image,
+ struct spl_image_loader *loader)
+{
+ int ret;
+ struct spl_boot_device bootdev;
+
+ bootdev.boot_device = loader->boot_device;
+ bootdev.boot_device_name = NULL;
+
+ ret = loader->load_image(spl_image, &bootdev);
+#ifdef CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK
+ if (!ret && spl_image->dcrc_length) {
+ /* check data crc */
+ ulong dcrc = crc32_wd(0, (unsigned char *)spl_image->dcrc_data,
+ spl_image->dcrc_length, CHUNKSZ_CRC32);
+ if (dcrc != spl_image->dcrc) {
+ puts("SPL: Image data CRC check failed!\n");
+ ret = -EINVAL;
+ }
+ }
+#endif
+ return ret;
+}
+
+/**
+ * boot_from_devices() - Try loading a booting U-Boot from a list of devices
+ *
+ * @spl_image: Place to put the image details if successful
+ * @spl_boot_list: List of boot devices to try
+ * @count: Number of elements in spl_boot_list
+ * @return 0 if OK, -ve on error
+ */
+static int boot_from_devices(struct spl_image_info *spl_image,
+ u32 spl_boot_list[], int count)
+{
+ int i;
+
+ for (i = 0; i < count && spl_boot_list[i] != BOOT_DEVICE_NONE; i++) {
+ struct spl_image_loader *loader;
+
+ loader = spl_ll_find_loader(spl_boot_list[i]);
+#if defined(CONFIG_SPL_SERIAL_SUPPORT) \
+ && defined(CONFIG_SPL_LIBCOMMON_SUPPORT) \
+ && !defined(CONFIG_SILENT_CONSOLE)
+ if (loader)
+ printf("Trying to boot from %s\n", loader->name);
+ else
+ puts(SPL_TPL_PROMPT "Unsupported Boot Device!\n");
+#endif
+ if (loader && !spl_load_image(spl_image, loader)) {
+ spl_image->boot_device = spl_boot_list[i];
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+#if defined(CONFIG_SPL_FRAMEWORK_BOARD_INIT_F)
+void board_init_f(ulong dummy)
+{
+ if (CONFIG_IS_ENABLED(OF_CONTROL)) {
+ int ret;
+
+ ret = spl_early_init();
+ if (ret) {
+ debug("spl_early_init() failed: %d\n", ret);
+ hang();
+ }
+ }
+
+ preloader_console_init();
+}
+#endif
+
+void board_init_r(gd_t *dummy1, ulong dummy2)
+{
+ u32 spl_boot_list[] = {
+ BOOT_DEVICE_NONE,
+ BOOT_DEVICE_NONE,
+ BOOT_DEVICE_NONE,
+ BOOT_DEVICE_NONE,
+ BOOT_DEVICE_NONE,
+ };
+ struct spl_image_info spl_image;
+ int ret;
+
+ debug(">>" SPL_TPL_PROMPT "board_init_r()\n");
+
+ spl_set_bd();
+
+#if defined(CONFIG_SYS_SPL_MALLOC_START)
+ mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
+ CONFIG_SYS_SPL_MALLOC_SIZE);
+ gd->flags |= GD_FLG_FULL_MALLOC_INIT;
+#endif
+ if (!(gd->flags & GD_FLG_SPL_INIT)) {
+ if (spl_init())
+ hang();
+ }
+#if !defined(CONFIG_PPC) && !defined(CONFIG_ARCH_MX6)
+ /*
+ * timer_init() does not exist on PPC systems. The timer is initialized
+ * and enabled (decrementer) in interrupt_init() here.
+ */
+ timer_init();
+#endif
+ if (CONFIG_IS_ENABLED(BLOBLIST)) {
+ ret = bloblist_init();
+ if (ret) {
+ debug("%s: Failed to set up bloblist: ret=%d\n",
+ __func__, ret);
+ puts(SPL_TPL_PROMPT "Cannot set up bloblist\n");
+ hang();
+ }
+ }
+ if (CONFIG_IS_ENABLED(HANDOFF)) {
+ int ret;
+
+ ret = setup_spl_handoff();
+ if (ret) {
+ puts(SPL_TPL_PROMPT "Cannot set up SPL handoff\n");
+ hang();
+ }
+ }
+
+#if CONFIG_IS_ENABLED(BOARD_INIT)
+ spl_board_init();
+#endif
+
+#if defined(CONFIG_SPL_WATCHDOG_SUPPORT) && CONFIG_IS_ENABLED(WDT)
+ initr_watchdog();
+#endif
+
+ if (IS_ENABLED(CONFIG_SPL_OS_BOOT) || CONFIG_IS_ENABLED(HANDOFF) ||
+ IS_ENABLED(CONFIG_SPL_ATF))
+ dram_init_banksize();
+
+ bootcount_inc();
+
+ memset(&spl_image, '\0', sizeof(spl_image));
+#ifdef CONFIG_SYS_SPL_ARGS_ADDR
+ spl_image.arg = (void *)CONFIG_SYS_SPL_ARGS_ADDR;
+#endif
+ spl_image.boot_device = BOOT_DEVICE_NONE;
+ board_boot_order(spl_boot_list);
+
+ if (boot_from_devices(&spl_image, spl_boot_list,
+ ARRAY_SIZE(spl_boot_list))) {
+ puts(SPL_TPL_PROMPT "failed to boot from all boot devices\n");
+ hang();
+ }
+
+ spl_perform_fixups(&spl_image);
+ if (CONFIG_IS_ENABLED(HANDOFF)) {
+ ret = write_spl_handoff();
+ if (ret)
+ printf(SPL_TPL_PROMPT
+ "SPL hand-off write failed (err=%d)\n", ret);
+ }
+ if (CONFIG_IS_ENABLED(BLOBLIST)) {
+ ret = bloblist_finish();
+ if (ret)
+ printf("Warning: Failed to finish bloblist (ret=%d)\n",
+ ret);
+ }
+
+#ifdef CONFIG_CPU_V7M
+ spl_image.entry_point |= 0x1;
+#endif
+ switch (spl_image.os) {
+ case IH_OS_U_BOOT:
+ debug("Jumping to %s...\n", spl_phase_name(spl_next_phase()));
+ break;
+#if CONFIG_IS_ENABLED(ATF)
+ case IH_OS_ARM_TRUSTED_FIRMWARE:
+ debug("Jumping to U-Boot via ARM Trusted Firmware\n");
+ spl_fixup_fdt(spl_image.fdt_addr);
+ spl_invoke_atf(&spl_image);
+ break;
+#endif
+#if CONFIG_IS_ENABLED(OPTEE)
+ case IH_OS_TEE:
+ debug("Jumping to U-Boot via OP-TEE\n");
+ spl_optee_entry(NULL, NULL, spl_image.fdt_addr,
+ (void *)spl_image.entry_point);
+ break;
+#endif
+#if CONFIG_IS_ENABLED(OPENSBI)
+ case IH_OS_OPENSBI:
+ debug("Jumping to U-Boot via RISC-V OpenSBI\n");
+ spl_invoke_opensbi(&spl_image);
+ break;
+#endif
+#ifdef CONFIG_SPL_OS_BOOT
+ case IH_OS_LINUX:
+ debug("Jumping to Linux\n");
+#if defined(CONFIG_SYS_SPL_ARGS_ADDR)
+ spl_fixup_fdt((void *)CONFIG_SYS_SPL_ARGS_ADDR);
+#endif
+ spl_board_prepare_for_linux();
+ jump_to_image_linux(&spl_image);
+#endif
+ default:
+ debug("Unsupported OS image.. Jumping nevertheless..\n");
+ }
+#if CONFIG_VAL(SYS_MALLOC_F_LEN) && !defined(CONFIG_SYS_SPL_MALLOC_SIZE)
+ debug("SPL malloc() used 0x%lx bytes (%ld KB)\n", gd->malloc_ptr,
+ gd->malloc_ptr / 1024);
+#endif
+ bootstage_mark_name(get_bootstage_id(false), "end phase");
+#ifdef CONFIG_BOOTSTAGE_STASH
+ ret = bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
+ CONFIG_BOOTSTAGE_STASH_SIZE);
+ if (ret)
+ debug("Failed to stash bootstage: err=%d\n", ret);
+#endif
+
+ spl_board_prepare_for_boot();
+ jump_to_image_no_args(&spl_image);
+}
+
+/*
+ * This requires UART clocks to be enabled. In order for this to work the
+ * caller must ensure that the gd pointer is valid.
+ */
+void preloader_console_init(void)
+{
+#ifdef CONFIG_SPL_SERIAL_SUPPORT
+ gd->baudrate = CONFIG_BAUDRATE;
+
+ serial_init(); /* serial communications setup */
+
+ gd->have_console = 1;
+
+#if CONFIG_IS_ENABLED(BANNER_PRINT)
+ puts("\nU-Boot " SPL_TPL_NAME " " PLAIN_VERSION " (" U_BOOT_DATE " - "
+ U_BOOT_TIME " " U_BOOT_TZ ")\n");
+#endif
+#ifdef CONFIG_SPL_DISPLAY_PRINT
+ spl_display_print();
+#endif
+#endif
+}
+
+/**
+ * This function is called before the stack is changed from initial stack to
+ * relocated stack. It tries to dump the stack size used
+ */
+__weak void spl_relocate_stack_check(void)
+{
+#if CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE)
+ ulong init_sp = gd->start_addr_sp;
+ ulong stack_bottom = init_sp - CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK);
+ u8 *ptr = (u8 *)stack_bottom;
+ ulong i;
+
+ for (i = 0; i < CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK); i++) {
+ if (*ptr != CONFIG_VAL(SYS_STACK_F_CHECK_BYTE))
+ break;
+ ptr++;
+ }
+ printf("SPL initial stack usage: %lu bytes\n",
+ CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK) - i);
+#endif
+}
+
+/**
+ * spl_relocate_stack_gd() - Relocate stack ready for board_init_r() execution
+ *
+ * Sometimes board_init_f() runs with a stack in SRAM but we want to use SDRAM
+ * for the main board_init_r() execution. This is typically because we need
+ * more stack space for things like the MMC sub-system.
+ *
+ * This function calculates the stack position, copies the global_data into
+ * place, sets the new gd (except for ARM, for which setting GD within a C
+ * function may not always work) and returns the new stack position. The
+ * caller is responsible for setting up the sp register and, in the case
+ * of ARM, setting up gd.
+ *
+ * All of this is done using the same layout and alignments as done in
+ * board_init_f_init_reserve() / board_init_f_alloc_reserve().
+ *
+ * @return new stack location, or 0 to use the same stack
+ */
+ulong spl_relocate_stack_gd(void)
+{
+#ifdef CONFIG_SPL_STACK_R
+ gd_t *new_gd;
+ ulong ptr = CONFIG_SPL_STACK_R_ADDR;
+
+ if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
+ spl_relocate_stack_check();
+
+#if defined(CONFIG_SPL_SYS_MALLOC_SIMPLE) && CONFIG_VAL(SYS_MALLOC_F_LEN)
+ if (CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN) {
+ debug("SPL malloc() before relocation used 0x%lx bytes (%ld KB)\n",
+ gd->malloc_ptr, gd->malloc_ptr / 1024);
+ ptr -= CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN;
+ gd->malloc_base = ptr;
+ gd->malloc_limit = CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN;
+ gd->malloc_ptr = 0;
+ }
+#endif
+ /* Get stack position: use 8-byte alignment for ABI compliance */
+ ptr = CONFIG_SPL_STACK_R_ADDR - roundup(sizeof(gd_t),16);
+ new_gd = (gd_t *)ptr;
+ memcpy(new_gd, (void *)gd, sizeof(gd_t));
+#if CONFIG_IS_ENABLED(DM)
+ dm_fixup_for_gd_move(new_gd);
+#endif
+#if !defined(CONFIG_ARM) && !defined(CONFIG_RISCV)
+ gd = new_gd;
+#endif
+ return ptr;
+#else
+ return 0;
+#endif
+}
+
+#if defined(CONFIG_BOOTCOUNT_LIMIT) && \
+ ((!defined(CONFIG_TPL_BUILD) && !defined(CONFIG_SPL_BOOTCOUNT_LIMIT)) || \
+ (defined(CONFIG_TPL_BUILD) && !defined(CONFIG_TPL_BOOTCOUNT_LIMIT)))
+void bootcount_store(ulong a)
+{
+}
+
+ulong bootcount_load(void)
+{
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/common/spl/spl_atf.c b/roms/u-boot/common/spl/spl_atf.c
new file mode 100644
index 000000000..e1b68dd56
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_atf.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Reference to the ARM TF Project,
+ * plat/arm/common/arm_bl2_setup.c
+ * Portions copyright (c) 2013-2016, ARM Limited and Contributors. All rights
+ * reserved.
+ * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
+ * Written by Kever Yang <kever.yang@rock-chips.com>
+ * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <atf_common.h>
+#include <cpu_func.h>
+#include <errno.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/cache.h>
+
+/* Holds all the structures we need for bl31 parameter passing */
+struct bl2_to_bl31_params_mem {
+ struct bl31_params bl31_params;
+ struct atf_image_info bl31_image_info;
+ struct atf_image_info bl32_image_info;
+ struct atf_image_info bl33_image_info;
+ struct entry_point_info bl33_ep_info;
+ struct entry_point_info bl32_ep_info;
+ struct entry_point_info bl31_ep_info;
+};
+
+struct bl2_to_bl31_params_mem_v2 {
+ struct bl_params bl_params;
+ struct bl_params_node bl31_params_node;
+ struct bl_params_node bl32_params_node;
+ struct bl_params_node bl33_params_node;
+ struct atf_image_info bl31_image_info;
+ struct atf_image_info bl32_image_info;
+ struct atf_image_info bl33_image_info;
+ struct entry_point_info bl33_ep_info;
+ struct entry_point_info bl32_ep_info;
+ struct entry_point_info bl31_ep_info;
+};
+
+struct bl31_params *bl2_plat_get_bl31_params_default(uintptr_t bl32_entry,
+ uintptr_t bl33_entry,
+ uintptr_t fdt_addr)
+{
+ static struct bl2_to_bl31_params_mem bl31_params_mem;
+ struct bl31_params *bl2_to_bl31_params;
+ struct entry_point_info *bl32_ep_info;
+ struct entry_point_info *bl33_ep_info;
+
+ /*
+ * Initialise the memory for all the arguments that needs to
+ * be passed to BL31
+ */
+ memset(&bl31_params_mem, 0, sizeof(struct bl2_to_bl31_params_mem));
+
+ /* Assign memory for TF related information */
+ bl2_to_bl31_params = &bl31_params_mem.bl31_params;
+ SET_PARAM_HEAD(bl2_to_bl31_params, ATF_PARAM_BL31, ATF_VERSION_1, 0);
+
+ /* Fill BL31 related information */
+ bl2_to_bl31_params->bl31_image_info = &bl31_params_mem.bl31_image_info;
+ SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info,
+ ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0);
+
+ /* Fill BL32 related information */
+ bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
+ bl32_ep_info = &bl31_params_mem.bl32_ep_info;
+ SET_PARAM_HEAD(bl32_ep_info, ATF_PARAM_EP, ATF_VERSION_1,
+ ATF_EP_SECURE);
+
+ /* secure payload is optional, so set pc to 0 if absent */
+ bl32_ep_info->args.arg3 = fdt_addr;
+ bl32_ep_info->pc = bl32_entry ? bl32_entry : 0;
+ bl32_ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+ DISABLE_ALL_EXECPTIONS);
+
+ bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
+ SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info,
+ ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0);
+
+ /* Fill BL33 related information */
+ bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
+ bl33_ep_info = &bl31_params_mem.bl33_ep_info;
+ SET_PARAM_HEAD(bl33_ep_info, ATF_PARAM_EP, ATF_VERSION_1,
+ ATF_EP_NON_SECURE);
+
+ /* BL33 expects to receive the primary CPU MPID (through x0) */
+ bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
+ bl33_ep_info->pc = bl33_entry;
+ bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXECPTIONS);
+
+ bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
+ SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info,
+ ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0);
+
+ return bl2_to_bl31_params;
+}
+
+__weak struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
+ uintptr_t bl33_entry,
+ uintptr_t fdt_addr)
+{
+ return bl2_plat_get_bl31_params_default(bl32_entry, bl33_entry,
+ fdt_addr);
+}
+
+struct bl_params *bl2_plat_get_bl31_params_v2_default(uintptr_t bl32_entry,
+ uintptr_t bl33_entry,
+ uintptr_t fdt_addr)
+{
+ static struct bl2_to_bl31_params_mem_v2 bl31_params_mem;
+ struct bl_params *bl_params;
+ struct bl_params_node *bl_params_node;
+
+ /*
+ * Initialise the memory for all the arguments that needs to
+ * be passed to BL31
+ */
+ memset(&bl31_params_mem, 0, sizeof(bl31_params_mem));
+
+ /* Assign memory for TF related information */
+ bl_params = &bl31_params_mem.bl_params;
+ SET_PARAM_HEAD(bl_params, ATF_PARAM_BL_PARAMS, ATF_VERSION_2, 0);
+ bl_params->head = &bl31_params_mem.bl31_params_node;
+
+ /* Fill BL31 related information */
+ bl_params_node = &bl31_params_mem.bl31_params_node;
+ bl_params_node->image_id = ATF_BL31_IMAGE_ID;
+ bl_params_node->image_info = &bl31_params_mem.bl31_image_info;
+ bl_params_node->ep_info = &bl31_params_mem.bl31_ep_info;
+ bl_params_node->next_params_info = &bl31_params_mem.bl32_params_node;
+ SET_PARAM_HEAD(bl_params_node->image_info, ATF_PARAM_IMAGE_BINARY,
+ ATF_VERSION_2, 0);
+
+ /* Fill BL32 related information */
+ bl_params_node = &bl31_params_mem.bl32_params_node;
+ bl_params_node->image_id = ATF_BL32_IMAGE_ID;
+ bl_params_node->image_info = &bl31_params_mem.bl32_image_info;
+ bl_params_node->ep_info = &bl31_params_mem.bl32_ep_info;
+ bl_params_node->next_params_info = &bl31_params_mem.bl33_params_node;
+ SET_PARAM_HEAD(bl_params_node->ep_info, ATF_PARAM_EP,
+ ATF_VERSION_2, ATF_EP_SECURE);
+
+ /* secure payload is optional, so set pc to 0 if absent */
+ bl_params_node->ep_info->args.arg3 = fdt_addr;
+ bl_params_node->ep_info->pc = bl32_entry ? bl32_entry : 0;
+ bl_params_node->ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+ DISABLE_ALL_EXECPTIONS);
+ SET_PARAM_HEAD(bl_params_node->image_info, ATF_PARAM_IMAGE_BINARY,
+ ATF_VERSION_2, 0);
+
+ /* Fill BL33 related information */
+ bl_params_node = &bl31_params_mem.bl33_params_node;
+ bl_params_node->image_id = ATF_BL33_IMAGE_ID;
+ bl_params_node->image_info = &bl31_params_mem.bl33_image_info;
+ bl_params_node->ep_info = &bl31_params_mem.bl33_ep_info;
+ bl_params_node->next_params_info = NULL;
+ SET_PARAM_HEAD(bl_params_node->ep_info, ATF_PARAM_EP,
+ ATF_VERSION_2, ATF_EP_NON_SECURE);
+
+ /* BL33 expects to receive the primary CPU MPID (through x0) */
+ bl_params_node->ep_info->args.arg0 = 0xffff & read_mpidr();
+ bl_params_node->ep_info->pc = bl33_entry;
+ bl_params_node->ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXECPTIONS);
+ SET_PARAM_HEAD(bl_params_node->image_info, ATF_PARAM_IMAGE_BINARY,
+ ATF_VERSION_2, 0);
+
+ return bl_params;
+}
+
+__weak struct bl_params *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry,
+ uintptr_t bl33_entry,
+ uintptr_t fdt_addr)
+{
+ return bl2_plat_get_bl31_params_v2_default(bl32_entry, bl33_entry,
+ fdt_addr);
+}
+
+static inline void raw_write_daif(unsigned int daif)
+{
+ __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
+}
+
+typedef void (*atf_entry_t)(struct bl31_params *params, void *plat_params);
+
+static void bl31_entry(uintptr_t bl31_entry, uintptr_t bl32_entry,
+ uintptr_t bl33_entry, uintptr_t fdt_addr)
+{
+ atf_entry_t atf_entry = (atf_entry_t)bl31_entry;
+ void *bl31_params;
+
+ if (CONFIG_IS_ENABLED(ATF_LOAD_IMAGE_V2))
+ bl31_params = bl2_plat_get_bl31_params_v2(bl32_entry,
+ bl33_entry,
+ fdt_addr);
+ else
+ bl31_params = bl2_plat_get_bl31_params(bl32_entry, bl33_entry,
+ fdt_addr);
+
+ raw_write_daif(SPSR_EXCEPTION_MASK);
+ dcache_disable();
+
+ atf_entry(bl31_params, (void *)fdt_addr);
+}
+
+static int spl_fit_images_find(void *blob, int os)
+{
+ int parent, node, ndepth = 0;
+ const void *data;
+
+ if (!blob)
+ return -FDT_ERR_BADMAGIC;
+
+ parent = fdt_path_offset(blob, "/fit-images");
+ if (parent < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ for (node = fdt_next_node(blob, parent, &ndepth);
+ (node >= 0) && (ndepth > 0);
+ node = fdt_next_node(blob, node, &ndepth)) {
+ if (ndepth != 1)
+ continue;
+
+ data = fdt_getprop(blob, node, FIT_OS_PROP, NULL);
+ if (!data)
+ continue;
+
+ if (genimg_get_os_id(data) == os)
+ return node;
+ };
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+uintptr_t spl_fit_images_get_entry(void *blob, int node)
+{
+ ulong val;
+ int ret;
+
+ ret = fit_image_get_entry(blob, node, &val);
+ if (ret)
+ ret = fit_image_get_load(blob, node, &val);
+
+ debug("%s: entry point 0x%lx\n", __func__, val);
+ return val;
+}
+
+void spl_invoke_atf(struct spl_image_info *spl_image)
+{
+ uintptr_t bl32_entry = 0;
+ uintptr_t bl33_entry = CONFIG_SYS_TEXT_BASE;
+ void *blob = spl_image->fdt_addr;
+ uintptr_t platform_param = (uintptr_t)blob;
+ int node;
+
+ /*
+ * Find the OP-TEE binary (in /fit-images) load address or
+ * entry point (if different) and pass it as the BL3-2 entry
+ * point, this is optional.
+ */
+ node = spl_fit_images_find(blob, IH_OS_TEE);
+ if (node >= 0)
+ bl32_entry = spl_fit_images_get_entry(blob, node);
+
+ /*
+ * Find the U-Boot binary (in /fit-images) load addreess or
+ * entry point (if different) and pass it as the BL3-3 entry
+ * point.
+ * This will need to be extended to support Falcon mode.
+ */
+
+ node = spl_fit_images_find(blob, IH_OS_U_BOOT);
+ if (node >= 0)
+ bl33_entry = spl_fit_images_get_entry(blob, node);
+
+ /*
+ * If ATF_NO_PLATFORM_PARAM is set, we override the platform
+ * parameter and always pass 0. This is a workaround for
+ * older ATF versions that have insufficiently robust (or
+ * overzealous) argument validation.
+ */
+ if (CONFIG_IS_ENABLED(ATF_NO_PLATFORM_PARAM))
+ platform_param = 0;
+
+ /*
+ * We don't provide a BL3-2 entry yet, but this will be possible
+ * using similar logic.
+ */
+ bl31_entry(spl_image->entry_point, bl32_entry,
+ bl33_entry, platform_param);
+}
diff --git a/roms/u-boot/common/spl/spl_bootrom.c b/roms/u-boot/common/spl/spl_bootrom.c
new file mode 100644
index 000000000..0eefd39a5
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_bootrom.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Theobroma Systems Design und Consulting GmH
+ */
+
+#include <common.h>
+#include <spl.h>
+
+__weak int board_return_to_bootrom(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ return 0;
+}
+
+static int spl_return_to_bootrom(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ /*
+ * If the board implements a way to return to its ROM (with
+ * the expectation that the next stage of will be booted by
+ * the ROM), it will implement board_return_to_bootrom() and
+ * should not return from it.
+ */
+ return board_return_to_bootrom(spl_image, bootdev);
+}
+
+SPL_LOAD_IMAGE_METHOD("BOOTROM", 0, BOOT_DEVICE_BOOTROM, spl_return_to_bootrom);
diff --git a/roms/u-boot/common/spl/spl_dfu.c b/roms/u-boot/common/spl/spl_dfu.c
new file mode 100644
index 000000000..5728d43ad
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_dfu.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016
+ * Texas Instruments, <www.ti.com>
+ *
+ * Ravi B <ravibabu@ti.com>
+ */
+#include <common.h>
+#include <env.h>
+#include <spl.h>
+#include <linux/compiler.h>
+#include <errno.h>
+#include <watchdog.h>
+#include <console.h>
+#include <g_dnl.h>
+#include <usb.h>
+#include <dfu.h>
+
+static int run_dfu(int usb_index, char *interface, char *devstring)
+{
+ int ret;
+
+ ret = dfu_init_env_entities(interface, devstring);
+ if (ret) {
+ dfu_free_entities();
+ goto exit;
+ }
+
+ run_usb_dnl_gadget(usb_index, "usb_dnl_dfu");
+exit:
+ dfu_free_entities();
+ return ret;
+}
+
+int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr)
+{
+ char *str_env;
+ int ret;
+
+ /* set default environment */
+ env_set_default(NULL, 0);
+ str_env = env_get(dfu_alt_info);
+ if (!str_env) {
+ pr_err("\"%s\" env variable not defined!\n", dfu_alt_info);
+ return -EINVAL;
+ }
+
+ ret = env_set("dfu_alt_info", str_env);
+ if (ret) {
+ pr_err("unable to set env variable \"dfu_alt_info\"!\n");
+ return -EINVAL;
+ }
+
+ /* invoke dfu command */
+ return run_dfu(usbctrl, interface, devstr);
+}
diff --git a/roms/u-boot/common/spl/spl_ext.c b/roms/u-boot/common/spl/spl_ext.c
new file mode 100644
index 000000000..d73f06276
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_ext.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <env.h>
+#include <part.h>
+#include <spl.h>
+#include <asm/u-boot.h>
+#include <ext4fs.h>
+#include <errno.h>
+#include <image.h>
+
+int spl_load_image_ext(struct spl_image_info *spl_image,
+ struct blk_desc *block_dev, int partition,
+ const char *filename)
+{
+ s32 err;
+ struct image_header *header;
+ loff_t filelen, actlen;
+ struct disk_partition part_info = {};
+
+ header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));
+
+ if (part_get_info(block_dev, partition, &part_info)) {
+ printf("spl: no partition table found\n");
+ return -1;
+ }
+
+ ext4fs_set_blk_dev(block_dev, &part_info);
+
+ err = ext4fs_mount(0);
+ if (!err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("%s: ext4fs mount err - %d\n", __func__, err);
+#endif
+ return -1;
+ }
+
+ err = ext4fs_open(filename, &filelen);
+ if (err < 0) {
+ puts("spl: ext4fs_open failed\n");
+ goto end;
+ }
+ err = ext4fs_read((char *)header, 0, sizeof(struct image_header), &actlen);
+ if (err < 0) {
+ puts("spl: ext4fs_read failed\n");
+ goto end;
+ }
+
+ err = spl_parse_image_header(spl_image, header);
+ if (err < 0) {
+ puts("spl: ext: failed to parse image header\n");
+ goto end;
+ }
+
+ err = ext4fs_read((char *)spl_image->load_addr, 0, filelen, &actlen);
+
+end:
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ if (err < 0)
+ printf("%s: error reading image %s, err - %d\n",
+ __func__, filename, err);
+#endif
+
+ return err < 0;
+}
+
+#ifdef CONFIG_SPL_OS_BOOT
+int spl_load_image_ext_os(struct spl_image_info *spl_image,
+ struct blk_desc *block_dev, int partition)
+{
+ int err;
+ __maybe_unused loff_t filelen, actlen;
+ struct disk_partition part_info = {};
+ __maybe_unused char *file;
+
+ if (part_get_info(block_dev, partition, &part_info)) {
+ printf("spl: no partition table found\n");
+ return -1;
+ }
+
+ ext4fs_set_blk_dev(block_dev, &part_info);
+
+ err = ext4fs_mount(0);
+ if (!err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("%s: ext4fs mount err - %d\n", __func__, err);
+#endif
+ return -1;
+ }
+#if defined(CONFIG_SPL_ENV_SUPPORT)
+ file = env_get("falcon_args_file");
+ if (file) {
+ err = ext4fs_open(file, &filelen);
+ if (err < 0) {
+ puts("spl: ext4fs_open failed\n");
+ goto defaults;
+ }
+ err = ext4fs_read((void *)CONFIG_SYS_SPL_ARGS_ADDR, 0, filelen, &actlen);
+ if (err < 0) {
+ printf("spl: error reading image %s, err - %d, falling back to default\n",
+ file, err);
+ goto defaults;
+ }
+ file = env_get("falcon_image_file");
+ if (file) {
+ err = spl_load_image_ext(spl_image, block_dev,
+ partition, file);
+ if (err != 0) {
+ puts("spl: falling back to default\n");
+ goto defaults;
+ }
+
+ return 0;
+ } else {
+ puts("spl: falcon_image_file not set in environment, falling back to default\n");
+ }
+ } else {
+ puts("spl: falcon_args_file not set in environment, falling back to default\n");
+ }
+
+defaults:
+#endif
+
+ err = ext4fs_open(CONFIG_SPL_FS_LOAD_ARGS_NAME, &filelen);
+ if (err < 0)
+ puts("spl: ext4fs_open failed\n");
+
+ err = ext4fs_read((void *)CONFIG_SYS_SPL_ARGS_ADDR, 0, filelen, &actlen);
+ if (err < 0) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("%s: error reading image %s, err - %d\n",
+ __func__, CONFIG_SPL_FS_LOAD_ARGS_NAME, err);
+#endif
+ return -1;
+ }
+
+ return spl_load_image_ext(spl_image, block_dev, partition,
+ CONFIG_SPL_FS_LOAD_KERNEL_NAME);
+}
+#else
+int spl_load_image_ext_os(struct spl_image_info *spl_image,
+ struct blk_desc *block_dev, int partition)
+{
+ return -ENOSYS;
+}
+#endif
diff --git a/roms/u-boot/common/spl/spl_fat.c b/roms/u-boot/common/spl/spl_fat.c
new file mode 100644
index 000000000..c2eb09736
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_fat.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2014
+ * Texas Instruments, <www.ti.com>
+ *
+ * Dan Murphy <dmurphy@ti.com>
+ *
+ * FAT Image Functions copied from spl_mmc.c
+ */
+
+#include <common.h>
+#include <env.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/u-boot.h>
+#include <fat.h>
+#include <errno.h>
+#include <image.h>
+#include <linux/libfdt.h>
+
+static int fat_registered;
+
+static int spl_register_fat_device(struct blk_desc *block_dev, int partition)
+{
+ int err = 0;
+
+ if (fat_registered)
+ return err;
+
+ err = fat_register_device(block_dev, partition);
+ if (err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("%s: fat register err - %d\n", __func__, err);
+#endif
+ return err;
+ }
+
+ fat_registered = 1;
+
+ return err;
+}
+
+static ulong spl_fit_read(struct spl_load_info *load, ulong file_offset,
+ ulong size, void *buf)
+{
+ loff_t actread;
+ int ret;
+ char *filename = (char *)load->filename;
+
+ ret = fat_read_file(filename, buf, file_offset, size, &actread);
+ if (ret)
+ return ret;
+
+ return actread;
+}
+
+int spl_load_image_fat(struct spl_image_info *spl_image,
+ struct blk_desc *block_dev, int partition,
+ const char *filename)
+{
+ int err;
+ struct image_header *header;
+
+ err = spl_register_fat_device(block_dev, partition);
+ if (err)
+ goto end;
+
+ header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));
+
+ err = file_fat_read(filename, header, sizeof(struct image_header));
+ if (err <= 0)
+ goto end;
+
+ if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) &&
+ image_get_magic(header) == FDT_MAGIC) {
+ err = file_fat_read(filename, (void *)CONFIG_SYS_LOAD_ADDR, 0);
+ if (err <= 0)
+ goto end;
+ err = spl_parse_image_header(spl_image,
+ (struct image_header *)CONFIG_SYS_LOAD_ADDR);
+ if (err == -EAGAIN)
+ return err;
+ if (err == 0)
+ err = 1;
+ } else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+ image_get_magic(header) == FDT_MAGIC) {
+ struct spl_load_info load;
+
+ debug("Found FIT\n");
+ load.read = spl_fit_read;
+ load.bl_len = 1;
+ load.filename = (void *)filename;
+ load.priv = NULL;
+
+ return spl_load_simple_fit(spl_image, &load, 0, header);
+ } else {
+ err = spl_parse_image_header(spl_image, header);
+ if (err)
+ goto end;
+
+ err = file_fat_read(filename,
+ (u8 *)(uintptr_t)spl_image->load_addr, 0);
+ }
+
+end:
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ if (err <= 0)
+ printf("%s: error reading image %s, err - %d\n",
+ __func__, filename, err);
+#endif
+
+ return (err <= 0);
+}
+
+#ifdef CONFIG_SPL_OS_BOOT
+int spl_load_image_fat_os(struct spl_image_info *spl_image,
+ struct blk_desc *block_dev, int partition)
+{
+ int err;
+ __maybe_unused char *file;
+
+ err = spl_register_fat_device(block_dev, partition);
+ if (err)
+ return err;
+
+#if defined(CONFIG_SPL_ENV_SUPPORT) && defined(CONFIG_SPL_OS_BOOT)
+ file = env_get("falcon_args_file");
+ if (file) {
+ err = file_fat_read(file, (void *)CONFIG_SYS_SPL_ARGS_ADDR, 0);
+ if (err <= 0) {
+ printf("spl: error reading image %s, err - %d, falling back to default\n",
+ file, err);
+ goto defaults;
+ }
+ file = env_get("falcon_image_file");
+ if (file) {
+ err = spl_load_image_fat(spl_image, block_dev,
+ partition, file);
+ if (err != 0) {
+ puts("spl: falling back to default\n");
+ goto defaults;
+ }
+
+ return 0;
+ } else
+ puts("spl: falcon_image_file not set in environment, falling back to default\n");
+ } else
+ puts("spl: falcon_args_file not set in environment, falling back to default\n");
+
+defaults:
+#endif
+
+ err = file_fat_read(CONFIG_SPL_FS_LOAD_ARGS_NAME,
+ (void *)CONFIG_SYS_SPL_ARGS_ADDR, 0);
+ if (err <= 0) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("%s: error reading image %s, err - %d\n",
+ __func__, CONFIG_SPL_FS_LOAD_ARGS_NAME, err);
+#endif
+ return -1;
+ }
+
+ return spl_load_image_fat(spl_image, block_dev, partition,
+ CONFIG_SPL_FS_LOAD_KERNEL_NAME);
+}
+#else
+int spl_load_image_fat_os(struct spl_image_info *spl_image,
+ struct blk_desc *block_dev, int partition)
+{
+ return -ENOSYS;
+}
+#endif
diff --git a/roms/u-boot/common/spl/spl_fit.c b/roms/u-boot/common/spl/spl_fit.c
new file mode 100644
index 000000000..caddf5119
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_fit.c
@@ -0,0 +1,810 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fpga.h>
+#include <gzip.h>
+#include <image.h>
+#include <log.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <spl.h>
+#include <sysinfo.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <linux/libfdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ
+#define CONFIG_SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ (64 * 1024)
+#endif
+
+#ifndef CONFIG_SYS_BOOTM_LEN
+#define CONFIG_SYS_BOOTM_LEN (64 << 20)
+#endif
+
+struct spl_fit_info {
+ const void *fit; /* Pointer to a valid FIT blob */
+ size_t ext_data_offset; /* Offset to FIT external data (end of FIT) */
+ int images_node; /* FDT offset to "/images" node */
+ int conf_node; /* FDT offset to selected configuration node */
+};
+
+__weak void board_spl_fit_post_load(const void *fit)
+{
+}
+
+__weak ulong board_spl_fit_size_align(ulong size)
+{
+ return size;
+}
+
+static int find_node_from_desc(const void *fit, int node, const char *str)
+{
+ int child;
+
+ if (node < 0)
+ return -EINVAL;
+
+ /* iterate the FIT nodes and find a matching description */
+ for (child = fdt_first_subnode(fit, node); child >= 0;
+ child = fdt_next_subnode(fit, child)) {
+ int len;
+ const char *desc = fdt_getprop(fit, child, "description", &len);
+
+ if (!desc)
+ continue;
+
+ if (!strcmp(desc, str))
+ return child;
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * spl_fit_get_image_name(): By using the matching configuration subnode,
+ * retrieve the name of an image, specified by a property name and an index
+ * into that.
+ * @fit: Pointer to the FDT blob.
+ * @images: Offset of the /images subnode.
+ * @type: Name of the property within the configuration subnode.
+ * @index: Index into the list of strings in this property.
+ * @outname: Name of the image
+ *
+ * Return: 0 on success, or a negative error number
+ */
+static int spl_fit_get_image_name(const struct spl_fit_info *ctx,
+ const char *type, int index,
+ const char **outname)
+{
+ struct udevice *sysinfo;
+ const char *name, *str;
+ __maybe_unused int node;
+ int len, i;
+ bool found = true;
+
+ name = fdt_getprop(ctx->fit, ctx->conf_node, type, &len);
+ if (!name) {
+ debug("cannot find property '%s': %d\n", type, len);
+ return -EINVAL;
+ }
+
+ str = name;
+ for (i = 0; i < index; i++) {
+ str = strchr(str, '\0') + 1;
+ if (!str || (str - name >= len)) {
+ found = false;
+ break;
+ }
+ }
+
+ if (!found && CONFIG_IS_ENABLED(SYSINFO) && !sysinfo_get(&sysinfo)) {
+ int rc;
+ /*
+ * no string in the property for this index. Check if the
+ * sysinfo-level code can supply one.
+ */
+ rc = sysinfo_detect(sysinfo);
+ if (rc)
+ return rc;
+
+ rc = sysinfo_get_fit_loadable(sysinfo, index - i - 1, type,
+ &str);
+ if (rc && rc != -ENOENT)
+ return rc;
+
+ if (!rc) {
+ /*
+ * The sysinfo provided a name for a loadable.
+ * Try to match it against the description properties
+ * first. If no matching node is found, use it as a
+ * node name.
+ */
+ int node;
+ int images = fdt_path_offset(ctx->fit, FIT_IMAGES_PATH);
+
+ node = find_node_from_desc(ctx->fit, images, str);
+ if (node > 0)
+ str = fdt_get_name(ctx->fit, node, NULL);
+
+ found = true;
+ }
+ }
+
+ if (!found) {
+ debug("no string for index %d\n", index);
+ return -E2BIG;
+ }
+
+ *outname = str;
+ return 0;
+}
+
+/**
+ * spl_fit_get_image_node(): By using the matching configuration subnode,
+ * retrieve the name of an image, specified by a property name and an index
+ * into that.
+ * @fit: Pointer to the FDT blob.
+ * @images: Offset of the /images subnode.
+ * @type: Name of the property within the configuration subnode.
+ * @index: Index into the list of strings in this property.
+ *
+ * Return: the node offset of the respective image node or a negative
+ * error number.
+ */
+static int spl_fit_get_image_node(const struct spl_fit_info *ctx,
+ const char *type, int index)
+{
+ const char *str;
+ int err;
+ int node;
+
+ err = spl_fit_get_image_name(ctx, type, index, &str);
+ if (err)
+ return err;
+
+ debug("%s: '%s'\n", type, str);
+
+ node = fdt_subnode_offset(ctx->fit, ctx->images_node, str);
+ if (node < 0) {
+ pr_err("cannot find image node '%s': %d\n", str, node);
+ return -EINVAL;
+ }
+
+ return node;
+}
+
+static int get_aligned_image_offset(struct spl_load_info *info, int offset)
+{
+ /*
+ * If it is a FS read, get the first address before offset which is
+ * aligned to ARCH_DMA_MINALIGN. If it is raw read return the
+ * block number to which offset belongs.
+ */
+ if (info->filename)
+ return offset & ~(ARCH_DMA_MINALIGN - 1);
+
+ return offset / info->bl_len;
+}
+
+static int get_aligned_image_overhead(struct spl_load_info *info, int offset)
+{
+ /*
+ * If it is a FS read, get the difference between the offset and
+ * the first address before offset which is aligned to
+ * ARCH_DMA_MINALIGN. If it is raw read return the offset within the
+ * block.
+ */
+ if (info->filename)
+ return offset & (ARCH_DMA_MINALIGN - 1);
+
+ return offset % info->bl_len;
+}
+
+static int get_aligned_image_size(struct spl_load_info *info, int data_size,
+ int offset)
+{
+ data_size = data_size + get_aligned_image_overhead(info, offset);
+
+ if (info->filename)
+ return data_size;
+
+ return (data_size + info->bl_len - 1) / info->bl_len;
+}
+
+/**
+ * spl_load_fit_image(): load the image described in a certain FIT node
+ * @info: points to information about the device to load data from
+ * @sector: the start sector of the FIT image on the device
+ * @ctx: points to the FIT context structure
+ * @node: offset of the DT node describing the image to load (relative
+ * to @fit)
+ * @image_info: will be filled with information about the loaded image
+ * If the FIT node does not contain a "load" (address) property,
+ * the image gets loaded to the address pointed to by the
+ * load_addr member in this struct, if load_addr is not 0
+ *
+ * Return: 0 on success or a negative error number.
+ */
+static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
+ const struct spl_fit_info *ctx, int node,
+ struct spl_image_info *image_info)
+{
+ int offset;
+ size_t length;
+ int len;
+ ulong size;
+ ulong load_addr;
+ void *load_ptr;
+ void *src;
+ ulong overhead;
+ int nr_sectors;
+ uint8_t image_comp = -1, type = -1;
+ const void *data;
+ const void *fit = ctx->fit;
+ bool external_data = false;
+
+ if (IS_ENABLED(CONFIG_SPL_FPGA) ||
+ (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP))) {
+ if (fit_image_get_type(fit, node, &type))
+ puts("Cannot get image type.\n");
+ else
+ debug("%s ", genimg_get_type_name(type));
+ }
+
+ if (IS_ENABLED(CONFIG_SPL_GZIP)) {
+ fit_image_get_comp(fit, node, &image_comp);
+ debug("%s ", genimg_get_comp_name(image_comp));
+ }
+
+ if (fit_image_get_load(fit, node, &load_addr)) {
+ if (!image_info->load_addr) {
+ printf("Can't load %s: No load address and no buffer\n",
+ fit_get_name(fit, node, NULL));
+ return -ENOBUFS;
+ }
+ load_addr = image_info->load_addr;
+ }
+
+ if (!fit_image_get_data_position(fit, node, &offset)) {
+ external_data = true;
+ } else if (!fit_image_get_data_offset(fit, node, &offset)) {
+ offset += ctx->ext_data_offset;
+ external_data = true;
+ }
+
+ if (external_data) {
+ void *src_ptr;
+
+ /* External data */
+ if (fit_image_get_data_size(fit, node, &len))
+ return -ENOENT;
+
+ src_ptr = map_sysmem(ALIGN(load_addr, ARCH_DMA_MINALIGN), len);
+ length = len;
+
+ overhead = get_aligned_image_overhead(info, offset);
+ nr_sectors = get_aligned_image_size(info, length, offset);
+
+ if (info->read(info,
+ sector + get_aligned_image_offset(info, offset),
+ nr_sectors, src_ptr) != nr_sectors)
+ return -EIO;
+
+ debug("External data: dst=%p, offset=%x, size=%lx\n",
+ src_ptr, offset, (unsigned long)length);
+ src = src_ptr + overhead;
+ } else {
+ /* Embedded data */
+ if (fit_image_get_data(fit, node, &data, &length)) {
+ puts("Cannot get image data/size\n");
+ return -ENOENT;
+ }
+ debug("Embedded data: dst=%lx, size=%lx\n", load_addr,
+ (unsigned long)length);
+ src = (void *)data; /* cast away const */
+ }
+
+ if (CONFIG_IS_ENABLED(FIT_SIGNATURE)) {
+ printf("## Checking hash(es) for Image %s ... ",
+ fit_get_name(fit, node, NULL));
+ if (!fit_image_verify_with_data(fit, node, src, length))
+ return -EPERM;
+ puts("OK\n");
+ }
+
+ if (CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS))
+ board_fit_image_post_process(&src, &length);
+
+ load_ptr = map_sysmem(load_addr, length);
+ if (IS_ENABLED(CONFIG_SPL_GZIP) && image_comp == IH_COMP_GZIP) {
+ size = length;
+ if (gunzip(load_ptr, CONFIG_SYS_BOOTM_LEN, src, &size)) {
+ puts("Uncompressing error\n");
+ return -EIO;
+ }
+ length = size;
+ } else {
+ memcpy(load_ptr, src, length);
+ }
+
+ if (image_info) {
+ ulong entry_point;
+
+ image_info->load_addr = load_addr;
+ image_info->size = length;
+
+ if (!fit_image_get_entry(fit, node, &entry_point))
+ image_info->entry_point = entry_point;
+ else
+ image_info->entry_point = FDT_ERROR;
+ }
+
+ return 0;
+}
+
+static bool os_takes_devicetree(uint8_t os)
+{
+ switch (os) {
+ case IH_OS_U_BOOT:
+ return true;
+ case IH_OS_LINUX:
+ return IS_ENABLED(CONFIG_SPL_OS_BOOT);
+ default:
+ return false;
+ }
+}
+
+static int spl_fit_append_fdt(struct spl_image_info *spl_image,
+ struct spl_load_info *info, ulong sector,
+ const struct spl_fit_info *ctx)
+{
+ struct spl_image_info image_info;
+ int node, ret = 0, index = 0;
+
+ /*
+ * Use the address following the image as target address for the
+ * device tree.
+ */
+ image_info.load_addr = spl_image->load_addr + spl_image->size;
+
+ /* Figure out which device tree the board wants to use */
+ node = spl_fit_get_image_node(ctx, FIT_FDT_PROP, index++);
+ if (node < 0) {
+ debug("%s: cannot find FDT node\n", __func__);
+
+ /*
+ * U-Boot did not find a device tree inside the FIT image. Use
+ * the U-Boot device tree instead.
+ */
+ if (gd->fdt_blob)
+ memcpy((void *)image_info.load_addr, gd->fdt_blob,
+ fdt_totalsize(gd->fdt_blob));
+ else
+ return node;
+ } else {
+ ret = spl_load_fit_image(info, sector, ctx, node,
+ &image_info);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Make the load-address of the FDT available for the SPL framework */
+ spl_image->fdt_addr = map_sysmem(image_info.load_addr, 0);
+ if (CONFIG_IS_ENABLED(FIT_IMAGE_TINY))
+ return 0;
+
+ if (CONFIG_IS_ENABLED(LOAD_FIT_APPLY_OVERLAY)) {
+ void *tmpbuffer = NULL;
+
+ for (; ; index++) {
+ node = spl_fit_get_image_node(ctx, FIT_FDT_PROP, index);
+ if (node == -E2BIG) {
+ debug("%s: No additional FDT node\n", __func__);
+ break;
+ } else if (node < 0) {
+ debug("%s: unable to find FDT node %d\n",
+ __func__, index);
+ continue;
+ }
+
+ if (!tmpbuffer) {
+ /*
+ * allocate memory to store the DT overlay
+ * before it is applied. It may not be used
+ * depending on how the overlay is stored, so
+ * don't fail yet if the allocation failed.
+ */
+ tmpbuffer = malloc(CONFIG_SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ);
+ if (!tmpbuffer)
+ debug("%s: unable to allocate space for overlays\n",
+ __func__);
+ }
+ image_info.load_addr = (ulong)tmpbuffer;
+ ret = spl_load_fit_image(info, sector, ctx,
+ node, &image_info);
+ if (ret < 0)
+ break;
+
+ /* Make room in FDT for changes from the overlay */
+ ret = fdt_increase_size(spl_image->fdt_addr,
+ image_info.size);
+ if (ret < 0)
+ break;
+
+ ret = fdt_overlay_apply_verbose(spl_image->fdt_addr,
+ (void *)image_info.load_addr);
+ if (ret) {
+ pr_err("failed to apply DT overlay %s\n",
+ fit_get_name(ctx->fit, node, NULL));
+ break;
+ }
+
+ debug("%s: DT overlay %s applied\n", __func__,
+ fit_get_name(ctx->fit, node, NULL));
+ }
+ free(tmpbuffer);
+ if (ret)
+ return ret;
+ }
+ /* Try to make space, so we can inject details on the loadables */
+ ret = fdt_shrink_to_minimum(spl_image->fdt_addr, 8192);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int spl_fit_record_loadable(const struct spl_fit_info *ctx, int index,
+ void *blob, struct spl_image_info *image)
+{
+ int ret = 0;
+ const char *name;
+ int node;
+
+ if (CONFIG_IS_ENABLED(FIT_IMAGE_TINY))
+ return 0;
+
+ ret = spl_fit_get_image_name(ctx, "loadables", index, &name);
+ if (ret < 0)
+ return ret;
+
+ node = spl_fit_get_image_node(ctx, "loadables", index);
+
+ ret = fdt_record_loadable(blob, index, name, image->load_addr,
+ image->size, image->entry_point,
+ fdt_getprop(ctx->fit, node, "type", NULL),
+ fdt_getprop(ctx->fit, node, "os", NULL));
+ return ret;
+}
+
+static int spl_fit_image_is_fpga(const void *fit, int node)
+{
+ const char *type;
+
+ if (!IS_ENABLED(CONFIG_SPL_FPGA))
+ return 0;
+
+ type = fdt_getprop(fit, node, FIT_TYPE_PROP, NULL);
+ if (!type)
+ return 0;
+
+ return !strcmp(type, "fpga");
+}
+
+static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os)
+{
+ if (!CONFIG_IS_ENABLED(FIT_IMAGE_TINY) || CONFIG_IS_ENABLED(OS_BOOT))
+ return fit_image_get_os(fit, noffset, os);
+
+ const char *name = fdt_getprop(fit, noffset, FIT_OS_PROP, NULL);
+ if (!name)
+ return -ENOENT;
+
+ /*
+ * We don't care what the type of the image actually is,
+ * only whether or not it is U-Boot. This saves some
+ * space by omitting the large table of OS types.
+ */
+ if (!strcmp(name, "u-boot"))
+ *os = IH_OS_U_BOOT;
+ else
+ *os = IH_OS_INVALID;
+
+ return 0;
+}
+
+/*
+ * The purpose of the FIT load buffer is to provide a memory location that is
+ * independent of the load address of any FIT component.
+ */
+static void *spl_get_fit_load_buffer(size_t size)
+{
+ void *buf;
+
+ buf = malloc(size);
+ if (!buf) {
+ pr_err("Could not get FIT buffer of %lu bytes\n", (ulong)size);
+ pr_err("\tcheck CONFIG_SYS_SPL_MALLOC_SIZE\n");
+ buf = spl_get_load_buffer(0, size);
+ }
+ return buf;
+}
+
+/*
+ * Weak default function to allow customizing SPL fit loading for load-only
+ * use cases by allowing to skip the parsing/processing of the FIT contents
+ * (so that this can be done separately in a more customized fashion)
+ */
+__weak bool spl_load_simple_fit_skip_processing(void)
+{
+ return false;
+}
+
+static void warn_deprecated(const char *msg)
+{
+ printf("DEPRECATED: %s\n", msg);
+ printf("\tSee doc/uImage.FIT/source_file_format.txt\n");
+}
+
+static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node,
+ struct spl_image_info *fpga_image)
+{
+ const char *compatible;
+ int ret;
+
+ debug("FPGA bitstream at: %x, size: %x\n",
+ (u32)fpga_image->load_addr, fpga_image->size);
+
+ compatible = fdt_getprop(ctx->fit, node, "compatible", NULL);
+ if (!compatible)
+ warn_deprecated("'fpga' image without 'compatible' property");
+ else if (strcmp(compatible, "u-boot,fpga-legacy"))
+ printf("Ignoring compatible = %s property\n", compatible);
+
+ ret = fpga_load(0, (void *)fpga_image->load_addr, fpga_image->size,
+ BIT_FULL);
+ if (ret) {
+ printf("%s: Cannot load the image to the FPGA\n", __func__);
+ return ret;
+ }
+
+ puts("FPGA image loaded from FIT\n");
+
+ return 0;
+}
+
+static int spl_fit_load_fpga(struct spl_fit_info *ctx,
+ struct spl_load_info *info, ulong sector)
+{
+ int node, ret;
+
+ struct spl_image_info fpga_image = {
+ .load_addr = 0,
+ };
+
+ node = spl_fit_get_image_node(ctx, "fpga", 0);
+ if (node < 0)
+ return node;
+
+ warn_deprecated("'fpga' property in config node. Use 'loadables'");
+
+ /* Load the image and set up the fpga_image structure */
+ ret = spl_load_fit_image(info, sector, ctx, node, &fpga_image);
+ if (ret) {
+ printf("%s: Cannot load the FPGA: %i\n", __func__, ret);
+ return ret;
+ }
+
+ return spl_fit_upload_fpga(ctx, node, &fpga_image);
+}
+
+static int spl_simple_fit_read(struct spl_fit_info *ctx,
+ struct spl_load_info *info, ulong sector,
+ const void *fit_header)
+{
+ unsigned long count, size;
+ int sectors;
+ void *buf;
+
+ /*
+ * For FIT with external data, figure out where the external images
+ * start. This is the base for the data-offset properties in each
+ * image.
+ */
+ size = ALIGN(fdt_totalsize(fit_header), 4);
+ size = board_spl_fit_size_align(size);
+ ctx->ext_data_offset = ALIGN(size, 4);
+
+ /*
+ * So far we only have one block of data from the FIT. Read the entire
+ * thing, including that first block.
+ *
+ * For FIT with data embedded, data is loaded as part of FIT image.
+ * For FIT with external data, data is not loaded in this step.
+ */
+ sectors = get_aligned_image_size(info, size, 0);
+ buf = spl_get_fit_load_buffer(sectors * info->bl_len);
+
+ count = info->read(info, sector, sectors, buf);
+ ctx->fit = buf;
+ debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu, size=0x%lx\n",
+ sector, sectors, buf, count, size);
+
+ return (count == 0) ? -EIO : 0;
+}
+
+static int spl_simple_fit_parse(struct spl_fit_info *ctx)
+{
+ /* Find the correct subnode under "/configurations" */
+ ctx->conf_node = fit_find_config_node(ctx->fit);
+ if (ctx->conf_node < 0)
+ return -EINVAL;
+
+ if (IS_ENABLED(CONFIG_SPL_FIT_SIGNATURE)) {
+ printf("## Checking hash(es) for config %s ... ",
+ fit_get_name(ctx->fit, ctx->conf_node, NULL));
+ if (fit_config_verify(ctx->fit, ctx->conf_node))
+ return -EPERM;
+ puts("OK\n");
+ }
+
+ /* find the node holding the images information */
+ ctx->images_node = fdt_path_offset(ctx->fit, FIT_IMAGES_PATH);
+ if (ctx->images_node < 0) {
+ debug("%s: Cannot find /images node: %d\n", __func__,
+ ctx->images_node);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int spl_load_simple_fit(struct spl_image_info *spl_image,
+ struct spl_load_info *info, ulong sector, void *fit)
+{
+ struct spl_image_info image_info;
+ struct spl_fit_info ctx;
+ int node = -1;
+ int ret;
+ int index = 0;
+ int firmware_node;
+
+ ret = spl_simple_fit_read(&ctx, info, sector, fit);
+ if (ret < 0)
+ return ret;
+
+ /* skip further processing if requested to enable load-only use cases */
+ if (spl_load_simple_fit_skip_processing())
+ return 0;
+
+ ret = spl_simple_fit_parse(&ctx);
+ if (ret < 0)
+ return ret;
+
+ if (IS_ENABLED(CONFIG_SPL_FPGA))
+ spl_fit_load_fpga(&ctx, info, sector);
+
+ /*
+ * Find the U-Boot image using the following search order:
+ * - start at 'firmware' (e.g. an ARM Trusted Firmware)
+ * - fall back 'kernel' (e.g. a Falcon-mode OS boot
+ * - fall back to using the first 'loadables' entry
+ */
+ if (node < 0)
+ node = spl_fit_get_image_node(&ctx, FIT_FIRMWARE_PROP, 0);
+
+ if (node < 0 && IS_ENABLED(CONFIG_SPL_OS_BOOT))
+ node = spl_fit_get_image_node(&ctx, FIT_KERNEL_PROP, 0);
+
+ if (node < 0) {
+ debug("could not find firmware image, trying loadables...\n");
+ node = spl_fit_get_image_node(&ctx, "loadables", 0);
+ /*
+ * If we pick the U-Boot image from "loadables", start at
+ * the second image when later loading additional images.
+ */
+ index = 1;
+ }
+ if (node < 0) {
+ debug("%s: Cannot find u-boot image node: %d\n",
+ __func__, node);
+ return -1;
+ }
+
+ /* Load the image and set up the spl_image structure */
+ ret = spl_load_fit_image(info, sector, &ctx, node, spl_image);
+ if (ret)
+ return ret;
+
+ /*
+ * For backward compatibility, we treat the first node that is
+ * as a U-Boot image, if no OS-type has been declared.
+ */
+ if (!spl_fit_image_get_os(ctx.fit, node, &spl_image->os))
+ debug("Image OS is %s\n", genimg_get_os_name(spl_image->os));
+ else if (!IS_ENABLED(CONFIG_SPL_OS_BOOT))
+ spl_image->os = IH_OS_U_BOOT;
+
+ /*
+ * Booting a next-stage U-Boot may require us to append the FDT.
+ * We allow this to fail, as the U-Boot image might embed its FDT.
+ */
+ if (os_takes_devicetree(spl_image->os)) {
+ ret = spl_fit_append_fdt(spl_image, info, sector, &ctx);
+ if (ret < 0 && spl_image->os != IH_OS_U_BOOT)
+ return ret;
+ }
+
+ firmware_node = node;
+ /* Now check if there are more images for us to load */
+ for (; ; index++) {
+ uint8_t os_type = IH_OS_INVALID;
+
+ node = spl_fit_get_image_node(&ctx, "loadables", index);
+ if (node < 0)
+ break;
+
+ /*
+ * if the firmware is also a loadable, skip it because
+ * it already has been loaded. This is typically the case with
+ * u-boot.img generated by mkimage.
+ */
+ if (firmware_node == node)
+ continue;
+
+ image_info.load_addr = 0;
+ ret = spl_load_fit_image(info, sector, &ctx, node, &image_info);
+ if (ret < 0) {
+ printf("%s: can't load image loadables index %d (ret = %d)\n",
+ __func__, index, ret);
+ return ret;
+ }
+
+ if (spl_fit_image_is_fpga(ctx.fit, node))
+ spl_fit_upload_fpga(&ctx, node, &image_info);
+
+ if (!spl_fit_image_get_os(ctx.fit, node, &os_type))
+ debug("Loadable is %s\n", genimg_get_os_name(os_type));
+
+ if (os_takes_devicetree(os_type)) {
+ spl_fit_append_fdt(&image_info, info, sector, &ctx);
+ spl_image->fdt_addr = image_info.fdt_addr;
+ }
+
+ /*
+ * If the "firmware" image did not provide an entry point,
+ * use the first valid entry point from the loadables.
+ */
+ if (spl_image->entry_point == FDT_ERROR &&
+ image_info.entry_point != FDT_ERROR)
+ spl_image->entry_point = image_info.entry_point;
+
+ /* Record our loadables into the FDT */
+ if (spl_image->fdt_addr)
+ spl_fit_record_loadable(&ctx, index,
+ spl_image->fdt_addr,
+ &image_info);
+ }
+
+ /*
+ * If a platform does not provide CONFIG_SYS_UBOOT_START, U-Boot's
+ * Makefile will set it to 0 and it will end up as the entry point
+ * here. What it actually means is: use the load address.
+ */
+ if (spl_image->entry_point == FDT_ERROR || spl_image->entry_point == 0)
+ spl_image->entry_point = spl_image->load_addr;
+
+ spl_image->flags |= SPL_FIT_FOUND;
+
+ if (IS_ENABLED(CONFIG_IMX_HAB))
+ board_spl_fit_post_load(ctx.fit);
+
+ return 0;
+}
diff --git a/roms/u-boot/common/spl/spl_legacy.c b/roms/u-boot/common/spl/spl_legacy.c
new file mode 100644
index 000000000..82d032680
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_legacy.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <image.h>
+#include <log.h>
+#include <malloc.h>
+#include <spl.h>
+
+#include <lzma/LzmaTypes.h>
+#include <lzma/LzmaDec.h>
+#include <lzma/LzmaTools.h>
+
+#define LZMA_LEN (1 << 20)
+
+int spl_parse_legacy_header(struct spl_image_info *spl_image,
+ const struct image_header *header)
+{
+ u32 header_size = sizeof(struct image_header);
+
+ /* check uImage header CRC */
+ if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK) &&
+ !image_check_hcrc(header)) {
+ puts("SPL: Image header CRC check failed!\n");
+ return -EINVAL;
+ }
+
+ if (spl_image->flags & SPL_COPY_PAYLOAD_ONLY) {
+ /*
+ * On some system (e.g. powerpc), the load-address and
+ * entry-point is located at address 0. We can't load
+ * to 0-0x40. So skip header in this case.
+ */
+ spl_image->load_addr = image_get_load(header);
+ spl_image->entry_point = image_get_ep(header);
+ spl_image->size = image_get_data_size(header);
+ } else {
+ spl_image->entry_point = image_get_ep(header);
+ /* Load including the header */
+ spl_image->load_addr = image_get_load(header) -
+ header_size;
+ spl_image->size = image_get_data_size(header) +
+ header_size;
+ }
+
+#ifdef CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK
+ /* store uImage data length and CRC to check later */
+ spl_image->dcrc_data = image_get_load(header);
+ spl_image->dcrc_length = image_get_data_size(header);
+ spl_image->dcrc = image_get_dcrc(header);
+#endif
+
+ spl_image->os = image_get_os(header);
+ spl_image->name = image_get_name(header);
+ debug(SPL_TPL_PROMPT
+ "payload image: %32s load addr: 0x%lx size: %d\n",
+ spl_image->name, spl_image->load_addr, spl_image->size);
+
+ return 0;
+}
+
+/*
+ * This function is added explicitly to avoid code size increase, when
+ * no compression method is enabled. The compiler will optimize the
+ * following switch/case statement in spl_load_legacy_img() away due to
+ * Dead Code Elimination.
+ */
+static inline int spl_image_get_comp(const struct image_header *hdr)
+{
+ if (IS_ENABLED(CONFIG_SPL_LZMA))
+ return image_get_comp(hdr);
+
+ return IH_COMP_NONE;
+}
+
+int spl_load_legacy_img(struct spl_image_info *spl_image,
+ struct spl_load_info *load, ulong header)
+{
+ __maybe_unused SizeT lzma_len;
+ __maybe_unused void *src;
+ struct image_header hdr;
+ ulong dataptr;
+ int ret;
+
+ /* Read header into local struct */
+ load->read(load, header, sizeof(hdr), &hdr);
+
+ ret = spl_parse_image_header(spl_image, &hdr);
+ if (ret)
+ return ret;
+
+ dataptr = header + sizeof(hdr);
+
+ /* Read image */
+ switch (spl_image_get_comp(&hdr)) {
+ case IH_COMP_NONE:
+ load->read(load, dataptr, spl_image->size,
+ (void *)(unsigned long)spl_image->load_addr);
+ break;
+
+ case IH_COMP_LZMA:
+ lzma_len = LZMA_LEN;
+
+ debug("LZMA: Decompressing %08lx to %08lx\n",
+ dataptr, spl_image->load_addr);
+ src = malloc(spl_image->size);
+ if (!src) {
+ printf("Unable to allocate %d bytes for LZMA\n",
+ spl_image->size);
+ return -ENOMEM;
+ }
+
+ load->read(load, dataptr, spl_image->size, src);
+ ret = lzmaBuffToBuffDecompress((void *)spl_image->load_addr,
+ &lzma_len, src, spl_image->size);
+ if (ret) {
+ printf("LZMA decompression error: %d\n", ret);
+ return ret;
+ }
+
+ spl_image->size = lzma_len;
+ break;
+
+ default:
+ debug("Compression method %s is not supported\n",
+ genimg_get_comp_short_name(image_get_comp(&hdr)));
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/roms/u-boot/common/spl/spl_mmc.c b/roms/u-boot/common/spl/spl_mmc.c
new file mode 100644
index 000000000..add2785b4
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_mmc.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *
+ * Aneesh V <aneesh@ti.com>
+ */
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <part.h>
+#include <spl.h>
+#include <linux/compiler.h>
+#include <errno.h>
+#include <asm/u-boot.h>
+#include <errno.h>
+#include <mmc.h>
+#include <image.h>
+
+static int mmc_load_legacy(struct spl_image_info *spl_image, struct mmc *mmc,
+ ulong sector, struct image_header *header)
+{
+ u32 image_size_sectors;
+ unsigned long count;
+ int ret;
+
+ ret = spl_parse_image_header(spl_image, header);
+ if (ret)
+ return ret;
+
+ /* convert size to sectors - round up */
+ image_size_sectors = (spl_image->size + mmc->read_bl_len - 1) /
+ mmc->read_bl_len;
+
+ /* Read the header too to avoid extra memcpy */
+ count = blk_dread(mmc_get_blk_desc(mmc), sector, image_size_sectors,
+ (void *)(ulong)spl_image->load_addr);
+ debug("read %x sectors to %lx\n", image_size_sectors,
+ spl_image->load_addr);
+ if (count != image_size_sectors)
+ return -EIO;
+
+ return 0;
+}
+
+static ulong h_spl_load_read(struct spl_load_info *load, ulong sector,
+ ulong count, void *buf)
+{
+ struct mmc *mmc = load->dev;
+
+ return blk_dread(mmc_get_blk_desc(mmc), sector, count, buf);
+}
+
+static __maybe_unused unsigned long spl_mmc_raw_uboot_offset(int part)
+{
+#if IS_ENABLED(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR)
+ if (part == 0)
+ return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_DATA_PART_OFFSET;
+#endif
+
+ return 0;
+}
+
+static __maybe_unused
+int mmc_load_image_raw_sector(struct spl_image_info *spl_image,
+ struct mmc *mmc, unsigned long sector)
+{
+ unsigned long count;
+ struct image_header *header;
+ struct blk_desc *bd = mmc_get_blk_desc(mmc);
+ int ret = 0;
+
+ header = spl_get_load_buffer(-sizeof(*header), bd->blksz);
+
+ /* read image header to find the image size & load address */
+ count = blk_dread(bd, sector, 1, header);
+ debug("hdr read sector %lx, count=%lu\n", sector, count);
+ if (count == 0) {
+ ret = -EIO;
+ goto end;
+ }
+
+ if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+ image_get_magic(header) == FDT_MAGIC) {
+ struct spl_load_info load;
+
+ debug("Found FIT\n");
+ load.dev = mmc;
+ load.priv = NULL;
+ load.filename = NULL;
+ load.bl_len = mmc->read_bl_len;
+ load.read = h_spl_load_read;
+ ret = spl_load_simple_fit(spl_image, &load, sector, header);
+ } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) {
+ struct spl_load_info load;
+
+ load.dev = mmc;
+ load.priv = NULL;
+ load.filename = NULL;
+ load.bl_len = mmc->read_bl_len;
+ load.read = h_spl_load_read;
+
+ ret = spl_load_imx_container(spl_image, &load, sector);
+ } else {
+ ret = mmc_load_legacy(spl_image, mmc, sector, header);
+ }
+
+end:
+ if (ret) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ puts("mmc_load_image_raw_sector: mmc block read error\n");
+#endif
+ return -1;
+ }
+
+ return 0;
+}
+
+static int spl_mmc_get_device_index(u32 boot_device)
+{
+ switch (boot_device) {
+ case BOOT_DEVICE_MMC1:
+ return 0;
+ case BOOT_DEVICE_MMC2:
+ case BOOT_DEVICE_MMC2_2:
+ return 1;
+ }
+
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("spl: unsupported mmc boot device.\n");
+#endif
+
+ return -ENODEV;
+}
+
+static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device)
+{
+ int err, mmc_dev;
+
+ mmc_dev = spl_mmc_get_device_index(boot_device);
+ if (mmc_dev < 0)
+ return mmc_dev;
+
+#if CONFIG_IS_ENABLED(DM_MMC)
+ err = mmc_init_device(mmc_dev);
+#else
+ err = mmc_initialize(NULL);
+#endif /* DM_MMC */
+ if (err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("spl: could not initialize mmc. error: %d\n", err);
+#endif
+ return err;
+ }
+ *mmcp = find_mmc_device(mmc_dev);
+ err = *mmcp ? 0 : -ENODEV;
+ if (err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("spl: could not find mmc device %d. error: %d\n",
+ mmc_dev, err);
+#endif
+ return err;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+static int mmc_load_image_raw_partition(struct spl_image_info *spl_image,
+ struct mmc *mmc, int partition,
+ unsigned long sector)
+{
+ struct disk_partition info;
+ int err;
+
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE
+ int type_part;
+ /* Only support MBR so DOS_ENTRY_NUMBERS */
+ for (type_part = 1; type_part <= DOS_ENTRY_NUMBERS; type_part++) {
+ err = part_get_info(mmc_get_blk_desc(mmc), type_part, &info);
+ if (err)
+ continue;
+ if (info.sys_ind ==
+ CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_TYPE) {
+ partition = type_part;
+ break;
+ }
+ }
+#endif
+
+ err = part_get_info(mmc_get_blk_desc(mmc), partition, &info);
+ if (err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ puts("spl: partition error\n");
+#endif
+ return -1;
+ }
+
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+ return mmc_load_image_raw_sector(spl_image, mmc, info.start + sector);
+#else
+ return mmc_load_image_raw_sector(spl_image, mmc, info.start);
+#endif
+}
+#endif
+
+#ifdef CONFIG_SPL_OS_BOOT
+static int mmc_load_image_raw_os(struct spl_image_info *spl_image,
+ struct mmc *mmc)
+{
+ int ret;
+
+#if defined(CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR)
+ unsigned long count;
+
+ count = blk_dread(mmc_get_blk_desc(mmc),
+ CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR,
+ CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS,
+ (void *) CONFIG_SYS_SPL_ARGS_ADDR);
+ if (count != CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ puts("mmc_load_image_raw_os: mmc block read error\n");
+#endif
+ return -1;
+ }
+#endif /* CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR */
+
+ ret = mmc_load_image_raw_sector(spl_image, mmc,
+ CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR);
+ if (ret)
+ return ret;
+
+ if (spl_image->os != IH_OS_LINUX) {
+ puts("Expected Linux image is not found. Trying to start U-boot\n");
+ return -ENOENT;
+ }
+
+ return 0;
+}
+#else
+int spl_start_uboot(void)
+{
+ return 1;
+}
+static int mmc_load_image_raw_os(struct spl_image_info *spl_image,
+ struct mmc *mmc)
+{
+ return -ENOSYS;
+}
+#endif
+
+#ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION
+static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc,
+ const char *filename)
+{
+ int err = -ENOSYS;
+
+#ifdef CONFIG_SPL_FS_FAT
+ if (!spl_start_uboot()) {
+ err = spl_load_image_fat_os(spl_image, mmc_get_blk_desc(mmc),
+ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION);
+ if (!err)
+ return err;
+ }
+#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
+ err = spl_load_image_fat(spl_image, mmc_get_blk_desc(mmc),
+ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION,
+ filename);
+ if (!err)
+ return err;
+#endif
+#endif
+#ifdef CONFIG_SPL_FS_EXT4
+ if (!spl_start_uboot()) {
+ err = spl_load_image_ext_os(spl_image, mmc_get_blk_desc(mmc),
+ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION);
+ if (!err)
+ return err;
+ }
+#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
+ err = spl_load_image_ext(spl_image, mmc_get_blk_desc(mmc),
+ CONFIG_SYS_MMCSD_FS_BOOT_PARTITION,
+ filename);
+ if (!err)
+ return err;
+#endif
+#endif
+
+#if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4)
+ err = -ENOENT;
+#endif
+
+ return err;
+}
+#else
+static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc,
+ const char *filename)
+{
+ return -ENOSYS;
+}
+#endif
+
+u32 __weak spl_mmc_boot_mode(const u32 boot_device)
+{
+#if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4)
+ return MMCSD_MODE_FS;
+#elif defined(CONFIG_SUPPORT_EMMC_BOOT)
+ return MMCSD_MODE_EMMCBOOT;
+#else
+ return MMCSD_MODE_RAW;
+#endif
+}
+
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+int __weak spl_mmc_boot_partition(const u32 boot_device)
+{
+ return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION;
+}
+#endif
+
+unsigned long __weak spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
+ unsigned long raw_sect)
+{
+ return raw_sect;
+}
+
+int spl_mmc_load(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev,
+ const char *filename,
+ int raw_part,
+ unsigned long raw_sect)
+{
+ static struct mmc *mmc;
+ u32 boot_mode;
+ int err = 0;
+ __maybe_unused int part = 0;
+
+ /* Perform peripheral init only once */
+ if (!mmc) {
+ err = spl_mmc_find_device(&mmc, bootdev->boot_device);
+ if (err)
+ return err;
+
+ err = mmc_init(mmc);
+ if (err) {
+ mmc = NULL;
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("spl: mmc init failed with error: %d\n", err);
+#endif
+ return err;
+ }
+ }
+
+ boot_mode = spl_mmc_boot_mode(bootdev->boot_device);
+ err = -EINVAL;
+ switch (boot_mode) {
+ case MMCSD_MODE_EMMCBOOT:
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_EMMC_BOOT_PARTITION
+ part = CONFIG_SYS_MMCSD_RAW_MODE_EMMC_BOOT_PARTITION;
+#else
+ /*
+ * We need to check what the partition is configured to.
+ * 1 and 2 match up to boot0 / boot1 and 7 is user data
+ * which is the first physical partition (0).
+ */
+ part = (mmc->part_config >> 3) & PART_ACCESS_MASK;
+
+ if (part == 7)
+ part = 0;
+#endif
+
+ if (CONFIG_IS_ENABLED(MMC_TINY))
+ err = mmc_switch_part(mmc, part);
+ else
+ err = blk_dselect_hwpart(mmc_get_blk_desc(mmc), part);
+
+ if (err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ puts("spl: mmc partition switch failed\n");
+#endif
+ return err;
+ }
+ /* Fall through */
+ case MMCSD_MODE_RAW:
+ debug("spl: mmc boot mode: raw\n");
+
+ if (!spl_start_uboot()) {
+ err = mmc_load_image_raw_os(spl_image, mmc);
+ if (!err)
+ return err;
+ }
+
+ raw_sect = spl_mmc_get_uboot_raw_sector(mmc, raw_sect);
+
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+ err = mmc_load_image_raw_partition(spl_image, mmc, raw_part,
+ raw_sect);
+ if (!err)
+ return err;
+#endif
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+ err = mmc_load_image_raw_sector(spl_image, mmc,
+ raw_sect + spl_mmc_raw_uboot_offset(part));
+ if (!err)
+ return err;
+#endif
+ /* If RAW mode fails, try FS mode. */
+ case MMCSD_MODE_FS:
+ debug("spl: mmc boot mode: fs\n");
+
+ err = spl_mmc_do_fs_boot(spl_image, mmc, filename);
+ if (!err)
+ return err;
+
+ break;
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ default:
+ puts("spl: mmc: wrong boot mode\n");
+#endif
+ }
+
+ return err;
+}
+
+int spl_mmc_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ return spl_mmc_load(spl_image, bootdev,
+#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
+ CONFIG_SPL_FS_LOAD_PAYLOAD_NAME,
+#else
+ NULL,
+#endif
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION
+ spl_mmc_boot_partition(bootdev->boot_device),
+#else
+ 0,
+#endif
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
+ CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);
+#else
+ 0);
+#endif
+}
+
+SPL_LOAD_IMAGE_METHOD("MMC1", 0, BOOT_DEVICE_MMC1, spl_mmc_load_image);
+SPL_LOAD_IMAGE_METHOD("MMC2", 0, BOOT_DEVICE_MMC2, spl_mmc_load_image);
+SPL_LOAD_IMAGE_METHOD("MMC2_2", 0, BOOT_DEVICE_MMC2_2, spl_mmc_load_image);
diff --git a/roms/u-boot/common/spl/spl_nand.c b/roms/u-boot/common/spl/spl_nand.c
new file mode 100644
index 000000000..59f4a84a3
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_nand.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011
+ * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
+ */
+#include <common.h>
+#include <config.h>
+#include <fdt_support.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <nand.h>
+#include <linux/libfdt_env.h>
+#include <fdt.h>
+
+uint32_t __weak spl_nand_get_uboot_raw_page(void)
+{
+ return CONFIG_SYS_NAND_U_BOOT_OFFS;
+}
+
+#if defined(CONFIG_SPL_NAND_RAW_ONLY)
+static int spl_nand_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ nand_init();
+
+ printf("Loading U-Boot from 0x%08x (size 0x%08x) to 0x%08x\n",
+ CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
+ CONFIG_SYS_NAND_U_BOOT_DST);
+
+ nand_spl_load_image(spl_nand_get_uboot_raw_page(),
+ CONFIG_SYS_NAND_U_BOOT_SIZE,
+ (void *)CONFIG_SYS_NAND_U_BOOT_DST);
+ spl_set_header_raw_uboot(spl_image);
+ nand_deselect();
+
+ return 0;
+}
+#else
+
+static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs,
+ ulong size, void *dst)
+{
+ int err;
+#ifdef CONFIG_SYS_NAND_BLOCK_SIZE
+ ulong sector;
+
+ sector = *(int *)load->priv;
+ offs = sector + nand_spl_adjust_offset(sector, offs - sector);
+#else
+ offs *= load->bl_len;
+ size *= load->bl_len;
+#endif
+ err = nand_spl_load_image(offs, size, dst);
+ if (err)
+ return 0;
+
+ return size / load->bl_len;
+}
+
+struct mtd_info * __weak nand_get_mtd(void)
+{
+ return NULL;
+}
+
+static int spl_nand_load_element(struct spl_image_info *spl_image,
+ int offset, struct image_header *header)
+{
+ struct mtd_info *mtd = nand_get_mtd();
+ int bl_len = mtd ? mtd->writesize : 1;
+ int err;
+
+ err = nand_spl_load_image(offset, sizeof(*header), (void *)header);
+ if (err)
+ return err;
+
+ if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+ image_get_magic(header) == FDT_MAGIC) {
+ struct spl_load_info load;
+
+ debug("Found FIT\n");
+ load.dev = NULL;
+ load.priv = &offset;
+ load.filename = NULL;
+ load.bl_len = bl_len;
+ load.read = spl_nand_fit_read;
+ return spl_load_simple_fit(spl_image, &load, offset / bl_len, header);
+ } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) {
+ struct spl_load_info load;
+
+ load.dev = NULL;
+ load.priv = NULL;
+ load.filename = NULL;
+ load.bl_len = bl_len;
+ load.read = spl_nand_fit_read;
+ return spl_load_imx_container(spl_image, &load, offset / bl_len);
+ } else {
+ err = spl_parse_image_header(spl_image, header);
+ if (err)
+ return err;
+ return nand_spl_load_image(offset, spl_image->size,
+ (void *)(ulong)spl_image->load_addr);
+ }
+}
+
+static int spl_nand_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ int err;
+ struct image_header *header;
+ int *src __attribute__((unused));
+ int *dst __attribute__((unused));
+
+#ifdef CONFIG_SPL_NAND_SOFTECC
+ debug("spl: nand - using sw ecc\n");
+#else
+ debug("spl: nand - using hw ecc\n");
+#endif
+ nand_init();
+
+ header = spl_get_load_buffer(0, sizeof(*header));
+
+#ifdef CONFIG_SPL_OS_BOOT
+ if (!spl_start_uboot()) {
+ /*
+ * load parameter image
+ * load to temp position since nand_spl_load_image reads
+ * a whole block which is typically larger than
+ * CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite
+ * following sections like BSS
+ */
+ nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS,
+ CONFIG_CMD_SPL_WRITE_SIZE,
+ (void *)CONFIG_SYS_TEXT_BASE);
+ /* copy to destintion */
+ for (dst = (int *)CONFIG_SYS_SPL_ARGS_ADDR,
+ src = (int *)CONFIG_SYS_TEXT_BASE;
+ src < (int *)(CONFIG_SYS_TEXT_BASE +
+ CONFIG_CMD_SPL_WRITE_SIZE);
+ src++, dst++) {
+ writel(readl(src), dst);
+ }
+
+ /* load linux */
+ nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
+ sizeof(*header), (void *)header);
+ err = spl_parse_image_header(spl_image, header);
+ if (err)
+ return err;
+ if (header->ih_os == IH_OS_LINUX) {
+ /* happy - was a linux */
+ err = nand_spl_load_image(
+ CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
+ spl_image->size,
+ (void *)spl_image->load_addr);
+ nand_deselect();
+ return err;
+ } else {
+ puts("The Expected Linux image was not "
+ "found. Please check your NAND "
+ "configuration.\n");
+ puts("Trying to start u-boot now...\n");
+ }
+ }
+#endif
+#ifdef CONFIG_NAND_ENV_DST
+ spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET, header);
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET_REDUND, header);
+#endif
+#endif
+ /* Load u-boot */
+ err = spl_nand_load_element(spl_image, spl_nand_get_uboot_raw_page(),
+ header);
+#ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
+#if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
+ if (err)
+ err = spl_nand_load_element(spl_image,
+ CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND,
+ header);
+#endif
+#endif
+ nand_deselect();
+ return err;
+}
+#endif
+/* Use priorty 1 so that Ubi can override this */
+SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);
diff --git a/roms/u-boot/common/spl/spl_net.c b/roms/u-boot/common/spl/spl_net.c
new file mode 100644
index 000000000..e140a6306
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_net.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2012
+ * Ilya Yanok <ilya.yanok@gmail.com>
+ */
+#include <common.h>
+#include <env.h>
+#include <errno.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+#include <net.h>
+#include <linux/libfdt.h>
+
+#if defined(CONFIG_SPL_ETH_SUPPORT) || defined(CONFIG_SPL_USB_ETHER)
+static ulong spl_net_load_read(struct spl_load_info *load, ulong sector,
+ ulong count, void *buf)
+{
+ debug("%s: sector %lx, count %lx, buf %lx\n",
+ __func__, sector, count, (ulong)buf);
+ memcpy(buf, (void *)(image_load_addr + sector), count);
+ return count;
+}
+
+static int spl_net_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ struct image_header *header = (struct image_header *)image_load_addr;
+ int rv;
+
+ env_init();
+ env_relocate();
+ env_set("autoload", "yes");
+ rv = eth_initialize();
+ if (rv == 0) {
+ printf("No Ethernet devices found\n");
+ return -ENODEV;
+ }
+ if (bootdev->boot_device_name)
+ env_set("ethact", bootdev->boot_device_name);
+ rv = net_loop(BOOTP);
+ if (rv < 0) {
+ printf("Problem booting with BOOTP\n");
+ return rv;
+ }
+
+ if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+ image_get_magic(header) == FDT_MAGIC) {
+ struct spl_load_info load;
+
+ debug("Found FIT\n");
+ load.bl_len = 1;
+ load.read = spl_net_load_read;
+ rv = spl_load_simple_fit(spl_image, &load, 0, header);
+ } else {
+ debug("Legacy image\n");
+
+ rv = spl_parse_image_header(spl_image, header);
+ if (rv)
+ return rv;
+
+ memcpy((void *)spl_image->load_addr, header, spl_image->size);
+ }
+
+ return rv;
+}
+#endif
+
+#ifdef CONFIG_SPL_ETH_SUPPORT
+int spl_net_load_image_cpgmac(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+#ifdef CONFIG_SPL_ETH_DEVICE
+ bootdev->boot_device_name = CONFIG_SPL_ETH_DEVICE;
+#endif
+
+ return spl_net_load_image(spl_image, bootdev);
+}
+SPL_LOAD_IMAGE_METHOD("eth device", 0, BOOT_DEVICE_CPGMAC,
+ spl_net_load_image_cpgmac);
+#endif
+
+#ifdef CONFIG_SPL_USB_ETHER
+int spl_net_load_image_usb(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ bootdev->boot_device_name = "usb_ether";
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+ usb_ether_init();
+#endif
+ return spl_net_load_image(spl_image, bootdev);
+}
+SPL_LOAD_IMAGE_METHOD("USB eth", 0, BOOT_DEVICE_USBETH, spl_net_load_image_usb);
+#endif
diff --git a/roms/u-boot/common/spl/spl_nor.c b/roms/u-boot/common/spl/spl_nor.c
new file mode 100644
index 000000000..5270401db
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_nor.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+
+static ulong spl_nor_load_read(struct spl_load_info *load, ulong sector,
+ ulong count, void *buf)
+{
+ debug("%s: sector %lx, count %lx, buf %p\n",
+ __func__, sector, count, buf);
+ memcpy(buf, (void *)sector, count);
+
+ return count;
+}
+
+unsigned long __weak spl_nor_get_uboot_base(void)
+{
+ return CONFIG_SYS_UBOOT_BASE;
+}
+
+static int spl_nor_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ __maybe_unused const struct image_header *header;
+ __maybe_unused struct spl_load_info load;
+
+ /*
+ * Loading of the payload to SDRAM is done with skipping of
+ * the mkimage header in this SPL NOR driver
+ */
+ spl_image->flags |= SPL_COPY_PAYLOAD_ONLY;
+
+#ifdef CONFIG_SPL_OS_BOOT
+ if (!spl_start_uboot()) {
+ /*
+ * Load Linux from its location in NOR flash to its defined
+ * location in SDRAM
+ */
+ header = (const struct image_header *)CONFIG_SYS_OS_BASE;
+#ifdef CONFIG_SPL_LOAD_FIT
+ if (image_get_magic(header) == FDT_MAGIC) {
+ int ret;
+
+ debug("Found FIT\n");
+ load.bl_len = 1;
+ load.read = spl_nor_load_read;
+
+ ret = spl_load_simple_fit(spl_image, &load,
+ CONFIG_SYS_OS_BASE,
+ (void *)header);
+
+#if defined CONFIG_SYS_SPL_ARGS_ADDR && defined CONFIG_CMD_SPL_NOR_OFS
+ memcpy((void *)CONFIG_SYS_SPL_ARGS_ADDR,
+ (void *)CONFIG_CMD_SPL_NOR_OFS,
+ CONFIG_CMD_SPL_WRITE_SIZE);
+#endif
+ return ret;
+ }
+#endif
+ if (image_get_os(header) == IH_OS_LINUX) {
+ /* happy - was a Linux */
+ int ret;
+
+ ret = spl_parse_image_header(spl_image, header);
+ if (ret)
+ return ret;
+
+ memcpy((void *)spl_image->load_addr,
+ (void *)(CONFIG_SYS_OS_BASE +
+ sizeof(struct image_header)),
+ spl_image->size);
+#ifdef CONFIG_SYS_FDT_BASE
+ spl_image->arg = (void *)CONFIG_SYS_FDT_BASE;
+#endif
+
+ return 0;
+ } else {
+ puts("The Expected Linux image was not found.\n"
+ "Please check your NOR configuration.\n"
+ "Trying to start u-boot now...\n");
+ }
+ }
+#endif
+
+ /*
+ * Load real U-Boot from its location in NOR flash to its
+ * defined location in SDRAM
+ */
+#ifdef CONFIG_SPL_LOAD_FIT
+ header = (const struct image_header *)spl_nor_get_uboot_base();
+ if (image_get_magic(header) == FDT_MAGIC) {
+ debug("Found FIT format U-Boot\n");
+ load.bl_len = 1;
+ load.read = spl_nor_load_read;
+ return spl_load_simple_fit(spl_image, &load,
+ spl_nor_get_uboot_base(),
+ (void *)header);
+ }
+#endif
+ if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) {
+ load.bl_len = 1;
+ load.read = spl_nor_load_read;
+ return spl_load_imx_container(spl_image, &load,
+ spl_nor_get_uboot_base());
+ }
+
+ /* Legacy image handling */
+ if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_SUPPORT)) {
+ load.bl_len = 1;
+ load.read = spl_nor_load_read;
+ return spl_load_legacy_img(spl_image, &load,
+ spl_nor_get_uboot_base());
+ }
+
+ return 0;
+}
+SPL_LOAD_IMAGE_METHOD("NOR", 0, BOOT_DEVICE_NOR, spl_nor_load_image);
diff --git a/roms/u-boot/common/spl/spl_onenand.c b/roms/u-boot/common/spl/spl_onenand.c
new file mode 100644
index 000000000..93cbf47e8
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_onenand.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2013
+ * ISEE 2007 SL - Enric Balletbo i Serra <eballetbo@iseebcn.com>
+ *
+ * Based on common/spl/spl_nand.c
+ * Copyright (C) 2011
+ * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
+ */
+#include <common.h>
+#include <config.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <onenand_uboot.h>
+
+static int spl_onenand_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ struct image_header *header;
+ int ret;
+
+ debug("spl: onenand\n");
+
+ header = spl_get_load_buffer(0, CONFIG_SYS_ONENAND_PAGE_SIZE);
+ /* Load u-boot */
+ onenand_spl_load_image(CONFIG_SYS_ONENAND_U_BOOT_OFFS,
+ CONFIG_SYS_ONENAND_PAGE_SIZE, (void *)header);
+ ret = spl_parse_image_header(spl_image, header);
+ if (ret)
+ return ret;
+ onenand_spl_load_image(CONFIG_SYS_ONENAND_U_BOOT_OFFS,
+ spl_image->size, (void *)spl_image->load_addr);
+
+ return 0;
+}
+/* Use priorty 1 so that Ubi can override this */
+SPL_LOAD_IMAGE_METHOD("OneNAND", 1, BOOT_DEVICE_ONENAND,
+ spl_onenand_load_image);
diff --git a/roms/u-boot/common/spl/spl_opensbi.c b/roms/u-boot/common/spl/spl_opensbi.c
new file mode 100644
index 000000000..1c0abf855
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_opensbi.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Fraunhofer AISEC,
+ * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
+ *
+ * Based on common/spl/spl_atf.c
+ */
+#include <common.h>
+#include <cpu_func.h>
+#include <errno.h>
+#include <hang.h>
+#include <image.h>
+#include <spl.h>
+#include <asm/global_data.h>
+#include <asm/smp.h>
+#include <opensbi.h>
+#include <linux/libfdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct fw_dynamic_info opensbi_info;
+
+static int spl_opensbi_find_uboot_node(void *blob, int *uboot_node)
+{
+ int fit_images_node, node;
+ const char *fit_os;
+
+ fit_images_node = fdt_path_offset(blob, "/fit-images");
+ if (fit_images_node < 0)
+ return -ENODEV;
+
+ fdt_for_each_subnode(node, blob, fit_images_node) {
+ fit_os = fdt_getprop(blob, node, FIT_OS_PROP, NULL);
+ if (!fit_os)
+ continue;
+
+ if (genimg_get_os_id(fit_os) == IH_OS_U_BOOT) {
+ *uboot_node = node;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+void spl_invoke_opensbi(struct spl_image_info *spl_image)
+{
+ int ret, uboot_node;
+ ulong uboot_entry;
+ void (*opensbi_entry)(ulong hartid, ulong dtb, ulong info);
+
+ if (!spl_image->fdt_addr) {
+ pr_err("No device tree specified in SPL image\n");
+ hang();
+ }
+
+ /* Find U-Boot image in /fit-images */
+ ret = spl_opensbi_find_uboot_node(spl_image->fdt_addr, &uboot_node);
+ if (ret) {
+ pr_err("Can't find U-Boot node, %d\n", ret);
+ hang();
+ }
+
+ /* Get U-Boot entry point */
+ ret = fit_image_get_entry(spl_image->fdt_addr, uboot_node, &uboot_entry);
+ if (ret)
+ ret = fit_image_get_load(spl_image->fdt_addr, uboot_node, &uboot_entry);
+
+ /* Prepare obensbi_info object */
+ opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE;
+ opensbi_info.version = FW_DYNAMIC_INFO_VERSION;
+ opensbi_info.next_addr = uboot_entry;
+ opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S;
+ opensbi_info.options = SBI_SCRATCH_NO_BOOT_PRINTS;
+ opensbi_info.boot_hart = gd->arch.boot_hart;
+
+ opensbi_entry = (void (*)(ulong, ulong, ulong))spl_image->entry_point;
+ invalidate_icache_all();
+
+#ifdef CONFIG_SPL_SMP
+ /*
+ * Start OpenSBI on all secondary harts and wait for acknowledgment.
+ *
+ * OpenSBI first relocates itself to its link address. This is done by
+ * the main hart. To make sure no hart is still running U-Boot SPL
+ * during relocation, we wait for all secondary harts to acknowledge
+ * the call-function request before entering OpenSBI on the main hart.
+ * Otherwise, code corruption can occur if the link address ranges of
+ * U-Boot SPL and OpenSBI overlap.
+ */
+ ret = smp_call_function((ulong)spl_image->entry_point,
+ (ulong)spl_image->fdt_addr,
+ (ulong)&opensbi_info, 1);
+ if (ret)
+ hang();
+#endif
+ opensbi_entry(gd->arch.boot_hart, (ulong)spl_image->fdt_addr,
+ (ulong)&opensbi_info);
+}
diff --git a/roms/u-boot/common/spl/spl_optee.S b/roms/u-boot/common/spl/spl_optee.S
new file mode 100644
index 000000000..8bd1949dd
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_optee.S
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2017 Rockchip Electronic Co.,Ltd
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ENTRY(spl_optee_entry)
+ ldr lr, =CONFIG_SYS_TEXT_BASE
+ mov pc, r3
+ENDPROC(spl_optee_entry)
diff --git a/roms/u-boot/common/spl/spl_ram.c b/roms/u-boot/common/spl/spl_ram.c
new file mode 100644
index 000000000..df1d5b43d
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_ram.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016
+ * Xilinx, Inc.
+ *
+ * (C) Copyright 2016
+ * Toradex AG
+ *
+ * Michal Simek <michal.simek@xilinx.com>
+ * Stefan Agner <stefan.agner@toradex.com>
+ */
+#include <common.h>
+#include <binman_sym.h>
+#include <image.h>
+#include <log.h>
+#include <mapmem.h>
+#include <spl.h>
+#include <linux/libfdt.h>
+
+#ifndef CONFIG_SPL_LOAD_FIT_ADDRESS
+# define CONFIG_SPL_LOAD_FIT_ADDRESS 0
+#endif
+
+static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector,
+ ulong count, void *buf)
+{
+ debug("%s: sector %lx, count %lx, buf %lx\n",
+ __func__, sector, count, (ulong)buf);
+ memcpy(buf, (void *)(CONFIG_SPL_LOAD_FIT_ADDRESS + sector), count);
+ return count;
+}
+
+static int spl_ram_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ struct image_header *header;
+
+ header = (struct image_header *)CONFIG_SPL_LOAD_FIT_ADDRESS;
+
+#if CONFIG_IS_ENABLED(DFU)
+ if (bootdev->boot_device == BOOT_DEVICE_DFU)
+ spl_dfu_cmd(0, "dfu_alt_info_ram", "ram", "0");
+#endif
+
+ if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+ image_get_magic(header) == FDT_MAGIC) {
+ struct spl_load_info load;
+
+ debug("Found FIT\n");
+ load.bl_len = 1;
+ load.read = spl_ram_load_read;
+ spl_load_simple_fit(spl_image, &load, 0, header);
+ } else {
+ ulong u_boot_pos = binman_sym(ulong, u_boot_any, image_pos);
+
+ debug("Legacy image\n");
+ /*
+ * Get the header. It will point to an address defined by
+ * handoff which will tell where the image located inside
+ * the flash.
+ */
+ debug("u_boot_pos = %lx\n", u_boot_pos);
+ if (u_boot_pos == BINMAN_SYM_MISSING) {
+ /*
+ * No binman support or no information. For now, fix it
+ * to the address pointed to by U-Boot.
+ */
+ u_boot_pos = (ulong)spl_get_load_buffer(-sizeof(*header),
+ sizeof(*header));
+ }
+ header = (struct image_header *)map_sysmem(u_boot_pos, 0);
+
+ spl_parse_image_header(spl_image, header);
+ }
+
+ return 0;
+}
+#if CONFIG_IS_ENABLED(RAM_DEVICE)
+SPL_LOAD_IMAGE_METHOD("RAM", 0, BOOT_DEVICE_RAM, spl_ram_load_image);
+#endif
+#if CONFIG_IS_ENABLED(DFU)
+SPL_LOAD_IMAGE_METHOD("DFU", 0, BOOT_DEVICE_DFU, spl_ram_load_image);
+#endif
+
+
diff --git a/roms/u-boot/common/spl/spl_sata.c b/roms/u-boot/common/spl/spl_sata.c
new file mode 100644
index 000000000..e108af057
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_sata.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2013
+ * Texas Instruments, <www.ti.com>
+ *
+ * Dan Murphy <dmurphy@ti.com>
+ *
+ * Derived work from spl_usb.c
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/u-boot.h>
+#include <sata.h>
+#include <scsi.h>
+#include <errno.h>
+#include <fat.h>
+#include <image.h>
+
+#ifndef CONFIG_SYS_SATA_FAT_BOOT_PARTITION
+#define CONFIG_SYS_SATA_FAT_BOOT_PARTITION 1
+#endif
+
+#ifndef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
+#define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "u-boot.img"
+#endif
+
+#ifndef CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR
+/* Dummy value to make the compiler happy */
+#define CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR 0x100
+#endif
+
+static int spl_sata_load_image_raw(struct spl_image_info *spl_image,
+ struct blk_desc *stor_dev, unsigned long sector)
+{
+ struct image_header *header;
+ unsigned long count;
+ u32 image_size_sectors;
+ int ret;
+
+ header = spl_get_load_buffer(-sizeof(*header), stor_dev->blksz);
+ count = blk_dread(stor_dev, sector, 1, header);
+ if (count == 0)
+ return -EIO;
+
+ ret = spl_parse_image_header(spl_image, header);
+ if (ret)
+ return ret;
+
+ image_size_sectors = DIV_ROUND_UP(spl_image->size, stor_dev->blksz);
+ count = blk_dread(stor_dev, sector, image_size_sectors,
+ (void *)spl_image->load_addr);
+ if (count != image_size_sectors)
+ return -EIO;
+
+ return 0;
+}
+
+static int spl_sata_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ int err = 0;
+ struct blk_desc *stor_dev;
+
+#if !defined(CONFIG_DM_SCSI) && !defined(CONFIG_AHCI)
+ err = init_sata(CONFIG_SPL_SATA_BOOT_DEVICE);
+#endif
+ if (err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("spl: sata init failed: err - %d\n", err);
+#endif
+ return err;
+ } else {
+ /* try to recognize storage devices immediately */
+ scsi_scan(false);
+ stor_dev = blk_get_devnum_by_type(IF_TYPE_SCSI, 0);
+ if (!stor_dev)
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_SPL_OS_BOOT
+ if (spl_start_uboot() ||
+ spl_load_image_fat_os(spl_image, stor_dev,
+ CONFIG_SYS_SATA_FAT_BOOT_PARTITION))
+#endif
+ {
+ err = -ENOSYS;
+
+ if (IS_ENABLED(CONFIG_SPL_FS_FAT)) {
+ err = spl_load_image_fat(spl_image, stor_dev,
+ CONFIG_SYS_SATA_FAT_BOOT_PARTITION,
+ CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
+ } else if (IS_ENABLED(CONFIG_SPL_SATA_RAW_U_BOOT_USE_SECTOR)) {
+ err = spl_sata_load_image_raw(spl_image, stor_dev,
+ CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR);
+ }
+ }
+ if (err) {
+ puts("Error loading sata device\n");
+ return err;
+ }
+
+ return 0;
+}
+SPL_LOAD_IMAGE_METHOD("SATA", 0, BOOT_DEVICE_SATA, spl_sata_load_image);
diff --git a/roms/u-boot/common/spl/spl_sdp.c b/roms/u-boot/common/spl/spl_sdp.c
new file mode 100644
index 000000000..ae9c09883
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_sdp.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Toradex
+ * Author: Stefan Agner <stefan.agner@toradex.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <spl.h>
+#include <usb.h>
+#include <g_dnl.h>
+#include <sdp.h>
+
+static int spl_sdp_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ int ret;
+ const int controller_index = CONFIG_SPL_SDP_USB_DEV;
+
+ usb_gadget_initialize(controller_index);
+
+ board_usb_init(0, USB_INIT_DEVICE);
+
+ g_dnl_clear_detach();
+ ret = g_dnl_register("usb_dnl_sdp");
+ if (ret) {
+ pr_err("SDP dnl register failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = sdp_init(controller_index);
+ if (ret) {
+ pr_err("SDP init failed: %d\n", ret);
+ return -ENODEV;
+ }
+
+ /*
+ * This command either loads a legacy image, jumps and never returns,
+ * or it loads a FIT image and returns it to be handled by the SPL
+ * code.
+ */
+ ret = spl_sdp_handle(controller_index, spl_image);
+ debug("SDP ended\n");
+
+ usb_gadget_release(controller_index);
+ return ret;
+}
+SPL_LOAD_IMAGE_METHOD("USB SDP", 0, BOOT_DEVICE_BOARD, spl_sdp_load_image);
diff --git a/roms/u-boot/common/spl/spl_spi.c b/roms/u-boot/common/spl/spl_spi.c
new file mode 100644
index 000000000..6a4e03328
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_spi.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 OMICRON electronics GmbH
+ *
+ * based on drivers/mtd/nand/raw/nand_spl_load.c
+ *
+ * Copyright (C) 2011
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ */
+
+#include <common.h>
+#include <image.h>
+#include <log.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <errno.h>
+#include <spl.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SPL_OS_BOOT
+/*
+ * Load the kernel, check for a valid header we can parse, and if found load
+ * the kernel and then device tree.
+ */
+static int spi_load_image_os(struct spl_image_info *spl_image,
+ struct spi_flash *flash,
+ struct image_header *header)
+{
+ int err;
+
+ /* Read for a header, parse or error out. */
+ spi_flash_read(flash, CONFIG_SYS_SPI_KERNEL_OFFS, sizeof(*header),
+ (void *)header);
+
+ if (image_get_magic(header) != IH_MAGIC)
+ return -1;
+
+ err = spl_parse_image_header(spl_image, header);
+ if (err)
+ return err;
+
+ spi_flash_read(flash, CONFIG_SYS_SPI_KERNEL_OFFS,
+ spl_image->size, (void *)spl_image->load_addr);
+
+ /* Read device tree. */
+ spi_flash_read(flash, CONFIG_SYS_SPI_ARGS_OFFS,
+ CONFIG_SYS_SPI_ARGS_SIZE,
+ (void *)CONFIG_SYS_SPL_ARGS_ADDR);
+
+ return 0;
+}
+#endif
+
+static ulong spl_spi_fit_read(struct spl_load_info *load, ulong sector,
+ ulong count, void *buf)
+{
+ struct spi_flash *flash = load->dev;
+ ulong ret;
+
+ ret = spi_flash_read(flash, sector, count, buf);
+ if (!ret)
+ return count;
+ else
+ return 0;
+}
+
+unsigned int __weak spl_spi_get_uboot_offs(struct spi_flash *flash)
+{
+ return CONFIG_SYS_SPI_U_BOOT_OFFS;
+}
+
+/*
+ * The main entry for SPI booting. It's necessary that SDRAM is already
+ * configured and available since this code loads the main U-Boot image
+ * from SPI into SDRAM and starts it from there.
+ */
+static int spl_spi_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ int err = 0;
+ unsigned int payload_offs;
+ struct spi_flash *flash;
+ struct image_header *header;
+
+ /*
+ * Load U-Boot image from SPI flash into RAM
+ * In DM mode: defaults speed and mode will be
+ * taken from DT when available
+ */
+
+ flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
+ CONFIG_SF_DEFAULT_CS,
+ CONFIG_SF_DEFAULT_SPEED,
+ CONFIG_SF_DEFAULT_MODE);
+ if (!flash) {
+ puts("SPI probe failed.\n");
+ return -ENODEV;
+ }
+
+ payload_offs = spl_spi_get_uboot_offs(flash);
+
+ header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ payload_offs = fdtdec_get_config_int(gd->fdt_blob,
+ "u-boot,spl-payload-offset",
+ payload_offs);
+#endif
+
+#ifdef CONFIG_SPL_OS_BOOT
+ if (spl_start_uboot() || spi_load_image_os(spl_image, flash, header))
+#endif
+ {
+ /* Load u-boot, mkimage header is 64 bytes. */
+ err = spi_flash_read(flash, payload_offs, sizeof(*header),
+ (void *)header);
+ if (err) {
+ debug("%s: Failed to read from SPI flash (err=%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) &&
+ image_get_magic(header) == FDT_MAGIC) {
+ err = spi_flash_read(flash, payload_offs,
+ roundup(fdt_totalsize(header), 4),
+ (void *)CONFIG_SYS_LOAD_ADDR);
+ if (err)
+ return err;
+ err = spl_parse_image_header(spl_image,
+ (struct image_header *)CONFIG_SYS_LOAD_ADDR);
+ } else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+ image_get_magic(header) == FDT_MAGIC) {
+ struct spl_load_info load;
+
+ debug("Found FIT\n");
+ load.dev = flash;
+ load.priv = NULL;
+ load.filename = NULL;
+ load.bl_len = 1;
+ load.read = spl_spi_fit_read;
+ err = spl_load_simple_fit(spl_image, &load,
+ payload_offs,
+ header);
+ } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) {
+ struct spl_load_info load;
+
+ load.dev = flash;
+ load.priv = NULL;
+ load.filename = NULL;
+ load.bl_len = 1;
+ load.read = spl_spi_fit_read;
+
+ err = spl_load_imx_container(spl_image, &load,
+ payload_offs);
+ } else {
+ err = spl_parse_image_header(spl_image, header);
+ if (err)
+ return err;
+ err = spi_flash_read(flash, payload_offs,
+ spl_image->size,
+ (void *)spl_image->load_addr);
+ }
+ }
+
+ return err;
+}
+/* Use priorty 1 so that boards can override this */
+SPL_LOAD_IMAGE_METHOD("SPI", 1, BOOT_DEVICE_SPI, spl_spi_load_image);
diff --git a/roms/u-boot/common/spl/spl_ubi.c b/roms/u-boot/common/spl/spl_ubi.c
new file mode 100644
index 000000000..de6a63bd2
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_ubi.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2016
+ * Ladislav Michl <ladis@linux-mips.org>
+ */
+
+#include <common.h>
+#include <config.h>
+#include <image.h>
+#include <nand.h>
+#include <onenand_uboot.h>
+#include <ubispl.h>
+#include <spl.h>
+
+int spl_ubi_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ struct image_header *header;
+ struct ubispl_info info;
+ struct ubispl_load volumes[2];
+ int ret = 1;
+
+ switch (bootdev->boot_device) {
+#ifdef CONFIG_SPL_NAND_SUPPORT
+ case BOOT_DEVICE_NAND:
+ nand_init();
+ info.read = nand_spl_read_block;
+ info.peb_size = CONFIG_SYS_NAND_BLOCK_SIZE;
+ break;
+#endif
+#ifdef CONFIG_SPL_ONENAND_SUPPORT
+ case BOOT_DEVICE_ONENAND:
+ info.read = onenand_spl_read_block;
+ info.peb_size = CONFIG_SYS_ONENAND_BLOCK_SIZE;
+ break;
+#endif
+ default:
+ goto out;
+ }
+ info.ubi = (struct ubi_scan_info *)CONFIG_SPL_UBI_INFO_ADDR;
+ info.fastmap = IS_ENABLED(CONFIG_MTD_UBI_FASTMAP);
+
+ info.peb_offset = CONFIG_SPL_UBI_PEB_OFFSET;
+ info.vid_offset = CONFIG_SPL_UBI_VID_OFFSET;
+ info.leb_start = CONFIG_SPL_UBI_LEB_START;
+ info.peb_count = CONFIG_SPL_UBI_MAX_PEBS - info.peb_offset;
+
+#ifdef CONFIG_SPL_OS_BOOT
+ if (!spl_start_uboot()) {
+ volumes[0].vol_id = CONFIG_SPL_UBI_LOAD_KERNEL_ID;
+ volumes[0].load_addr = (void *)CONFIG_SYS_LOAD_ADDR;
+ volumes[1].vol_id = CONFIG_SPL_UBI_LOAD_ARGS_ID;
+ volumes[1].load_addr = (void *)CONFIG_SYS_SPL_ARGS_ADDR;
+
+ ret = ubispl_load_volumes(&info, volumes, 2);
+ if (!ret) {
+ header = (struct image_header *)volumes[0].load_addr;
+ spl_parse_image_header(spl_image, header);
+ puts("Linux loaded.\n");
+ goto out;
+ }
+ puts("Loading Linux failed, falling back to U-Boot.\n");
+ }
+#endif
+ header = spl_get_load_buffer(-sizeof(*header), sizeof(header));
+#ifdef CONFIG_SPL_UBI_LOAD_BY_VOLNAME
+ volumes[0].vol_id = -1;
+ strncpy(volumes[0].name,
+ CONFIG_SPL_UBI_LOAD_MONITOR_VOLNAME,
+ UBI_VOL_NAME_MAX + 1);
+#else
+ volumes[0].vol_id = CONFIG_SPL_UBI_LOAD_MONITOR_ID;
+#endif
+ volumes[0].load_addr = (void *)header;
+
+ ret = ubispl_load_volumes(&info, volumes, 1);
+ if (!ret)
+ spl_parse_image_header(spl_image, header);
+out:
+#ifdef CONFIG_SPL_NAND_SUPPORT
+ if (bootdev->boot_device == BOOT_DEVICE_NAND)
+ nand_deselect();
+#endif
+ return ret;
+}
+/* Use priorty 0 so that Ubi will override NAND and ONENAND methods */
+SPL_LOAD_IMAGE_METHOD("NAND", 0, BOOT_DEVICE_NAND, spl_ubi_load_image);
+SPL_LOAD_IMAGE_METHOD("OneNAND", 0, BOOT_DEVICE_ONENAND, spl_ubi_load_image);
diff --git a/roms/u-boot/common/spl/spl_usb.c b/roms/u-boot/common/spl/spl_usb.c
new file mode 100644
index 000000000..3648de349
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_usb.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2014
+ * Texas Instruments, <www.ti.com>
+ *
+ * Dan Murphy <dmurphy@ti.com>
+ *
+ * Derived work from spl_mmc.c
+ */
+
+#include <common.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/u-boot.h>
+#include <errno.h>
+#include <usb.h>
+#include <fat.h>
+
+static int usb_stor_curr_dev = -1; /* current device */
+
+int spl_usb_load(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev, int partition,
+ const char *filename)
+{
+ int err = 0;
+ struct blk_desc *stor_dev;
+ static bool usb_init_pending = true;
+
+ if (usb_init_pending) {
+ usb_stop();
+ err = usb_init();
+ usb_init_pending = false;
+ }
+
+ if (err) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+ printf("%s: usb init failed: err - %d\n", __func__, err);
+#endif
+ return err;
+ }
+
+ /* try to recognize storage devices immediately */
+ usb_stor_curr_dev = usb_stor_scan(1);
+ stor_dev = blk_get_devnum_by_type(IF_TYPE_USB, usb_stor_curr_dev);
+ if (!stor_dev)
+ return -ENODEV;
+
+ debug("boot mode - FAT\n");
+
+#ifdef CONFIG_SPL_OS_BOOT
+ if (spl_start_uboot() ||
+ spl_load_image_fat_os(spl_image, stor_dev, partition))
+#endif
+ {
+ err = spl_load_image_fat(spl_image, stor_dev, partition, filename);
+ }
+
+ if (err) {
+ puts("Error loading from USB device\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int spl_usb_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ return spl_usb_load(spl_image, bootdev,
+ CONFIG_SYS_USB_FAT_BOOT_PARTITION,
+ CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
+}
+SPL_LOAD_IMAGE_METHOD("USB", 0, BOOT_DEVICE_USB, spl_usb_load_image);
diff --git a/roms/u-boot/common/spl/spl_xip.c b/roms/u-boot/common/spl/spl_xip.c
new file mode 100644
index 000000000..8ce0a09ef
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_xip.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
+ */
+
+#include <common.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+
+static int spl_xip(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+#ifdef CONFIG_SPL_OS_BOOT
+ if (!spl_start_uboot()) {
+ spl_image->arg = (void *)CONFIG_SYS_FDT_BASE;
+ spl_image->name = "Linux";
+ spl_image->os = IH_OS_LINUX;
+ spl_image->load_addr = CONFIG_SYS_LOAD_ADDR;
+ spl_image->entry_point = CONFIG_SYS_LOAD_ADDR;
+ debug("spl: payload xipImage, load addr: 0x%lx\n",
+ spl_image->load_addr);
+ return 0;
+ }
+#endif
+ return(spl_parse_image_header(spl_image, (const struct image_header *)
+ CONFIG_SYS_UBOOT_BASE));
+}
+SPL_LOAD_IMAGE_METHOD("XIP", 0, BOOT_DEVICE_XIP, spl_xip);
diff --git a/roms/u-boot/common/spl/spl_ymodem.c b/roms/u-boot/common/spl/spl_ymodem.c
new file mode 100644
index 000000000..e979f780a
--- /dev/null
+++ b/roms/u-boot/common/spl/spl_ymodem.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2011
+ * Texas Instruments, <www.ti.com>
+ *
+ * Matt Porter <mporter@ti.com>
+ */
+#include <common.h>
+#include <gzip.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+#include <xyzModem.h>
+#include <asm/u-boot.h>
+#include <linux/libfdt.h>
+
+#define BUF_SIZE 1024
+
+/*
+ * Information required to load image using ymodem.
+ *
+ * @image_read: Now of bytes read from the image.
+ * @buf: pointer to the previous read block.
+ */
+struct ymodem_fit_info {
+ int image_read;
+ char *buf;
+};
+
+static int getcymodem(void) {
+ if (tstc())
+ return (getchar());
+ return -1;
+}
+
+static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset,
+ ulong size, void *addr)
+{
+ int res, err, buf_offset;
+ struct ymodem_fit_info *info = load->priv;
+ char *buf = info->buf;
+
+ while (info->image_read < offset) {
+ res = xyzModem_stream_read(buf, BUF_SIZE, &err);
+ if (res <= 0)
+ break;
+
+ info->image_read += res;
+ }
+
+ if (info->image_read > offset) {
+ res = info->image_read - offset;
+ if (info->image_read % BUF_SIZE)
+ buf_offset = (info->image_read % BUF_SIZE);
+ else
+ buf_offset = BUF_SIZE;
+ memcpy(addr, &buf[buf_offset - res], res);
+ addr = addr + res;
+ }
+
+ while (info->image_read < offset + size) {
+ res = xyzModem_stream_read(buf, BUF_SIZE, &err);
+ if (res <= 0)
+ break;
+
+ memcpy(addr, buf, res);
+ info->image_read += res;
+ addr += res;
+ }
+
+ return size;
+}
+
+int spl_ymodem_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ ulong size = 0;
+ int err;
+ int res;
+ int ret;
+ connection_info_t info;
+ char buf[BUF_SIZE];
+ struct image_header *ih = NULL;
+ ulong addr = 0;
+
+ info.mode = xyzModem_ymodem;
+ ret = xyzModem_stream_open(&info, &err);
+ if (ret) {
+ printf("spl: ymodem err - %s\n", xyzModem_error(err));
+ return ret;
+ }
+
+ res = xyzModem_stream_read(buf, BUF_SIZE, &err);
+ if (res <= 0)
+ goto end_stream;
+
+ if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) &&
+ image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
+ addr = CONFIG_SYS_LOAD_ADDR;
+ ih = (struct image_header *)addr;
+
+ memcpy((void *)addr, buf, res);
+ size += res;
+ addr += res;
+
+ while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) {
+ memcpy((void *)addr, buf, res);
+ size += res;
+ addr += res;
+ }
+
+ ret = spl_parse_image_header(spl_image, ih);
+ if (ret)
+ return ret;
+ } else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+ image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
+ struct spl_load_info load;
+ struct ymodem_fit_info info;
+
+ debug("Found FIT\n");
+ load.dev = NULL;
+ load.priv = (void *)&info;
+ load.filename = NULL;
+ load.bl_len = 1;
+ info.buf = buf;
+ info.image_read = BUF_SIZE;
+ load.read = ymodem_read_fit;
+ ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf);
+ size = info.image_read;
+
+ while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0)
+ size += res;
+ } else {
+ ih = (struct image_header *)buf;
+ ret = spl_parse_image_header(spl_image, ih);
+ if (ret)
+ goto end_stream;
+#ifdef CONFIG_SPL_GZIP
+ if (ih->ih_comp == IH_COMP_GZIP)
+ addr = CONFIG_SYS_LOAD_ADDR;
+ else
+#endif
+ addr = spl_image->load_addr;
+ memcpy((void *)addr, buf, res);
+ ih = (struct image_header *)addr;
+ size += res;
+ addr += res;
+
+ while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) {
+ memcpy((void *)addr, buf, res);
+ size += res;
+ addr += res;
+ }
+ }
+
+end_stream:
+ xyzModem_stream_close(&err);
+ xyzModem_stream_terminate(false, &getcymodem);
+
+ printf("Loaded %lu bytes\n", size);
+
+#ifdef CONFIG_SPL_GZIP
+ if (!(IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+ image_get_magic((struct image_header *)buf) == FDT_MAGIC) &&
+ (ih->ih_comp == IH_COMP_GZIP)) {
+ if (gunzip((void *)(spl_image->load_addr + sizeof(*ih)),
+ CONFIG_SYS_BOOTM_LEN,
+ (void *)(CONFIG_SYS_LOAD_ADDR + sizeof(*ih)),
+ &size)) {
+ puts("Uncompressing error\n");
+ return -EIO;
+ }
+ }
+#endif
+
+ return ret;
+}
+SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image);
diff --git a/roms/u-boot/common/splash.c b/roms/u-boot/common/splash.c
new file mode 100644
index 000000000..2b9313e03
--- /dev/null
+++ b/roms/u-boot/common/splash.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2013, Boundary Devices <info@boundarydevices.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program 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 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/
+ *
+ */
+
+#include <common.h>
+#include <env.h>
+#include <splash.h>
+#include <lcd.h>
+
+static struct splash_location default_splash_locations[] = {
+ {
+ .name = "sf",
+ .storage = SPLASH_STORAGE_SF,
+ .flags = SPLASH_STORAGE_RAW,
+ .offset = 0x0,
+ },
+ {
+ .name = "mmc_fs",
+ .storage = SPLASH_STORAGE_MMC,
+ .flags = SPLASH_STORAGE_FS,
+ .devpart = "0:1",
+ },
+ {
+ .name = "usb_fs",
+ .storage = SPLASH_STORAGE_USB,
+ .flags = SPLASH_STORAGE_FS,
+ .devpart = "0:1",
+ },
+ {
+ .name = "sata_fs",
+ .storage = SPLASH_STORAGE_SATA,
+ .flags = SPLASH_STORAGE_FS,
+ .devpart = "0:1",
+ },
+};
+
+#if defined(CONFIG_DM_VIDEO) && defined(CONFIG_VIDEO_LOGO)
+
+#include <bmp_logo_data.h>
+
+static int splash_video_logo_load(void)
+{
+ char *splashimage;
+ ulong bmp_load_addr;
+
+ splashimage = env_get("splashimage");
+ if (!splashimage)
+ return -ENOENT;
+
+ bmp_load_addr = simple_strtoul(splashimage, 0, 16);
+ if (!bmp_load_addr) {
+ printf("Error: bad 'splashimage' address\n");
+ return -EFAULT;
+ }
+
+ memcpy((void *)bmp_load_addr, bmp_logo_bitmap,
+ ARRAY_SIZE(bmp_logo_bitmap));
+
+ return 0;
+}
+#else
+static inline int splash_video_logo_load(void) { return -ENOSYS; }
+#endif
+
+__weak int splash_screen_prepare(void)
+{
+ if (CONFIG_IS_ENABLED(SPLASH_SOURCE))
+ return splash_source_load(default_splash_locations,
+ ARRAY_SIZE(default_splash_locations));
+
+ return splash_video_logo_load();
+}
+
+#ifdef CONFIG_SPLASH_SCREEN_ALIGN
+void splash_get_pos(int *x, int *y)
+{
+ char *s = env_get("splashpos");
+
+ if (!s)
+ return;
+
+ if (s[0] == 'm')
+ *x = BMP_ALIGN_CENTER;
+ else
+ *x = simple_strtol(s, NULL, 0);
+
+ s = strchr(s + 1, ',');
+ if (s != NULL) {
+ if (s[1] == 'm')
+ *y = BMP_ALIGN_CENTER;
+ else
+ *y = simple_strtol(s + 1, NULL, 0);
+ }
+}
+#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
+
+#if defined(CONFIG_DM_VIDEO) && !defined(CONFIG_HIDE_LOGO_VERSION)
+
+#ifdef CONFIG_VIDEO_LOGO
+#include <bmp_logo.h>
+#endif
+#include <dm.h>
+#include <video_console.h>
+#include <video_font.h>
+
+void splash_display_banner(void)
+{
+ struct udevice *dev;
+ char buf[DISPLAY_OPTIONS_BANNER_LENGTH];
+ int col, row, ret;
+
+ ret = uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &dev);
+ if (ret)
+ return;
+
+#ifdef CONFIG_VIDEO_LOGO
+ col = BMP_LOGO_WIDTH / VIDEO_FONT_WIDTH + 1;
+ row = BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT + 1;
+#else
+ col = 0;
+ row = 0;
+#endif
+
+ display_options_get_banner(false, buf, sizeof(buf));
+ vidconsole_position_cursor(dev, col, 1);
+ vidconsole_put_string(dev, buf);
+ vidconsole_position_cursor(dev, 0, row);
+}
+#endif /* CONFIG_DM_VIDEO && !CONFIG_HIDE_LOGO_VERSION */
+
+/*
+ * Common function to show a splash image if env("splashimage") is set.
+ * Is used for both dm_video and lcd video stacks. For additional
+ * details please refer to doc/README.splashprepare.
+ */
+#if defined(CONFIG_SPLASH_SCREEN) && defined(CONFIG_CMD_BMP)
+int splash_display(void)
+{
+ ulong addr;
+ char *s;
+ int x = 0, y = 0, ret;
+
+ s = env_get("splashimage");
+ if (!s)
+ return -EINVAL;
+
+ addr = simple_strtoul(s, NULL, 16);
+ ret = splash_screen_prepare();
+ if (ret)
+ return ret;
+
+ splash_get_pos(&x, &y);
+
+ ret = bmp_display(addr, x, y);
+
+ /* Skip banner output on video console if the logo is not at 0,0 */
+ if (x || y)
+ goto end;
+
+#if defined(CONFIG_DM_VIDEO) && !defined(CONFIG_HIDE_LOGO_VERSION)
+ splash_display_banner();
+#endif
+end:
+ return ret;
+}
+#endif
diff --git a/roms/u-boot/common/splash_source.c b/roms/u-boot/common/splash_source.c
new file mode 100644
index 000000000..3cf926d91
--- /dev/null
+++ b/roms/u-boot/common/splash_source.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2014 CompuLab, Ltd. <www.compulab.co.il>
+ *
+ * Authors: Igor Grinberg <grinberg@compulab.co.il>
+ */
+
+#include <common.h>
+#include <bmp_layout.h>
+#include <command.h>
+#include <env.h>
+#include <errno.h>
+#include <fs.h>
+#include <fdt_support.h>
+#include <image.h>
+#include <log.h>
+#include <nand.h>
+#include <sata.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <splash.h>
+#include <usb.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SPI_FLASH
+static struct spi_flash *sf;
+static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
+{
+ if (!sf) {
+ sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
+ CONFIG_SF_DEFAULT_CS,
+ CONFIG_SF_DEFAULT_SPEED,
+ CONFIG_SF_DEFAULT_MODE);
+ if (!sf)
+ return -ENODEV;
+ }
+
+ return spi_flash_read(sf, offset, read_size, (void *)(uintptr_t)bmp_load_addr);
+}
+#else
+static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
+{
+ debug("%s: sf support not available\n", __func__);
+ return -ENOSYS;
+}
+#endif
+
+#ifdef CONFIG_CMD_NAND
+static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
+{
+ struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device);
+ return nand_read_skip_bad(mtd, offset,
+ &read_size, NULL,
+ mtd->size,
+ (u_char *)bmp_load_addr);
+}
+#else
+static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
+{
+ debug("%s: nand support not available\n", __func__);
+ return -ENOSYS;
+}
+#endif
+
+static int splash_storage_read_raw(struct splash_location *location,
+ u32 bmp_load_addr, size_t read_size)
+{
+ u32 offset;
+
+ if (!location)
+ return -EINVAL;
+
+ offset = location->offset;
+ switch (location->storage) {
+ case SPLASH_STORAGE_NAND:
+ return splash_nand_read_raw(bmp_load_addr, offset, read_size);
+ case SPLASH_STORAGE_SF:
+ return splash_sf_read_raw(bmp_load_addr, offset, read_size);
+ default:
+ printf("Unknown splash location\n");
+ }
+
+ return -EINVAL;
+}
+
+static int splash_load_raw(struct splash_location *location, u32 bmp_load_addr)
+{
+ struct bmp_header *bmp_hdr;
+ int res;
+ size_t bmp_size, bmp_header_size = sizeof(struct bmp_header);
+
+ if (bmp_load_addr + bmp_header_size >= gd->start_addr_sp)
+ goto splash_address_too_high;
+
+ res = splash_storage_read_raw(location, bmp_load_addr, bmp_header_size);
+ if (res < 0)
+ return res;
+
+ bmp_hdr = (struct bmp_header *)(uintptr_t)bmp_load_addr;
+ bmp_size = le32_to_cpu(bmp_hdr->file_size);
+
+ if (bmp_load_addr + bmp_size >= gd->start_addr_sp)
+ goto splash_address_too_high;
+
+ return splash_storage_read_raw(location, bmp_load_addr, bmp_size);
+
+splash_address_too_high:
+ printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n");
+
+ return -EFAULT;
+}
+
+static int splash_select_fs_dev(struct splash_location *location)
+{
+ int res;
+
+ switch (location->storage) {
+ case SPLASH_STORAGE_MMC:
+ res = fs_set_blk_dev("mmc", location->devpart, FS_TYPE_ANY);
+ break;
+ case SPLASH_STORAGE_USB:
+ res = fs_set_blk_dev("usb", location->devpart, FS_TYPE_ANY);
+ break;
+ case SPLASH_STORAGE_SATA:
+ res = fs_set_blk_dev("sata", location->devpart, FS_TYPE_ANY);
+ break;
+ case SPLASH_STORAGE_NAND:
+ if (location->ubivol != NULL)
+ res = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
+ else
+ res = -ENODEV;
+ break;
+ default:
+ printf("Error: unsupported location storage.\n");
+ return -ENODEV;
+ }
+
+ if (res)
+ printf("Error: could not access storage.\n");
+
+ return res;
+}
+
+#ifdef CONFIG_USB_STORAGE
+static int splash_init_usb(void)
+{
+ int err;
+
+ err = usb_init();
+ if (err)
+ return err;
+
+#ifndef CONFIG_DM_USB
+ err = usb_stor_scan(1) < 0 ? -ENODEV : 0;
+#endif
+
+ return err;
+}
+#else
+static inline int splash_init_usb(void)
+{
+ printf("Cannot load splash image: no USB support\n");
+ return -ENOSYS;
+}
+#endif
+
+#ifdef CONFIG_SATA
+static int splash_init_sata(void)
+{
+ return sata_probe(0);
+}
+#else
+static inline int splash_init_sata(void)
+{
+ printf("Cannot load splash image: no SATA support\n");
+ return -ENOSYS;
+}
+#endif
+
+#ifdef CONFIG_CMD_UBIFS
+static int splash_mount_ubifs(struct splash_location *location)
+{
+ int res;
+ char cmd[32];
+
+ sprintf(cmd, "ubi part %s", location->mtdpart);
+ res = run_command(cmd, 0);
+ if (res)
+ return res;
+
+ sprintf(cmd, "ubifsmount %s", location->ubivol);
+ res = run_command(cmd, 0);
+
+ return res;
+}
+
+static inline int splash_umount_ubifs(void)
+{
+ return run_command("ubifsumount", 0);
+}
+#else
+static inline int splash_mount_ubifs(struct splash_location *location)
+{
+ printf("Cannot load splash image: no UBIFS support\n");
+ return -ENOSYS;
+}
+
+static inline int splash_umount_ubifs(void)
+{
+ printf("Cannot unmount UBIFS: no UBIFS support\n");
+ return -ENOSYS;
+}
+#endif
+
+#define SPLASH_SOURCE_DEFAULT_FILE_NAME "splash.bmp"
+
+static int splash_load_fs(struct splash_location *location, u32 bmp_load_addr)
+{
+ int res = 0;
+ loff_t bmp_size;
+ loff_t actread;
+ char *splash_file;
+
+ splash_file = env_get("splashfile");
+ if (!splash_file)
+ splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME;
+
+ if (location->storage == SPLASH_STORAGE_USB)
+ res = splash_init_usb();
+
+ if (location->storage == SPLASH_STORAGE_SATA)
+ res = splash_init_sata();
+
+ if (location->ubivol != NULL)
+ res = splash_mount_ubifs(location);
+
+ if (res)
+ return res;
+
+ res = splash_select_fs_dev(location);
+ if (res)
+ goto out;
+
+ res = fs_size(splash_file, &bmp_size);
+ if (res) {
+ printf("Error (%d): cannot determine file size\n", res);
+ goto out;
+ }
+
+ if (bmp_load_addr + bmp_size >= gd->start_addr_sp) {
+ printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n");
+ res = -EFAULT;
+ goto out;
+ }
+
+ splash_select_fs_dev(location);
+ res = fs_read(splash_file, bmp_load_addr, 0, 0, &actread);
+
+out:
+ if (location->ubivol != NULL)
+ splash_umount_ubifs();
+
+ return res;
+}
+
+/**
+ * select_splash_location - return the splash location based on board support
+ * and env variable "splashsource".
+ *
+ * @locations: An array of supported splash locations.
+ * @size: Size of splash_locations array.
+ *
+ * @return: If a null set of splash locations is given, or
+ * splashsource env variable is set to unsupported value
+ * return NULL.
+ * If splashsource env variable is not defined
+ * return the first entry in splash_locations as default.
+ * If splashsource env variable contains a supported value
+ * return the location selected by splashsource.
+ */
+static struct splash_location *select_splash_location(
+ struct splash_location *locations, uint size)
+{
+ int i;
+ char *env_splashsource;
+
+ if (!locations || size == 0)
+ return NULL;
+
+ env_splashsource = env_get("splashsource");
+ if (env_splashsource == NULL)
+ return &locations[0];
+
+ for (i = 0; i < size; i++) {
+ if (!strcmp(locations[i].name, env_splashsource))
+ return &locations[i];
+ }
+
+ printf("splashsource env variable set to unsupported value\n");
+ return NULL;
+}
+
+#ifdef CONFIG_FIT
+static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
+{
+ int res;
+ int node_offset;
+ const char *splash_file;
+ const void *internal_splash_data;
+ size_t internal_splash_size;
+ int external_splash_addr;
+ int external_splash_size;
+ bool is_splash_external = false;
+ struct image_header *img_header;
+ const u32 *fit_header;
+ u32 fit_size;
+ const size_t header_size = sizeof(struct image_header);
+
+ /* Read in image header */
+ res = splash_storage_read_raw(location, bmp_load_addr, header_size);
+ if (res < 0)
+ return res;
+
+ img_header = (struct image_header *)bmp_load_addr;
+ if (image_get_magic(img_header) != FDT_MAGIC) {
+ printf("Could not find FDT magic\n");
+ return -EINVAL;
+ }
+
+ fit_size = fdt_totalsize(img_header);
+
+ /* Read in entire FIT */
+ fit_header = (const u32 *)(bmp_load_addr + header_size);
+ res = splash_storage_read_raw(location, (u32)fit_header, fit_size);
+ if (res < 0)
+ return res;
+
+ res = fit_check_format(fit_header, IMAGE_SIZE_INVAL);
+ if (res) {
+ debug("Could not find valid FIT image\n");
+ return res;
+ }
+
+ /* Get the splash image node */
+ splash_file = env_get("splashfile");
+ if (!splash_file)
+ splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME;
+
+ node_offset = fit_image_get_node(fit_header, splash_file);
+ if (node_offset < 0) {
+ debug("Could not find splash image '%s' in FIT\n",
+ splash_file);
+ return -ENOENT;
+ }
+
+ /* Extract the splash data from FIT */
+ /* 1. Test if splash is in FIT internal data. */
+ if (!fit_image_get_data(fit_header, node_offset, &internal_splash_data, &internal_splash_size))
+ memmove((void *)bmp_load_addr, internal_splash_data, internal_splash_size);
+ /* 2. Test if splash is in FIT external data with fixed position. */
+ else if (!fit_image_get_data_position(fit_header, node_offset, &external_splash_addr))
+ is_splash_external = true;
+ /* 3. Test if splash is in FIT external data with offset. */
+ else if (!fit_image_get_data_offset(fit_header, node_offset, &external_splash_addr)) {
+ /* Align data offset to 4-byte boundary */
+ fit_size = ALIGN(fdt_totalsize(fit_header), 4);
+ /* External splash offset means the offset by end of FIT header */
+ external_splash_addr += location->offset + fit_size;
+ is_splash_external = true;
+ } else {
+ printf("Failed to get splash image from FIT\n");
+ return -ENODATA;
+ }
+
+ if (is_splash_external) {
+ res = fit_image_get_data_size(fit_header, node_offset, &external_splash_size);
+ if (res < 0) {
+ printf("Failed to get size of splash image (err=%d)\n", res);
+ return res;
+ }
+
+ /* Read in the splash data */
+ location->offset = external_splash_addr;
+ res = splash_storage_read_raw(location, bmp_load_addr, external_splash_size);
+ if (res < 0)
+ return res;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_FIT */
+
+/**
+ * splash_source_load - load splash image from a supported location.
+ *
+ * Select a splash image location based on the value of splashsource environment
+ * variable and the board supported splash source locations, and load a
+ * splashimage to the address pointed to by splashimage environment variable.
+ *
+ * @locations: An array of supported splash locations.
+ * @size: Size of splash_locations array.
+ *
+ * @return: 0 on success, negative value on failure.
+ */
+int splash_source_load(struct splash_location *locations, uint size)
+{
+ struct splash_location *splash_location;
+ char *env_splashimage_value;
+ u32 bmp_load_addr;
+
+ env_splashimage_value = env_get("splashimage");
+ if (env_splashimage_value == NULL)
+ return -ENOENT;
+
+ bmp_load_addr = simple_strtoul(env_splashimage_value, 0, 16);
+ if (bmp_load_addr == 0) {
+ printf("Error: bad splashimage address specified\n");
+ return -EFAULT;
+ }
+
+ splash_location = select_splash_location(locations, size);
+ if (!splash_location)
+ return -EINVAL;
+
+ if (splash_location->flags == SPLASH_STORAGE_RAW)
+ return splash_load_raw(splash_location, bmp_load_addr);
+ else if (splash_location->flags == SPLASH_STORAGE_FS)
+ return splash_load_fs(splash_location, bmp_load_addr);
+#ifdef CONFIG_FIT
+ else if (splash_location->flags == SPLASH_STORAGE_FIT)
+ return splash_load_fit(splash_location, bmp_load_addr);
+#endif
+ return -EINVAL;
+}
diff --git a/roms/u-boot/common/stackprot.c b/roms/u-boot/common/stackprot.c
new file mode 100644
index 000000000..d5b706166
--- /dev/null
+++ b/roms/u-boot/common/stackprot.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Broadcom
+ */
+
+#include <common.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+unsigned long __stack_chk_guard = (unsigned long)(0xfeedf00ddeadbeef & ~0UL);
+
+void __stack_chk_fail(void)
+{
+ void *ra;
+
+ ra = __builtin_extract_return_addr(__builtin_return_address(0));
+ panic("Stack smashing detected in function:\n%p relocated from %p",
+ ra, ra - gd->reloc_off);
+}
diff --git a/roms/u-boot/common/stdio.c b/roms/u-boot/common/stdio.c
new file mode 100644
index 000000000..d4acc5256
--- /dev/null
+++ b/roms/u-boot/common/stdio.c
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Changes for multibus/multiadapter I2C support.
+ *
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ */
+
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <stdio_dev.h>
+#include <serial.h>
+#include <splash.h>
+#include <i2c.h>
+#include <asm/global_data.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct stdio_dev devs;
+struct stdio_dev *stdio_devices[] = { NULL, NULL, NULL };
+char *stdio_names[MAX_FILES] = { "stdin", "stdout", "stderr" };
+
+int stdio_file_to_flags(const int file)
+{
+ switch (file) {
+ case stdin:
+ return DEV_FLAGS_INPUT;
+ case stdout:
+ case stderr:
+ return DEV_FLAGS_OUTPUT;
+ default:
+ return -EINVAL;
+ }
+}
+
+#if CONFIG_IS_ENABLED(SYS_DEVICE_NULLDEV)
+static void nulldev_putc(struct stdio_dev *dev, const char c)
+{
+ /* nulldev is empty! */
+}
+
+static void nulldev_puts(struct stdio_dev *dev, const char *s)
+{
+ /* nulldev is empty! */
+}
+
+static int nulldev_input(struct stdio_dev *dev)
+{
+ /* nulldev is empty! */
+ return 0;
+}
+
+static void nulldev_register(void)
+{
+ struct stdio_dev dev;
+
+ memset(&dev, '\0', sizeof(dev));
+
+ strcpy(dev.name, "nulldev");
+ dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
+ dev.putc = nulldev_putc;
+ dev.puts = nulldev_puts;
+ dev.getc = nulldev_input;
+ dev.tstc = nulldev_input;
+
+ stdio_register(&dev);
+}
+#else
+static inline void nulldev_register(void) {}
+#endif /* SYS_DEVICE_NULLDEV */
+
+static void stdio_serial_putc(struct stdio_dev *dev, const char c)
+{
+ serial_putc(c);
+}
+
+static void stdio_serial_puts(struct stdio_dev *dev, const char *s)
+{
+ serial_puts(s);
+}
+
+static int stdio_serial_getc(struct stdio_dev *dev)
+{
+ return serial_getc();
+}
+
+static int stdio_serial_tstc(struct stdio_dev *dev)
+{
+ return serial_tstc();
+}
+
+/**************************************************************************
+ * SYSTEM DRIVERS
+ **************************************************************************
+ */
+
+static void drv_system_init (void)
+{
+ struct stdio_dev dev;
+
+ memset (&dev, 0, sizeof (dev));
+
+ strcpy (dev.name, "serial");
+ dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
+ dev.putc = stdio_serial_putc;
+ dev.puts = stdio_serial_puts;
+ dev.getc = stdio_serial_getc;
+ dev.tstc = stdio_serial_tstc;
+ stdio_register (&dev);
+
+ nulldev_register();
+}
+
+/**************************************************************************
+ * DEVICES
+ **************************************************************************
+ */
+struct list_head* stdio_get_list(void)
+{
+ return &devs.list;
+}
+
+/**
+ * stdio_probe_device() - Find a device which provides the given stdio device
+ *
+ * This looks for a device of the given uclass which provides a particular
+ * stdio device. It is currently really only useful for UCLASS_VIDEO.
+ *
+ * Ultimately we want to be able to probe a device by its stdio name. At
+ * present devices register in their probe function (for video devices this
+ * is done in vidconsole_post_probe()) and we don't know what name they will
+ * use until they do so.
+ * TODO(sjg@chromium.org): We should be able to determine the name before
+ * probing, and probe the required device.
+ *
+ * @name: stdio device name (e.g. "vidconsole")
+ * id: Uclass ID of device to look for (e.g. UCLASS_VIDEO)
+ * @sdevp: Returns stdout device, if found, else NULL
+ * @return 0 if found, -ENOENT if no device found with that name, other -ve
+ * on other error
+ */
+static int stdio_probe_device(const char *name, enum uclass_id id,
+ struct stdio_dev **sdevp)
+{
+ struct stdio_dev *sdev;
+ struct udevice *dev;
+ int seq, ret;
+
+ *sdevp = NULL;
+ seq = trailing_strtoln(name, NULL);
+ if (seq == -1)
+ seq = 0;
+ ret = uclass_get_device_by_seq(id, seq, &dev);
+ if (ret == -ENODEV)
+ ret = uclass_first_device_err(id, &dev);
+ if (ret) {
+ debug("No %s device for seq %d (%s)\n", uclass_get_name(id),
+ seq, name);
+ return ret;
+ }
+ /* The device should be be the last one registered */
+ sdev = list_empty(&devs.list) ? NULL :
+ list_last_entry(&devs.list, struct stdio_dev, list);
+ if (!sdev || strcmp(sdev->name, name)) {
+ debug("Device '%s' did not register with stdio as '%s'\n",
+ dev->name, name);
+ return -ENOENT;
+ }
+ *sdevp = sdev;
+
+ return 0;
+}
+
+struct stdio_dev *stdio_get_by_name(const char *name)
+{
+ struct list_head *pos;
+ struct stdio_dev *sdev;
+
+ if (!name)
+ return NULL;
+
+ list_for_each(pos, &devs.list) {
+ sdev = list_entry(pos, struct stdio_dev, list);
+ if (strcmp(sdev->name, name) == 0)
+ return sdev;
+ }
+ if (IS_ENABLED(CONFIG_DM_VIDEO)) {
+ /*
+ * We did not find a suitable stdio device. If there is a video
+ * driver with a name starting with 'vidconsole', we can try
+ * probing that in the hope that it will produce the required
+ * stdio device.
+ *
+ * This function is sometimes called with the entire value of
+ * 'stdout', which may include a list of devices separate by
+ * commas. Obviously this is not going to work, so we ignore
+ * that case. The call path in that case is
+ * console_init_r() -> console_search_dev() -> stdio_get_by_name()
+ */
+ if (!strncmp(name, "vidconsole", 10) && !strchr(name, ',') &&
+ !stdio_probe_device(name, UCLASS_VIDEO, &sdev))
+ return sdev;
+ }
+
+ return NULL;
+}
+
+struct stdio_dev *stdio_clone(struct stdio_dev *dev)
+{
+ struct stdio_dev *_dev;
+
+ if (!dev)
+ return NULL;
+
+ _dev = calloc(1, sizeof(struct stdio_dev));
+ if (!_dev)
+ return NULL;
+
+ memcpy(_dev, dev, sizeof(struct stdio_dev));
+
+ return _dev;
+}
+
+int stdio_register_dev(struct stdio_dev *dev, struct stdio_dev **devp)
+{
+ struct stdio_dev *_dev;
+
+ _dev = stdio_clone(dev);
+ if (!_dev)
+ return -ENODEV;
+ list_add_tail(&_dev->list, &devs.list);
+ if (devp)
+ *devp = _dev;
+
+ return 0;
+}
+
+int stdio_register(struct stdio_dev *dev)
+{
+ return stdio_register_dev(dev, NULL);
+}
+
+int stdio_deregister_dev(struct stdio_dev *dev, int force)
+{
+ struct list_head *pos;
+ char temp_names[3][16];
+ int i;
+
+ /* get stdio devices (ListRemoveItem changes the dev list) */
+ for (i = 0 ; i < MAX_FILES; i++) {
+ if (stdio_devices[i] == dev) {
+ if (force) {
+ strcpy(temp_names[i], "nulldev");
+ continue;
+ }
+ /* Device is assigned -> report error */
+ return -EBUSY;
+ }
+ memcpy(&temp_names[i][0], stdio_devices[i]->name,
+ sizeof(temp_names[i]));
+ }
+
+ list_del(&dev->list);
+ free(dev);
+
+ /* reassign device list */
+ list_for_each(pos, &devs.list) {
+ dev = list_entry(pos, struct stdio_dev, list);
+ for (i = 0 ; i < MAX_FILES; i++) {
+ if (strcmp(dev->name, temp_names[i]) == 0)
+ stdio_devices[i] = dev;
+ }
+ }
+
+ return 0;
+}
+
+int stdio_init_tables(void)
+{
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ /* already relocated for current ARM implementation */
+ ulong relocation_offset = gd->reloc_off;
+ int i;
+
+ /* relocate device name pointers */
+ for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
+ stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
+ relocation_offset);
+ }
+#endif /* CONFIG_NEEDS_MANUAL_RELOC */
+
+ /* Initialize the list */
+ INIT_LIST_HEAD(&devs.list);
+
+ return 0;
+}
+
+int stdio_add_devices(void)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ if (IS_ENABLED(CONFIG_DM_KEYBOARD)) {
+ /*
+ * For now we probe all the devices here. At some point this
+ * should be done only when the devices are required - e.g. we
+ * have a list of input devices to start up in the stdin
+ * environment variable. That work probably makes more sense
+ * when stdio itself is converted to driver model.
+ *
+ * TODO(sjg@chromium.org): Convert changing
+ * uclass_first_device() etc. to return the device even on
+ * error. Then we could use that here.
+ */
+ ret = uclass_get(UCLASS_KEYBOARD, &uc);
+ if (ret)
+ return ret;
+
+ /*
+ * Don't report errors to the caller - assume that they are
+ * non-fatal
+ */
+ uclass_foreach_dev(dev, uc) {
+ ret = device_probe(dev);
+ if (ret)
+ printf("Failed to probe keyboard '%s'\n",
+ dev->name);
+ }
+ }
+#ifdef CONFIG_SYS_I2C
+ i2c_init_all();
+#endif
+ if (IS_ENABLED(CONFIG_DM_VIDEO)) {
+ /*
+ * If the console setting is not in environment variables then
+ * console_init_r() will not be calling iomux_doenv() (which
+ * calls console_search_dev()). So we will not dynamically add
+ * devices by calling stdio_probe_device().
+ *
+ * So just probe all video devices now so that whichever one is
+ * required will be available.
+ */
+ struct udevice *vdev;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_SYS_CONSOLE_IS_IN_ENV)) {
+ for (ret = uclass_first_device(UCLASS_VIDEO, &vdev);
+ vdev;
+ ret = uclass_next_device(&vdev))
+ ;
+ if (ret)
+ printf("%s: Video device failed (ret=%d)\n",
+ __func__, ret);
+ }
+ if (IS_ENABLED(CONFIG_SPLASH_SCREEN) &&
+ IS_ENABLED(CONFIG_CMD_BMP))
+ splash_display();
+ } else {
+ if (IS_ENABLED(CONFIG_LCD))
+ drv_lcd_init();
+ if (IS_ENABLED(CONFIG_VIDEO) ||
+ IS_ENABLED(CONFIG_CFB_CONSOLE) ||
+ IS_ENABLED(CONFIG_VIDEO_VCXK))
+ drv_video_init();
+ }
+
+#if defined(CONFIG_KEYBOARD) && !defined(CONFIG_DM_KEYBOARD)
+ drv_keyboard_init();
+#endif
+ drv_system_init();
+ serial_stdio_init();
+#ifdef CONFIG_USB_TTY
+ drv_usbtty_init();
+#endif
+ if (IS_ENABLED(CONFIG_NETCONSOLE))
+ drv_nc_init();
+#ifdef CONFIG_JTAG_CONSOLE
+ drv_jtag_console_init();
+#endif
+ if (IS_ENABLED(CONFIG_CBMEM_CONSOLE))
+ cbmemc_init();
+
+ return 0;
+}
+
+int stdio_init(void)
+{
+ stdio_init_tables();
+ stdio_add_devices();
+
+ return 0;
+}
diff --git a/roms/u-boot/common/system_map.c b/roms/u-boot/common/system_map.c
new file mode 100644
index 000000000..8307293bf
--- /dev/null
+++ b/roms/u-boot/common/system_map.c
@@ -0,0 +1,8 @@
+/*
+ * The builtin symbol table for use with kallsyms
+ *
+ * Copyright (c) 2008-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+const char const system_map[] = SYSTEM_MAP;
diff --git a/roms/u-boot/common/update.c b/roms/u-boot/common/update.c
new file mode 100644
index 000000000..f0848954e
--- /dev/null
+++ b/roms/u-boot/common/update.c
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * Written by: Rafal Czubak <rcz@semihalf.com>
+ * Bartlomiej Sieka <tur@semihalf.com>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <image.h>
+
+#if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT))
+#error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature"
+#endif
+
+#if defined(CONFIG_UPDATE_TFTP) && !defined(CONFIG_MTD_NOR_FLASH)
+#error "CONFIG_UPDATE_TFTP and !CONFIG_MTD_NOR_FLASH needed for legacy behaviour"
+#endif
+
+#include <command.h>
+#include <env.h>
+#include <flash.h>
+#include <net.h>
+#include <net/tftp.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <dfu.h>
+#include <errno.h>
+#include <mtd/cfi_flash.h>
+
+#if defined(CONFIG_DFU_TFTP) || defined(CONFIG_UPDATE_TFTP)
+/* env variable holding the location of the update file */
+#define UPDATE_FILE_ENV "updatefile"
+
+/* set configuration defaults if needed */
+#ifndef CONFIG_UPDATE_LOAD_ADDR
+#define CONFIG_UPDATE_LOAD_ADDR 0x100000
+#endif
+
+#ifndef CONFIG_UPDATE_TFTP_MSEC_MAX
+#define CONFIG_UPDATE_TFTP_MSEC_MAX 100
+#endif
+
+#ifndef CONFIG_UPDATE_TFTP_CNT_MAX
+#define CONFIG_UPDATE_TFTP_CNT_MAX 0
+#endif
+
+extern ulong tftp_timeout_ms;
+extern int tftp_timeout_count_max;
+#ifdef CONFIG_MTD_NOR_FLASH
+extern flash_info_t flash_info[];
+static uchar *saved_prot_info;
+#endif
+static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr)
+{
+ int size, rv;
+ ulong saved_timeout_msecs;
+ int saved_timeout_count;
+ char *saved_netretry, *saved_bootfile;
+
+ rv = 0;
+ /* save used globals and env variable */
+ saved_timeout_msecs = tftp_timeout_ms;
+ saved_timeout_count = tftp_timeout_count_max;
+ saved_netretry = strdup(env_get("netretry"));
+ saved_bootfile = strdup(net_boot_file_name);
+
+ /* set timeouts for auto-update */
+ tftp_timeout_ms = msec_max;
+ tftp_timeout_count_max = cnt_max;
+
+ /* we don't want to retry the connection if errors occur */
+ env_set("netretry", "no");
+
+ /* download the update file */
+ image_load_addr = addr;
+ copy_filename(net_boot_file_name, filename, sizeof(net_boot_file_name));
+ size = net_loop(TFTPGET);
+
+ if (size < 0)
+ rv = 1;
+ else if (size > 0)
+ flush_cache(addr, size);
+
+ /* restore changed globals and env variable */
+ tftp_timeout_ms = saved_timeout_msecs;
+ tftp_timeout_count_max = saved_timeout_count;
+
+ env_set("netretry", saved_netretry);
+ if (saved_netretry != NULL)
+ free(saved_netretry);
+
+ if (saved_bootfile != NULL) {
+ copy_filename(net_boot_file_name, saved_bootfile,
+ sizeof(net_boot_file_name));
+ free(saved_bootfile);
+ }
+
+ return rv;
+}
+
+#ifdef CONFIG_MTD_NOR_FLASH
+static int update_flash_protect(int prot, ulong addr_first, ulong addr_last)
+{
+ uchar *sp_info_ptr;
+ ulong s;
+ int i, bank, cnt;
+ flash_info_t *info;
+
+ sp_info_ptr = NULL;
+
+ if (prot == 0) {
+ saved_prot_info =
+ calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
+ if (!saved_prot_info)
+ return 1;
+ }
+
+ for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+ cnt = 0;
+ info = &flash_info[bank];
+
+ /* Nothing to do if the bank doesn't exist */
+ if (info->sector_count == 0)
+ return 0;
+
+ /* Point to current bank protection information */
+ sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
+
+ /*
+ * Adjust addr_first or addr_last if we are on bank boundary.
+ * Address space between banks must be continuous for other
+ * flash functions (like flash_sect_erase or flash_write) to
+ * succeed. Banks must also be numbered in correct order,
+ * according to increasing addresses.
+ */
+ if (addr_last > info->start[0] + info->size - 1)
+ addr_last = info->start[0] + info->size - 1;
+ if (addr_first < info->start[0])
+ addr_first = info->start[0];
+
+ for (i = 0; i < info->sector_count; i++) {
+ /* Save current information about protected sectors */
+ if (prot == 0) {
+ s = info->start[i];
+ if ((s >= addr_first) && (s <= addr_last))
+ sp_info_ptr[i] = info->protect[i];
+
+ }
+
+ /* Protect/unprotect sectors */
+ if (sp_info_ptr[i] == 1) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, prot))
+ return 1;
+#else
+ info->protect[i] = prot;
+#endif
+ cnt++;
+ }
+ }
+
+ if (cnt) {
+ printf("%sProtected %d sectors\n",
+ prot ? "": "Un-", cnt);
+ }
+ }
+
+ if((prot == 1) && saved_prot_info)
+ free(saved_prot_info);
+
+ return 0;
+}
+#endif
+
+static int update_flash(ulong addr_source, ulong addr_first, ulong size)
+{
+#ifdef CONFIG_MTD_NOR_FLASH
+ ulong addr_last = addr_first + size - 1;
+
+ /* round last address to the sector boundary */
+ if (flash_sect_roundb(&addr_last) > 0)
+ return 1;
+
+ if (addr_first >= addr_last) {
+ printf("Error: end address exceeds addressing space\n");
+ return 1;
+ }
+
+ /* remove protection on processed sectors */
+ if (update_flash_protect(0, addr_first, addr_last) > 0) {
+ printf("Error: could not unprotect flash sectors\n");
+ return 1;
+ }
+
+ printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last);
+ if (flash_sect_erase(addr_first, addr_last) > 0) {
+ printf("Error: could not erase flash\n");
+ return 1;
+ }
+
+ printf("Copying to flash...");
+ if (flash_write((char *)addr_source, addr_first, size) > 0) {
+ printf("Error: could not copy to flash\n");
+ return 1;
+ }
+ printf("done\n");
+
+ /* enable protection on processed sectors */
+ if (update_flash_protect(1, addr_first, addr_last) > 0) {
+ printf("Error: could not protect flash sectors\n");
+ return 1;
+ }
+#endif
+ return 0;
+}
+#endif /* CONFIG_DFU_TFTP || CONFIG_UPDATE_TFTP */
+
+static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
+ ulong *fladdr, ulong *size)
+{
+ const void *data;
+
+ if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
+ return 1;
+
+ if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
+ return 1;
+
+ *addr = (ulong)data;
+
+ return 0;
+}
+
+#if defined(CONFIG_DFU_TFTP) || defined(CONFIG_UPDATE_TFTP)
+int update_tftp(ulong addr, char *interface, char *devstring)
+{
+ char *filename, *env_addr, *fit_image_name;
+ ulong update_addr, update_fladdr, update_size;
+ int images_noffset, ndepth, noffset;
+ bool update_tftp_dfu;
+ int ret = 0;
+ void *fit;
+
+ if (interface == NULL && devstring == NULL) {
+ update_tftp_dfu = false;
+ } else if (interface && devstring) {
+ update_tftp_dfu = true;
+ } else {
+ pr_err("Interface: %s and devstring: %s not supported!\n",
+ interface, devstring);
+ return -EINVAL;
+ }
+
+ /* use already present image */
+ if (addr)
+ goto got_update_file;
+
+ printf("Auto-update from TFTP: ");
+
+ /* get the file name of the update file */
+ filename = env_get(UPDATE_FILE_ENV);
+ if (filename == NULL) {
+ printf("failed, env. variable '%s' not found\n",
+ UPDATE_FILE_ENV);
+ return 1;
+ }
+
+ printf("trying update file '%s'\n", filename);
+
+ /* get load address of downloaded update file */
+ env_addr = env_get("loadaddr");
+ if (env_addr)
+ addr = simple_strtoul(env_addr, NULL, 16);
+ else
+ addr = CONFIG_UPDATE_LOAD_ADDR;
+
+
+ if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX,
+ CONFIG_UPDATE_TFTP_CNT_MAX, addr)) {
+ printf("Can't load update file, aborting auto-update\n");
+ return 1;
+ }
+
+got_update_file:
+ fit = map_sysmem(addr, 0);
+
+ if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) {
+ printf("Bad FIT format of the update file, aborting "
+ "auto-update\n");
+ return 1;
+ }
+
+ /* process updates */
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+
+ ndepth = 0;
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ while (noffset >= 0 && ndepth > 0) {
+ if (ndepth != 1)
+ goto next_node;
+
+ fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
+ printf("Processing update '%s' :", fit_image_name);
+
+ if (!fit_image_verify(fit, noffset)) {
+ printf("Error: invalid update hash, aborting\n");
+ ret = 1;
+ goto next_node;
+ }
+
+ printf("\n");
+ if (update_fit_getparams(fit, noffset, &update_addr,
+ &update_fladdr, &update_size)) {
+ printf("Error: can't get update parameters, aborting\n");
+ ret = 1;
+ goto next_node;
+ }
+
+ if (!update_tftp_dfu) {
+ if (update_flash(update_addr, update_fladdr,
+ update_size)) {
+ printf("Error: can't flash update, aborting\n");
+ ret = 1;
+ goto next_node;
+ }
+ } else if (fit_image_check_type(fit, noffset,
+ IH_TYPE_FIRMWARE)) {
+ ret = dfu_write_by_name(fit_image_name,
+ (void *)update_addr,
+ update_size, interface,
+ devstring);
+ if (ret)
+ return ret;
+ }
+next_node:
+ noffset = fdt_next_node(fit, noffset, &ndepth);
+ }
+
+ return ret;
+}
+#endif /* CONFIG_DFU_UPDATE || CONFIG_UPDATE_TFTP */
+
+#ifdef CONFIG_UPDATE_FIT
+/**
+ * fit_update - update storage with FIT image
+ * @fit: Pointer to FIT image
+ *
+ * Update firmware on storage using FIT image as input.
+ * The storage area to be update will be identified by the name
+ * in FIT and matching it to "dfu_alt_info" variable.
+ *
+ * Return: 0 - on success, non-zero - otherwise
+ */
+int fit_update(const void *fit)
+{
+ char *fit_image_name;
+ ulong update_addr, update_fladdr, update_size;
+ int images_noffset, ndepth, noffset;
+ int ret = 0;
+
+ if (!fit)
+ return -EINVAL;
+
+ if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) {
+ printf("Bad FIT format of the update file, aborting auto-update\n");
+ return -EINVAL;
+ }
+
+ /* process updates */
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+
+ ndepth = 0;
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ while (noffset >= 0 && ndepth > 0) {
+ if (ndepth != 1)
+ goto next_node;
+
+ fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
+ printf("Processing update '%s' :", fit_image_name);
+
+ if (!fit_image_verify(fit, noffset)) {
+ printf("Error: invalid update hash, aborting\n");
+ ret = 1;
+ goto next_node;
+ }
+
+ printf("\n");
+ if (update_fit_getparams(fit, noffset, &update_addr,
+ &update_fladdr, &update_size)) {
+ printf("Error: can't get update parameters, aborting\n");
+ ret = 1;
+ goto next_node;
+ }
+
+ if (fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE)) {
+ ret = dfu_write_by_name(fit_image_name,
+ (void *)update_addr,
+ update_size, NULL, NULL);
+ if (ret)
+ return ret;
+ }
+next_node:
+ noffset = fdt_next_node(fit, noffset, &ndepth);
+ }
+
+ return ret;
+}
+#endif /* CONFIG_UPDATE_FIT */
diff --git a/roms/u-boot/common/usb.c b/roms/u-boot/common/usb.c
new file mode 100644
index 000000000..aad13fd9c
--- /dev/null
+++ b/roms/u-boot/common/usb.c
@@ -0,0 +1,1293 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Most of this source has been derived from the Linux USB
+ * project:
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ *
+ * Adapted for U-Boot:
+ * (C) Copyright 2001 Denis Peter, MPL AG Switzerland
+ */
+
+/*
+ * How it works:
+ *
+ * Since this is a bootloader, the devices will not be automatic
+ * (re)configured on hotplug, but after a restart of the USB the
+ * device should work.
+ *
+ * For each transfer (except "Interrupt") we wait for completion.
+ */
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <asm/processor.h>
+#include <linux/compiler.h>
+#include <linux/ctype.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <errno.h>
+#include <usb.h>
+#include <linux/delay.h>
+
+#define USB_BUFSIZ 512
+
+static int asynch_allowed;
+char usb_started; /* flag for the started/stopped USB status */
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+static struct usb_device usb_dev[USB_MAX_DEVICE];
+static int dev_index;
+
+#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
+/***************************************************************************
+ * Init USB Device
+ */
+int usb_init(void)
+{
+ void *ctrl;
+ struct usb_device *dev;
+ int i, start_index = 0;
+ int controllers_initialized = 0;
+ int ret;
+
+ dev_index = 0;
+ asynch_allowed = 1;
+ usb_hub_reset();
+
+ /* first make all devices unknown */
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ memset(&usb_dev[i], 0, sizeof(struct usb_device));
+ usb_dev[i].devnum = -1;
+ }
+
+ /* init low_level USB */
+ for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
+ /* init low_level USB */
+ printf("USB%d: ", i);
+ ret = usb_lowlevel_init(i, USB_INIT_HOST, &ctrl);
+ if (ret == -ENODEV) { /* No such device. */
+ puts("Port not available.\n");
+ controllers_initialized++;
+ continue;
+ }
+
+ if (ret) { /* Other error. */
+ puts("lowlevel init failed\n");
+ continue;
+ }
+ /*
+ * lowlevel init is OK, now scan the bus for devices
+ * i.e. search HUBs and configure them
+ */
+ controllers_initialized++;
+ start_index = dev_index;
+ printf("scanning bus %d for devices... ", i);
+ ret = usb_alloc_new_device(ctrl, &dev);
+ if (ret)
+ break;
+
+ /*
+ * device 0 is always present
+ * (root hub, so let it analyze)
+ */
+ ret = usb_new_device(dev);
+ if (ret)
+ usb_free_device(dev->controller);
+
+ if (start_index == dev_index) {
+ puts("No USB Device found\n");
+ continue;
+ } else {
+ printf("%d USB Device(s) found\n",
+ dev_index - start_index);
+ }
+
+ usb_started = 1;
+ }
+
+ debug("scan end\n");
+ /* if we were not able to find at least one working bus, bail out */
+ if (controllers_initialized == 0)
+ puts("USB error: all controllers failed lowlevel init\n");
+
+ return usb_started ? 0 : -ENODEV;
+}
+
+/******************************************************************************
+ * Stop USB this stops the LowLevel Part and deregisters USB devices.
+ */
+int usb_stop(void)
+{
+ int i;
+
+ if (usb_started) {
+ asynch_allowed = 1;
+ usb_started = 0;
+ usb_hub_reset();
+
+ for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
+ if (usb_lowlevel_stop(i))
+ printf("failed to stop USB controller %d\n", i);
+ }
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ * Detect if a USB device has been plugged or unplugged.
+ */
+int usb_detect_change(void)
+{
+ int i, j;
+ int change = 0;
+
+ for (j = 0; j < USB_MAX_DEVICE; j++) {
+ for (i = 0; i < usb_dev[j].maxchild; i++) {
+ struct usb_port_status status;
+
+ if (usb_get_port_status(&usb_dev[j], i + 1,
+ &status) < 0)
+ /* USB request failed */
+ continue;
+
+ if (le16_to_cpu(status.wPortChange) &
+ USB_PORT_STAT_C_CONNECTION)
+ change++;
+ }
+ }
+
+ return change;
+}
+
+/* Lock or unlock async schedule on the controller */
+__weak int usb_lock_async(struct usb_device *dev, int lock)
+{
+ return 0;
+}
+
+/*
+ * disables the asynch behaviour of the control message. This is used for data
+ * transfers that uses the exclusiv access to the control and bulk messages.
+ * Returns the old value so it can be restored later.
+ */
+int usb_disable_asynch(int disable)
+{
+ int old_value = asynch_allowed;
+
+ asynch_allowed = !disable;
+ return old_value;
+}
+#endif /* !CONFIG_IS_ENABLED(DM_USB) */
+
+
+/*-------------------------------------------------------------------
+ * Message wrappers.
+ *
+ */
+
+/*
+ * submits an Interrupt Message. Some drivers may implement non-blocking
+ * polling: when non-block is true and the device is not responding return
+ * -EAGAIN instead of waiting for device to respond.
+ */
+int usb_int_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, int interval, bool nonblock)
+{
+ return submit_int_msg(dev, pipe, buffer, transfer_len, interval,
+ nonblock);
+}
+
+/*
+ * submits a control message and waits for comletion (at least timeout * 1ms)
+ * If timeout is 0, we don't wait for completion (used as example to set and
+ * clear keyboards LEDs). For data transfers, (storage transfers) we don't
+ * allow control messages with 0 timeout, by previousely resetting the flag
+ * asynch_allowed (usb_disable_asynch(1)).
+ * returns the transferred length if OK or -1 if error. The transferred length
+ * and the current status are stored in the dev->act_len and dev->status.
+ */
+int usb_control_msg(struct usb_device *dev, unsigned int pipe,
+ unsigned char request, unsigned char requesttype,
+ unsigned short value, unsigned short index,
+ void *data, unsigned short size, int timeout)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct devrequest, setup_packet, 1);
+ int err;
+
+ if ((timeout == 0) && (!asynch_allowed)) {
+ /* request for a asynch control pipe is not allowed */
+ return -EINVAL;
+ }
+
+ /* set setup command */
+ setup_packet->requesttype = requesttype;
+ setup_packet->request = request;
+ setup_packet->value = cpu_to_le16(value);
+ setup_packet->index = cpu_to_le16(index);
+ setup_packet->length = cpu_to_le16(size);
+ debug("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \
+ "value 0x%X index 0x%X length 0x%X\n",
+ request, requesttype, value, index, size);
+ dev->status = USB_ST_NOT_PROC; /*not yet processed */
+
+ err = submit_control_msg(dev, pipe, data, size, setup_packet);
+ if (err < 0)
+ return err;
+ if (timeout == 0)
+ return (int)size;
+
+ /*
+ * Wait for status to update until timeout expires, USB driver
+ * interrupt handler may set the status when the USB operation has
+ * been completed.
+ */
+ while (timeout--) {
+ if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
+ break;
+ mdelay(1);
+ }
+ if (dev->status)
+ return -1;
+
+ return dev->act_len;
+
+}
+
+/*-------------------------------------------------------------------
+ * submits bulk message, and waits for completion. returns 0 if Ok or
+ * negative if Error.
+ * synchronous behavior
+ */
+int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout)
+{
+ if (len < 0)
+ return -EINVAL;
+ dev->status = USB_ST_NOT_PROC; /*not yet processed */
+ if (submit_bulk_msg(dev, pipe, data, len) < 0)
+ return -EIO;
+ while (timeout--) {
+ if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
+ break;
+ mdelay(1);
+ }
+ *actual_length = dev->act_len;
+ if (dev->status == 0)
+ return 0;
+ else
+ return -EIO;
+}
+
+
+/*-------------------------------------------------------------------
+ * Max Packet stuff
+ */
+
+/*
+ * returns the max packet size, depending on the pipe direction and
+ * the configurations values
+ */
+int usb_maxpacket(struct usb_device *dev, unsigned long pipe)
+{
+ /* direction is out -> use emaxpacket out */
+ if ((pipe & USB_DIR_IN) == 0)
+ return dev->epmaxpacketout[((pipe>>15) & 0xf)];
+ else
+ return dev->epmaxpacketin[((pipe>>15) & 0xf)];
+}
+
+/*
+ * The routine usb_set_maxpacket_ep() is extracted from the loop of routine
+ * usb_set_maxpacket(), because the optimizer of GCC 4.x chokes on this routine
+ * when it is inlined in 1 single routine. What happens is that the register r3
+ * is used as loop-count 'i', but gets overwritten later on.
+ * This is clearly a compiler bug, but it is easier to workaround it here than
+ * to update the compiler (Occurs with at least several GCC 4.{1,2},x
+ * CodeSourcery compilers like e.g. 2007q3, 2008q1, 2008q3 lite editions on ARM)
+ *
+ * NOTE: Similar behaviour was observed with GCC4.6 on ARMv5.
+ */
+static void noinline
+usb_set_maxpacket_ep(struct usb_device *dev, int if_idx, int ep_idx)
+{
+ int b;
+ struct usb_endpoint_descriptor *ep;
+ u16 ep_wMaxPacketSize;
+
+ ep = &dev->config.if_desc[if_idx].ep_desc[ep_idx];
+
+ b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ ep_wMaxPacketSize = get_unaligned(&ep->wMaxPacketSize);
+
+ if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_CONTROL) {
+ /* Control => bidirectional */
+ dev->epmaxpacketout[b] = ep_wMaxPacketSize;
+ dev->epmaxpacketin[b] = ep_wMaxPacketSize;
+ debug("##Control EP epmaxpacketout/in[%d] = %d\n",
+ b, dev->epmaxpacketin[b]);
+ } else {
+ if ((ep->bEndpointAddress & 0x80) == 0) {
+ /* OUT Endpoint */
+ if (ep_wMaxPacketSize > dev->epmaxpacketout[b]) {
+ dev->epmaxpacketout[b] = ep_wMaxPacketSize;
+ debug("##EP epmaxpacketout[%d] = %d\n",
+ b, dev->epmaxpacketout[b]);
+ }
+ } else {
+ /* IN Endpoint */
+ if (ep_wMaxPacketSize > dev->epmaxpacketin[b]) {
+ dev->epmaxpacketin[b] = ep_wMaxPacketSize;
+ debug("##EP epmaxpacketin[%d] = %d\n",
+ b, dev->epmaxpacketin[b]);
+ }
+ } /* if out */
+ } /* if control */
+}
+
+/*
+ * set the max packed value of all endpoints in the given configuration
+ */
+static int usb_set_maxpacket(struct usb_device *dev)
+{
+ int i, ii;
+
+ for (i = 0; i < dev->config.desc.bNumInterfaces; i++)
+ for (ii = 0; ii < dev->config.if_desc[i].desc.bNumEndpoints; ii++)
+ usb_set_maxpacket_ep(dev, i, ii);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Parse the config, located in buffer, and fills the dev->config structure.
+ * Note that all little/big endian swapping are done automatically.
+ * (wTotalLength has already been swapped and sanitized when it was read.)
+ */
+static int usb_parse_config(struct usb_device *dev,
+ unsigned char *buffer, int cfgno)
+{
+ struct usb_descriptor_header *head;
+ int index, ifno, epno, curr_if_num;
+ u16 ep_wMaxPacketSize;
+ struct usb_interface *if_desc = NULL;
+
+ ifno = -1;
+ epno = -1;
+ curr_if_num = -1;
+
+ dev->configno = cfgno;
+ head = (struct usb_descriptor_header *) &buffer[0];
+ if (head->bDescriptorType != USB_DT_CONFIG) {
+ printf(" ERROR: NOT USB_CONFIG_DESC %x\n",
+ head->bDescriptorType);
+ return -EINVAL;
+ }
+ if (head->bLength != USB_DT_CONFIG_SIZE) {
+ printf("ERROR: Invalid USB CFG length (%d)\n", head->bLength);
+ return -EINVAL;
+ }
+ memcpy(&dev->config, head, USB_DT_CONFIG_SIZE);
+ dev->config.no_of_if = 0;
+
+ index = dev->config.desc.bLength;
+ /* Ok the first entry must be a configuration entry,
+ * now process the others */
+ head = (struct usb_descriptor_header *) &buffer[index];
+ while (index + 1 < dev->config.desc.wTotalLength && head->bLength) {
+ switch (head->bDescriptorType) {
+ case USB_DT_INTERFACE:
+ if (head->bLength != USB_DT_INTERFACE_SIZE) {
+ printf("ERROR: Invalid USB IF length (%d)\n",
+ head->bLength);
+ break;
+ }
+ if (index + USB_DT_INTERFACE_SIZE >
+ dev->config.desc.wTotalLength) {
+ puts("USB IF descriptor overflowed buffer!\n");
+ break;
+ }
+ if (((struct usb_interface_descriptor *) \
+ head)->bInterfaceNumber != curr_if_num) {
+ /* this is a new interface, copy new desc */
+ ifno = dev->config.no_of_if;
+ if (ifno >= USB_MAXINTERFACES) {
+ puts("Too many USB interfaces!\n");
+ /* try to go on with what we have */
+ return -EINVAL;
+ }
+ if_desc = &dev->config.if_desc[ifno];
+ dev->config.no_of_if++;
+ memcpy(if_desc, head,
+ USB_DT_INTERFACE_SIZE);
+ if_desc->no_of_ep = 0;
+ if_desc->num_altsetting = 1;
+ curr_if_num =
+ if_desc->desc.bInterfaceNumber;
+ } else {
+ /* found alternate setting for the interface */
+ if (ifno >= 0) {
+ if_desc = &dev->config.if_desc[ifno];
+ if_desc->num_altsetting++;
+ }
+ }
+ break;
+ case USB_DT_ENDPOINT:
+ if (head->bLength != USB_DT_ENDPOINT_SIZE &&
+ head->bLength != USB_DT_ENDPOINT_AUDIO_SIZE) {
+ printf("ERROR: Invalid USB EP length (%d)\n",
+ head->bLength);
+ break;
+ }
+ if (index + head->bLength >
+ dev->config.desc.wTotalLength) {
+ puts("USB EP descriptor overflowed buffer!\n");
+ break;
+ }
+ if (ifno < 0) {
+ puts("Endpoint descriptor out of order!\n");
+ break;
+ }
+ epno = dev->config.if_desc[ifno].no_of_ep;
+ if_desc = &dev->config.if_desc[ifno];
+ if (epno >= USB_MAXENDPOINTS) {
+ printf("Interface %d has too many endpoints!\n",
+ if_desc->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+ /* found an endpoint */
+ if_desc->no_of_ep++;
+ memcpy(&if_desc->ep_desc[epno], head,
+ USB_DT_ENDPOINT_SIZE);
+ ep_wMaxPacketSize = get_unaligned(&dev->config.\
+ if_desc[ifno].\
+ ep_desc[epno].\
+ wMaxPacketSize);
+ put_unaligned(le16_to_cpu(ep_wMaxPacketSize),
+ &dev->config.\
+ if_desc[ifno].\
+ ep_desc[epno].\
+ wMaxPacketSize);
+ debug("if %d, ep %d\n", ifno, epno);
+ break;
+ case USB_DT_SS_ENDPOINT_COMP:
+ if (head->bLength != USB_DT_SS_EP_COMP_SIZE) {
+ printf("ERROR: Invalid USB EPC length (%d)\n",
+ head->bLength);
+ break;
+ }
+ if (index + USB_DT_SS_EP_COMP_SIZE >
+ dev->config.desc.wTotalLength) {
+ puts("USB EPC descriptor overflowed buffer!\n");
+ break;
+ }
+ if (ifno < 0 || epno < 0) {
+ puts("EPC descriptor out of order!\n");
+ break;
+ }
+ if_desc = &dev->config.if_desc[ifno];
+ memcpy(&if_desc->ss_ep_comp_desc[epno], head,
+ USB_DT_SS_EP_COMP_SIZE);
+ break;
+ default:
+ if (head->bLength == 0)
+ return -EINVAL;
+
+ debug("unknown Description Type : %x\n",
+ head->bDescriptorType);
+
+#ifdef DEBUG
+ {
+ unsigned char *ch = (unsigned char *)head;
+ int i;
+
+ for (i = 0; i < head->bLength; i++)
+ debug("%02X ", *ch++);
+ debug("\n\n\n");
+ }
+#endif
+ break;
+ }
+ index += head->bLength;
+ head = (struct usb_descriptor_header *)&buffer[index];
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * Clears an endpoint
+ * endp: endpoint number in bits 0-3;
+ * direction flag in bit 7 (1 = IN, 0 = OUT)
+ */
+int usb_clear_halt(struct usb_device *dev, int pipe)
+{
+ int result;
+ int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
+
+ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
+ endp, NULL, 0, USB_CNTL_TIMEOUT * 3);
+
+ /* don't clear if failed */
+ if (result < 0)
+ return result;
+
+ /*
+ * NOTE: we do not get status and verify reset was successful
+ * as some devices are reported to lock up upon this check..
+ */
+
+ usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
+ /* toggle is reset on clear */
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
+ return 0;
+}
+
+
+/**********************************************************************
+ * get_descriptor type
+ */
+static int usb_get_descriptor(struct usb_device *dev, unsigned char type,
+ unsigned char index, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (type << 8) + index, 0, buf, size,
+ USB_CNTL_TIMEOUT);
+}
+
+/**********************************************************************
+ * gets len of configuration cfgno
+ */
+int usb_get_configuration_len(struct usb_device *dev, int cfgno)
+{
+ int result;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 9);
+ struct usb_config_descriptor *config;
+
+ config = (struct usb_config_descriptor *)&buffer[0];
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9);
+ if (result < 9) {
+ if (result < 0)
+ printf("unable to get descriptor, error %lX\n",
+ dev->status);
+ else
+ printf("config descriptor too short " \
+ "(expected %i, got %i)\n", 9, result);
+ return -EIO;
+ }
+ return le16_to_cpu(config->wTotalLength);
+}
+
+/**********************************************************************
+ * gets configuration cfgno and store it in the buffer
+ */
+int usb_get_configuration_no(struct usb_device *dev, int cfgno,
+ unsigned char *buffer, int length)
+{
+ int result;
+ struct usb_config_descriptor *config;
+
+ config = (struct usb_config_descriptor *)&buffer[0];
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, length);
+ debug("get_conf_no %d Result %d, wLength %d\n", cfgno, result,
+ le16_to_cpu(config->wTotalLength));
+ config->wTotalLength = result; /* validated, with CPU byte order */
+
+ return result;
+}
+
+/********************************************************************
+ * set address of a device to the value in dev->devnum.
+ * This can only be done by addressing the device via the default address (0)
+ */
+static int usb_set_address(struct usb_device *dev)
+{
+ debug("set address %d\n", dev->devnum);
+
+ return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
+ 0, (dev->devnum), 0, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * set interface number to interface
+ */
+int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+{
+ struct usb_interface *if_face = NULL;
+ int ret, i;
+
+ for (i = 0; i < dev->config.desc.bNumInterfaces; i++) {
+ if (dev->config.if_desc[i].desc.bInterfaceNumber == interface) {
+ if_face = &dev->config.if_desc[i];
+ break;
+ }
+ }
+ if (!if_face) {
+ printf("selecting invalid interface %d", interface);
+ return -EINVAL;
+ }
+ /*
+ * We should return now for devices with only one alternate setting.
+ * According to 9.4.10 of the Universal Serial Bus Specification
+ * Revision 2.0 such devices can return with a STALL. This results in
+ * some USB sticks timeouting during initialization and then being
+ * unusable in U-Boot.
+ */
+ if (if_face->num_altsetting == 1)
+ return 0;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
+ alternate, interface, NULL, 0,
+ USB_CNTL_TIMEOUT * 5);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/********************************************************************
+ * set configuration number to configuration
+ */
+static int usb_set_configuration(struct usb_device *dev, int configuration)
+{
+ int res;
+ debug("set configuration %d\n", configuration);
+ /* set setup command */
+ res = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_CONFIGURATION, 0,
+ configuration, 0,
+ NULL, 0, USB_CNTL_TIMEOUT);
+ if (res == 0) {
+ dev->toggle[0] = 0;
+ dev->toggle[1] = 0;
+ return 0;
+ } else
+ return -EIO;
+}
+
+/********************************************************************
+ * set protocol to protocol
+ */
+int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ protocol, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * set idle
+ */
+int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (duration << 8) | report_id, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get report
+ */
+int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get class descriptor
+ */
+int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
+ unsigned char type, unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
+ (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get string index in buffer
+ */
+static int usb_get_string(struct usb_device *dev, unsigned short langid,
+ unsigned char index, void *buf, int size)
+{
+ int i;
+ int result;
+
+ for (i = 0; i < 3; ++i) {
+ /* some devices are flaky */
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (USB_DT_STRING << 8) + index, langid, buf, size,
+ USB_CNTL_TIMEOUT);
+
+ if (result > 0)
+ break;
+ }
+
+ return result;
+}
+
+
+static void usb_try_string_workarounds(unsigned char *buf, int *length)
+{
+ int newlength, oldlength = *length;
+
+ for (newlength = 2; newlength + 1 < oldlength; newlength += 2)
+ if (!isprint(buf[newlength]) || buf[newlength + 1])
+ break;
+
+ if (newlength > 2) {
+ buf[0] = newlength;
+ *length = newlength;
+ }
+}
+
+
+static int usb_string_sub(struct usb_device *dev, unsigned int langid,
+ unsigned int index, unsigned char *buf)
+{
+ int rc;
+
+ /* Try to read the string descriptor by asking for the maximum
+ * possible number of bytes */
+ rc = usb_get_string(dev, langid, index, buf, 255);
+
+ /* If that failed try to read the descriptor length, then
+ * ask for just that many bytes */
+ if (rc < 2) {
+ rc = usb_get_string(dev, langid, index, buf, 2);
+ if (rc == 2)
+ rc = usb_get_string(dev, langid, index, buf, buf[0]);
+ }
+
+ if (rc >= 2) {
+ if (!buf[0] && !buf[1])
+ usb_try_string_workarounds(buf, &rc);
+
+ /* There might be extra junk at the end of the descriptor */
+ if (buf[0] < rc)
+ rc = buf[0];
+
+ rc = rc - (rc & 1); /* force a multiple of two */
+ }
+
+ if (rc < 2)
+ rc = -EINVAL;
+
+ return rc;
+}
+
+
+/********************************************************************
+ * usb_string:
+ * Get string index and translate it to ascii.
+ * returns string length (> 0) or error (< 0)
+ */
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, mybuf, USB_BUFSIZ);
+ unsigned char *tbuf;
+ int err;
+ unsigned int u, idx;
+
+ if (size <= 0 || !buf || !index)
+ return -EINVAL;
+ buf[0] = 0;
+ tbuf = &mybuf[0];
+
+ /* get langid for strings if it's not yet known */
+ if (!dev->have_langid) {
+ err = usb_string_sub(dev, 0, 0, tbuf);
+ if (err < 0) {
+ debug("error getting string descriptor 0 " \
+ "(error=%lx)\n", dev->status);
+ return -EIO;
+ } else if (tbuf[0] < 4) {
+ debug("string descriptor 0 too short\n");
+ return -EIO;
+ } else {
+ dev->have_langid = -1;
+ dev->string_langid = tbuf[2] | (tbuf[3] << 8);
+ /* always use the first langid listed */
+ debug("USB device number %d default " \
+ "language ID 0x%x\n",
+ dev->devnum, dev->string_langid);
+ }
+ }
+
+ err = usb_string_sub(dev, dev->string_langid, index, tbuf);
+ if (err < 0)
+ return err;
+
+ size--; /* leave room for trailing NULL char in output buffer */
+ for (idx = 0, u = 2; u < err; u += 2) {
+ if (idx >= size)
+ break;
+ if (tbuf[u+1]) /* high byte */
+ buf[idx++] = '?'; /* non-ASCII character */
+ else
+ buf[idx++] = tbuf[u];
+ }
+ buf[idx] = 0;
+ err = idx;
+ return err;
+}
+
+
+/********************************************************************
+ * USB device handling:
+ * the USB device are static allocated [USB_MAX_DEVICE].
+ */
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+
+/* returns a pointer to the device with the index [index].
+ * if the device is not assigned (dev->devnum==-1) returns NULL
+ */
+struct usb_device *usb_get_dev_index(int index)
+{
+ if (usb_dev[index].devnum == -1)
+ return NULL;
+ else
+ return &usb_dev[index];
+}
+
+int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp)
+{
+ int i;
+ debug("New Device %d\n", dev_index);
+ if (dev_index == USB_MAX_DEVICE) {
+ printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE);
+ return -ENOSPC;
+ }
+ /* default Address is 0, real addresses start with 1 */
+ usb_dev[dev_index].devnum = dev_index + 1;
+ usb_dev[dev_index].maxchild = 0;
+ for (i = 0; i < USB_MAXCHILDREN; i++)
+ usb_dev[dev_index].children[i] = NULL;
+ usb_dev[dev_index].parent = NULL;
+ usb_dev[dev_index].controller = controller;
+ dev_index++;
+ *devp = &usb_dev[dev_index - 1];
+
+ return 0;
+}
+
+/*
+ * Free the newly created device node.
+ * Called in error cases where configuring a newly attached
+ * device fails for some reason.
+ */
+void usb_free_device(struct udevice *controller)
+{
+ dev_index--;
+ debug("Freeing device node: %d\n", dev_index);
+ memset(&usb_dev[dev_index], 0, sizeof(struct usb_device));
+ usb_dev[dev_index].devnum = -1;
+}
+
+/*
+ * XHCI issues Enable Slot command and thereafter
+ * allocates device contexts. Provide a weak alias
+ * function for the purpose, so that XHCI overrides it
+ * and EHCI/OHCI just work out of the box.
+ */
+__weak int usb_alloc_device(struct usb_device *udev)
+{
+ return 0;
+}
+#endif /* !CONFIG_IS_ENABLED(DM_USB) */
+
+static int usb_hub_port_reset(struct usb_device *dev, struct usb_device *hub)
+{
+ if (!hub)
+ usb_reset_root_port(dev);
+
+ return 0;
+}
+
+static int get_descriptor_len(struct usb_device *dev, int len, int expect_len)
+{
+ __maybe_unused struct usb_device_descriptor *desc;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
+ int err;
+
+ desc = (struct usb_device_descriptor *)tmpbuf;
+
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, len);
+ if (err < expect_len) {
+ if (err < 0) {
+ printf("unable to get device descriptor (error=%d)\n",
+ err);
+ return err;
+ } else {
+ printf("USB device descriptor short read (expected %i, got %i)\n",
+ expect_len, err);
+ return -EIO;
+ }
+ }
+ memcpy(&dev->descriptor, tmpbuf, sizeof(dev->descriptor));
+
+ return 0;
+}
+
+static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
+{
+ /*
+ * This is a Windows scheme of initialization sequence, with double
+ * reset of the device (Linux uses the same sequence)
+ * Some equipment is said to work only with such init sequence; this
+ * patch is based on the work by Alan Stern:
+ * http://sourceforge.net/mailarchive/forum.php?
+ * thread_id=5729457&forum_id=5398
+ */
+
+ /*
+ * send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is
+ * only 18 bytes long, this will terminate with a short packet. But if
+ * the maxpacket size is 8 or 16 the device may be waiting to transmit
+ * some more, or keeps on retransmitting the 8 byte header.
+ */
+
+ if (dev->speed == USB_SPEED_LOW) {
+ dev->descriptor.bMaxPacketSize0 = 8;
+ dev->maxpacketsize = PACKET_SIZE_8;
+ } else {
+ dev->descriptor.bMaxPacketSize0 = 64;
+ dev->maxpacketsize = PACKET_SIZE_64;
+ }
+ dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
+ dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
+
+ if (do_read && dev->speed == USB_SPEED_FULL) {
+ int err;
+
+ /*
+ * Validate we've received only at least 8 bytes, not that
+ * we've received the entire descriptor. The reasoning is:
+ * - The code only uses fields in the first 8 bytes, so
+ * that's all we need to have fetched at this stage.
+ * - The smallest maxpacket size is 8 bytes. Before we know
+ * the actual maxpacket the device uses, the USB controller
+ * may only accept a single packet. Consequently we are only
+ * guaranteed to receive 1 packet (at least 8 bytes) even in
+ * a non-error case.
+ *
+ * At least the DWC2 controller needs to be programmed with
+ * the number of packets in addition to the number of bytes.
+ * A request for 64 bytes of data with the maxpacket guessed
+ * as 64 (above) yields a request for 1 packet.
+ */
+ err = get_descriptor_len(dev, 64, 8);
+ if (err)
+ return err;
+ }
+
+ dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
+ dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
+ switch (dev->descriptor.bMaxPacketSize0) {
+ case 8:
+ dev->maxpacketsize = PACKET_SIZE_8;
+ break;
+ case 16:
+ dev->maxpacketsize = PACKET_SIZE_16;
+ break;
+ case 32:
+ dev->maxpacketsize = PACKET_SIZE_32;
+ break;
+ case 64:
+ dev->maxpacketsize = PACKET_SIZE_64;
+ break;
+ default:
+ printf("%s: invalid max packet size\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
+ struct usb_device *parent)
+{
+ int err;
+
+ /*
+ * Allocate usb 3.0 device context.
+ * USB 3.0 (xHCI) protocol tries to allocate device slot
+ * and related data structures first. This call does that.
+ * Refer to sec 4.3.2 in xHCI spec rev1.0
+ */
+ err = usb_alloc_device(dev);
+ if (err) {
+ printf("Cannot allocate device context to get SLOT_ID\n");
+ return err;
+ }
+ err = usb_setup_descriptor(dev, do_read);
+ if (err)
+ return err;
+ err = usb_hub_port_reset(dev, parent);
+ if (err)
+ return err;
+
+ dev->devnum = addr;
+
+ err = usb_set_address(dev); /* set address */
+
+ if (err < 0) {
+ printf("\n USB device not accepting new address " \
+ "(error=%lX)\n", dev->status);
+ return err;
+ }
+
+ mdelay(10); /* Let the SET_ADDRESS settle */
+
+ /*
+ * If we haven't read device descriptor before, read it here
+ * after device is assigned an address. This is only applicable
+ * to xHCI so far.
+ */
+ if (!do_read) {
+ err = usb_setup_descriptor(dev, true);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+int usb_select_config(struct usb_device *dev)
+{
+ unsigned char *tmpbuf = NULL;
+ int err;
+
+ err = get_descriptor_len(dev, USB_DT_DEVICE_SIZE, USB_DT_DEVICE_SIZE);
+ if (err)
+ return err;
+
+ /* correct le values */
+ le16_to_cpus(&dev->descriptor.bcdUSB);
+ le16_to_cpus(&dev->descriptor.idVendor);
+ le16_to_cpus(&dev->descriptor.idProduct);
+ le16_to_cpus(&dev->descriptor.bcdDevice);
+
+ /*
+ * Kingston DT Ultimate 32GB USB 3.0 seems to be extremely sensitive
+ * about this first Get Descriptor request. If there are any other
+ * requests in the first microframe, the stick crashes. Wait about
+ * one microframe duration here (1mS for USB 1.x , 125uS for USB 2.0).
+ */
+ mdelay(1);
+
+ /* only support for one config for now */
+ err = usb_get_configuration_len(dev, 0);
+ if (err >= 0) {
+ tmpbuf = (unsigned char *)malloc_cache_aligned(err);
+ if (!tmpbuf)
+ err = -ENOMEM;
+ else
+ err = usb_get_configuration_no(dev, 0, tmpbuf, err);
+ }
+ if (err < 0) {
+ printf("usb_new_device: Cannot read configuration, " \
+ "skipping device %04x:%04x\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ free(tmpbuf);
+ return err;
+ }
+ usb_parse_config(dev, tmpbuf, 0);
+ free(tmpbuf);
+ usb_set_maxpacket(dev);
+ /*
+ * we set the default configuration here
+ * This seems premature. If the driver wants a different configuration
+ * it will need to select itself.
+ */
+ err = usb_set_configuration(dev, dev->config.desc.bConfigurationValue);
+ if (err < 0) {
+ printf("failed to set default configuration " \
+ "len %d, status %lX\n", dev->act_len, dev->status);
+ return err;
+ }
+
+ /*
+ * Wait until the Set Configuration request gets processed by the
+ * device. This is required by at least SanDisk Cruzer Pop USB 2.0
+ * and Kingston DT Ultimate 32GB USB 3.0 on DWC2 OTG controller.
+ */
+ mdelay(10);
+
+ debug("new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
+ dev->descriptor.iManufacturer, dev->descriptor.iProduct,
+ dev->descriptor.iSerialNumber);
+ memset(dev->mf, 0, sizeof(dev->mf));
+ memset(dev->prod, 0, sizeof(dev->prod));
+ memset(dev->serial, 0, sizeof(dev->serial));
+ if (dev->descriptor.iManufacturer)
+ usb_string(dev, dev->descriptor.iManufacturer,
+ dev->mf, sizeof(dev->mf));
+ if (dev->descriptor.iProduct)
+ usb_string(dev, dev->descriptor.iProduct,
+ dev->prod, sizeof(dev->prod));
+ if (dev->descriptor.iSerialNumber)
+ usb_string(dev, dev->descriptor.iSerialNumber,
+ dev->serial, sizeof(dev->serial));
+ debug("Manufacturer %s\n", dev->mf);
+ debug("Product %s\n", dev->prod);
+ debug("SerialNumber %s\n", dev->serial);
+
+ return 0;
+}
+
+int usb_setup_device(struct usb_device *dev, bool do_read,
+ struct usb_device *parent)
+{
+ int addr;
+ int ret;
+
+ /* We still haven't set the Address yet */
+ addr = dev->devnum;
+ dev->devnum = 0;
+
+ ret = usb_prepare_device(dev, addr, do_read, parent);
+ if (ret)
+ return ret;
+ ret = usb_select_config(dev);
+
+ return ret;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+/*
+ * By the time we get here, the device has gotten a new device ID
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
+ */
+int usb_new_device(struct usb_device *dev)
+{
+ bool do_read = true;
+ int err;
+
+ /*
+ * XHCI needs to issue a Address device command to setup
+ * proper device context structures, before it can interact
+ * with the device. So a get_descriptor will fail before any
+ * of that is done for XHCI unlike EHCI.
+ */
+#ifdef CONFIG_USB_XHCI_HCD
+ do_read = false;
+#endif
+ err = usb_setup_device(dev, do_read, dev->parent);
+ if (err)
+ return err;
+
+ /* Now probe if the device is a hub */
+ err = usb_hub_probe(dev, 0);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+#endif
+
+__weak
+int board_usb_init(int index, enum usb_init_type init)
+{
+ return 0;
+}
+
+__weak
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+ return 0;
+}
+
+bool usb_device_has_child_on_port(struct usb_device *parent, int port)
+{
+#if CONFIG_IS_ENABLED(DM_USB)
+ return false;
+#else
+ return parent->children[port] != NULL;
+#endif
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+void usb_find_usb2_hub_address_port(struct usb_device *udev,
+ uint8_t *hub_address, uint8_t *hub_port)
+{
+ struct udevice *parent;
+ struct usb_device *uparent, *ttdev;
+
+ /*
+ * When called from usb-uclass.c: usb_scan_device() udev->dev points
+ * to the parent udevice, not the actual udevice belonging to the
+ * udev as the device is not instantiated yet. So when searching
+ * for the first usb-2 parent start with udev->dev not
+ * udev->dev->parent .
+ */
+ ttdev = udev;
+ parent = udev->dev;
+ uparent = dev_get_parent_priv(parent);
+
+ while (uparent->speed != USB_SPEED_HIGH) {
+ struct udevice *dev = parent;
+
+ if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
+ printf("Error: Cannot find high speed parent of usb-1 device\n");
+ *hub_address = 0;
+ *hub_port = 0;
+ return;
+ }
+
+ ttdev = dev_get_parent_priv(dev);
+ parent = dev->parent;
+ uparent = dev_get_parent_priv(parent);
+ }
+ *hub_address = uparent->devnum;
+ *hub_port = ttdev->portnr;
+}
+#else
+void usb_find_usb2_hub_address_port(struct usb_device *udev,
+ uint8_t *hub_address, uint8_t *hub_port)
+{
+ /* Find out the nearest parent which is high speed */
+ while (udev->parent->parent != NULL)
+ if (udev->parent->speed != USB_SPEED_HIGH) {
+ udev = udev->parent;
+ } else {
+ *hub_address = udev->parent->devnum;
+ *hub_port = udev->portnr;
+ return;
+ }
+
+ printf("Error: Cannot find high speed parent of usb-1 device\n");
+ *hub_address = 0;
+ *hub_port = 0;
+}
+#endif
+
+
+/* EOF */
diff --git a/roms/u-boot/common/usb_hub.c b/roms/u-boot/common/usb_hub.c
new file mode 100644
index 000000000..ba11a188c
--- /dev/null
+++ b/roms/u-boot/common/usb_hub.c
@@ -0,0 +1,977 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Most of this source has been derived from the Linux USB
+ * project:
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ *
+ * Adapted for U-Boot:
+ * (C) Copyright 2001 Denis Peter, MPL AG Switzerland
+ */
+
+/****************************************************************************
+ * HUB "Driver"
+ * Probes device for being a hub and configurate it
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <env.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <asm/processor.h>
+#include <asm/unaligned.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <asm/byteorder.h>
+#ifdef CONFIG_SANDBOX
+#include <asm/state.h>
+#endif
+#include <asm/unaligned.h>
+
+#include <usb.h>
+
+#define USB_BUFSIZ 512
+
+#define HUB_SHORT_RESET_TIME 20
+#define HUB_LONG_RESET_TIME 200
+
+#define PORT_OVERCURRENT_MAX_SCAN_COUNT 3
+
+struct usb_device_scan {
+ struct usb_device *dev; /* USB hub device to scan */
+ struct usb_hub_device *hub; /* USB hub struct */
+ int port; /* USB port to scan */
+ struct list_head list;
+};
+
+static LIST_HEAD(usb_scan_list);
+
+__weak void usb_hub_reset_devices(struct usb_hub_device *hub, int port)
+{
+ return;
+}
+
+static inline bool usb_hub_is_superspeed(struct usb_device *hdev)
+{
+ return hdev->descriptor.bDeviceProtocol == 3;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+bool usb_hub_is_root_hub(struct udevice *hub)
+{
+ if (device_get_uclass_id(hub->parent) != UCLASS_USB_HUB)
+ return true;
+
+ return false;
+}
+
+static int usb_set_hub_depth(struct usb_device *dev, int depth)
+{
+ if (depth < 0 || depth > 4)
+ return -EINVAL;
+
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_HUB_DEPTH, USB_DIR_OUT | USB_RT_HUB,
+ depth, 0, NULL, 0, USB_CNTL_TIMEOUT);
+}
+#endif
+
+static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+ unsigned short dtype = USB_DT_HUB;
+
+ if (usb_hub_is_superspeed(dev))
+ dtype = USB_DT_SS_HUB;
+
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
+ dtype << 8, 0, data, size, USB_CNTL_TIMEOUT);
+}
+
+static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature,
+ port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT, feature,
+ port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+static int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
+ data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+}
+
+int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+ int ret;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
+ data, sizeof(struct usb_port_status), USB_CNTL_TIMEOUT);
+
+#if CONFIG_IS_ENABLED(DM_USB)
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Translate the USB 3.0 hub port status field into the old version
+ * that U-Boot understands. Do this only when the hub is not root hub.
+ * For root hub, the port status field has already been translated
+ * in the host controller driver (see xhci_submit_root() in xhci.c).
+ *
+ * Note: this only supports driver model.
+ */
+
+ if (!usb_hub_is_root_hub(dev->dev) && usb_hub_is_superspeed(dev)) {
+ struct usb_port_status *status = (struct usb_port_status *)data;
+ u16 tmp = le16_to_cpu(status->wPortStatus) &
+ USB_SS_PORT_STAT_MASK;
+
+ if (status->wPortStatus & USB_SS_PORT_STAT_POWER)
+ tmp |= USB_PORT_STAT_POWER;
+ if ((status->wPortStatus & USB_SS_PORT_STAT_SPEED) ==
+ USB_SS_PORT_STAT_SPEED_5GBPS)
+ tmp |= USB_PORT_STAT_SUPER_SPEED;
+
+ status->wPortStatus = cpu_to_le16(tmp);
+ }
+#endif
+
+ return ret;
+}
+
+
+static void usb_hub_power_on(struct usb_hub_device *hub)
+{
+ int i;
+ struct usb_device *dev;
+ unsigned pgood_delay = hub->desc.bPwrOn2PwrGood * 2;
+ const char *env;
+
+ dev = hub->pusb_dev;
+
+ debug("enabling power on all ports\n");
+ for (i = 0; i < dev->maxchild; i++) {
+ usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+ debug("port %d returns %lX\n", i + 1, dev->status);
+ }
+
+#ifdef CONFIG_SANDBOX
+ /*
+ * Don't set timeout / delay values here. This results
+ * in these values still being reset to 0.
+ */
+ if (state_get_skip_delays())
+ return;
+#endif
+
+ /*
+ * Wait for power to become stable,
+ * plus spec-defined max time for device to connect
+ * but allow this time to be increased via env variable as some
+ * devices break the spec and require longer warm-up times
+ */
+ env = env_get("usb_pgood_delay");
+ if (env)
+ pgood_delay = max(pgood_delay,
+ (unsigned)simple_strtol(env, NULL, 0));
+ debug("pgood_delay=%dms\n", pgood_delay);
+
+ /*
+ * Do a minimum delay of the larger value of 100ms or pgood_delay
+ * so that the power can stablize before the devices are queried
+ */
+ hub->query_delay = get_timer(0) + max(100, (int)pgood_delay);
+
+ /*
+ * Record the power-on timeout here. The max. delay (timeout)
+ * will be done based on this value in the USB port loop in
+ * usb_hub_configure() later.
+ */
+ hub->connect_timeout = hub->query_delay + 1000;
+ debug("devnum=%d poweron: query_delay=%d connect_timeout=%d\n",
+ dev->devnum, max(100, (int)pgood_delay),
+ max(100, (int)pgood_delay) + 1000);
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+static struct usb_hub_device hub_dev[USB_MAX_HUB];
+static int usb_hub_index;
+
+void usb_hub_reset(void)
+{
+ usb_hub_index = 0;
+
+ /* Zero out global hub_dev in case its re-used again */
+ memset(hub_dev, 0, sizeof(hub_dev));
+}
+
+static struct usb_hub_device *usb_hub_allocate(void)
+{
+ if (usb_hub_index < USB_MAX_HUB)
+ return &hub_dev[usb_hub_index++];
+
+ printf("ERROR: USB_MAX_HUB (%d) reached\n", USB_MAX_HUB);
+ return NULL;
+}
+#endif
+
+#define MAX_TRIES 5
+
+static inline const char *portspeed(int portstatus)
+{
+ switch (portstatus & USB_PORT_STAT_SPEED_MASK) {
+ case USB_PORT_STAT_SUPER_SPEED:
+ return "5 Gb/s";
+ case USB_PORT_STAT_HIGH_SPEED:
+ return "480 Mb/s";
+ case USB_PORT_STAT_LOW_SPEED:
+ return "1.5 Mb/s";
+ default:
+ return "12 Mb/s";
+ }
+}
+
+/**
+ * usb_hub_port_reset() - reset a port given its usb_device pointer
+ *
+ * Reset a hub port and see if a device is present on that port, providing
+ * sufficient time for it to show itself. The port status is returned.
+ *
+ * @dev: USB device to reset
+ * @port: Port number to reset (note ports are numbered from 0 here)
+ * @portstat: Returns port status
+ */
+static int usb_hub_port_reset(struct usb_device *dev, int port,
+ unsigned short *portstat)
+{
+ int err, tries;
+ ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
+ unsigned short portstatus, portchange;
+ int delay = HUB_SHORT_RESET_TIME; /* start with short reset delay */
+
+#if CONFIG_IS_ENABLED(DM_USB)
+ debug("%s: resetting '%s' port %d...\n", __func__, dev->dev->name,
+ port + 1);
+#else
+ debug("%s: resetting port %d...\n", __func__, port + 1);
+#endif
+ for (tries = 0; tries < MAX_TRIES; tries++) {
+ err = usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
+ if (err < 0)
+ return err;
+
+ mdelay(delay);
+
+ if (usb_get_port_status(dev, port + 1, portsts) < 0) {
+ debug("get_port_status failed status %lX\n",
+ dev->status);
+ return -1;
+ }
+ portstatus = le16_to_cpu(portsts->wPortStatus);
+ portchange = le16_to_cpu(portsts->wPortChange);
+
+ debug("portstatus %x, change %x, %s\n", portstatus, portchange,
+ portspeed(portstatus));
+
+ debug("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \
+ " USB_PORT_STAT_ENABLE %d\n",
+ (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0,
+ (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0,
+ (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
+
+ /*
+ * Perhaps we should check for the following here:
+ * - C_CONNECTION hasn't been set.
+ * - CONNECTION is still set.
+ *
+ * Doing so would ensure that the device is still connected
+ * to the bus, and hasn't been unplugged or replaced while the
+ * USB bus reset was going on.
+ *
+ * However, if we do that, then (at least) a San Disk Ultra
+ * USB 3.0 16GB device fails to reset on (at least) an NVIDIA
+ * Tegra Jetson TK1 board. For some reason, the device appears
+ * to briefly drop off the bus when this second bus reset is
+ * executed, yet if we retry this loop, it'll eventually come
+ * back after another reset or two.
+ */
+
+ if (portstatus & USB_PORT_STAT_ENABLE)
+ break;
+
+ /* Switch to long reset delay for the next round */
+ delay = HUB_LONG_RESET_TIME;
+ }
+
+ if (tries == MAX_TRIES) {
+ debug("Cannot enable port %i after %i retries, " \
+ "disabling port.\n", port + 1, MAX_TRIES);
+ debug("Maybe the USB cable is bad?\n");
+ return -1;
+ }
+
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET);
+ *portstat = portstatus;
+ return 0;
+}
+
+int usb_hub_port_connect_change(struct usb_device *dev, int port)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
+ unsigned short portstatus;
+ int ret, speed;
+
+ /* Check status */
+ ret = usb_get_port_status(dev, port + 1, portsts);
+ if (ret < 0) {
+ debug("get_port_status failed\n");
+ return ret;
+ }
+
+ portstatus = le16_to_cpu(portsts->wPortStatus);
+ debug("portstatus %x, change %x, %s\n",
+ portstatus,
+ le16_to_cpu(portsts->wPortChange),
+ portspeed(portstatus));
+
+ /* Clear the connection change status */
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
+
+ /* Disconnect any existing devices under this port */
+ if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
+ (!(portstatus & USB_PORT_STAT_ENABLE))) ||
+ usb_device_has_child_on_port(dev, port)) {
+ debug("usb_disconnect(&hub->children[port]);\n");
+ /* Return now if nothing is connected */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return -ENOTCONN;
+ }
+
+ /* Reset the port */
+ ret = usb_hub_port_reset(dev, port, &portstatus);
+ if (ret < 0) {
+ if (ret != -ENXIO)
+ printf("cannot reset port %i!?\n", port + 1);
+ return ret;
+ }
+
+ switch (portstatus & USB_PORT_STAT_SPEED_MASK) {
+ case USB_PORT_STAT_SUPER_SPEED:
+ speed = USB_SPEED_SUPER;
+ break;
+ case USB_PORT_STAT_HIGH_SPEED:
+ speed = USB_SPEED_HIGH;
+ break;
+ case USB_PORT_STAT_LOW_SPEED:
+ speed = USB_SPEED_LOW;
+ break;
+ default:
+ speed = USB_SPEED_FULL;
+ break;
+ }
+
+#if CONFIG_IS_ENABLED(DM_USB)
+ struct udevice *child;
+
+ ret = usb_scan_device(dev->dev, port + 1, speed, &child);
+#else
+ struct usb_device *usb;
+
+ ret = usb_alloc_new_device(dev->controller, &usb);
+ if (ret) {
+ printf("cannot create new device: ret=%d", ret);
+ return ret;
+ }
+
+ dev->children[port] = usb;
+ usb->speed = speed;
+ usb->parent = dev;
+ usb->portnr = port + 1;
+ /* Run it through the hoops (find a driver, etc) */
+ ret = usb_new_device(usb);
+ if (ret < 0) {
+ /* Woops, disable the port */
+ usb_free_device(dev->controller);
+ dev->children[port] = NULL;
+ }
+#endif
+ if (ret < 0) {
+ debug("hub: disabling port %d\n", port + 1);
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
+ }
+
+ return ret;
+}
+
+static int usb_scan_port(struct usb_device_scan *usb_scan)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
+ unsigned short portstatus;
+ unsigned short portchange;
+ struct usb_device *dev;
+ struct usb_hub_device *hub;
+ int ret = 0;
+ int i;
+
+ dev = usb_scan->dev;
+ hub = usb_scan->hub;
+ i = usb_scan->port;
+
+ /*
+ * Don't talk to the device before the query delay is expired.
+ * This is needed for voltages to stabalize.
+ */
+ if (get_timer(0) < hub->query_delay)
+ return 0;
+
+ ret = usb_get_port_status(dev, i + 1, portsts);
+ if (ret < 0) {
+ debug("get_port_status failed\n");
+ if (get_timer(0) >= hub->connect_timeout) {
+ debug("devnum=%d port=%d: timeout\n",
+ dev->devnum, i + 1);
+ /* Remove this device from scanning list */
+ list_del(&usb_scan->list);
+ free(usb_scan);
+ return 0;
+ }
+ return 0;
+ }
+
+ portstatus = le16_to_cpu(portsts->wPortStatus);
+ portchange = le16_to_cpu(portsts->wPortChange);
+ debug("Port %d Status %X Change %X\n", i + 1, portstatus, portchange);
+
+ /*
+ * No connection change happened, wait a bit more.
+ *
+ * For some situation, the hub reports no connection change but a
+ * device is connected to the port (eg: CCS bit is set but CSC is not
+ * in the PORTSC register of a root hub), ignore such case.
+ */
+ if (!(portchange & USB_PORT_STAT_C_CONNECTION) &&
+ !(portstatus & USB_PORT_STAT_CONNECTION)) {
+ if (get_timer(0) >= hub->connect_timeout) {
+ debug("devnum=%d port=%d: timeout\n",
+ dev->devnum, i + 1);
+ /* Remove this device from scanning list */
+ list_del(&usb_scan->list);
+ free(usb_scan);
+ return 0;
+ }
+ return 0;
+ }
+
+ if (portchange & USB_PORT_STAT_C_RESET) {
+ debug("port %d reset change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
+ }
+
+ if ((portchange & USB_SS_PORT_STAT_C_BH_RESET) &&
+ usb_hub_is_superspeed(dev)) {
+ debug("port %d BH reset change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1, USB_SS_PORT_FEAT_C_BH_RESET);
+ }
+
+ /* A new USB device is ready at this point */
+ debug("devnum=%d port=%d: USB dev found\n", dev->devnum, i + 1);
+
+ usb_hub_port_connect_change(dev, i);
+
+ if (portchange & USB_PORT_STAT_C_ENABLE) {
+ debug("port %d enable change, status %x\n", i + 1, portstatus);
+ usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
+ /*
+ * The following hack causes a ghost device problem
+ * to Faraday EHCI
+ */
+#ifndef CONFIG_USB_EHCI_FARADAY
+ /*
+ * EM interference sometimes causes bad shielded USB
+ * devices to be shutdown by the hub, this hack enables
+ * them again. Works at least with mouse driver
+ */
+ if (!(portstatus & USB_PORT_STAT_ENABLE) &&
+ (portstatus & USB_PORT_STAT_CONNECTION) &&
+ usb_device_has_child_on_port(dev, i)) {
+ debug("already running port %i disabled by hub (EMI?), re-enabling...\n",
+ i + 1);
+ usb_hub_port_connect_change(dev, i);
+ }
+#endif
+ }
+
+ if (portstatus & USB_PORT_STAT_SUSPEND) {
+ debug("port %d suspend change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND);
+ }
+
+ if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+ debug("port %d over-current change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1,
+ USB_PORT_FEAT_C_OVER_CURRENT);
+ /* Only power-on this one port */
+ usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+ hub->overcurrent_count[i]++;
+
+ /*
+ * If the max-scan-count is not reached, return without removing
+ * the device from scan-list. This will re-issue a new scan.
+ */
+ if (hub->overcurrent_count[i] <=
+ PORT_OVERCURRENT_MAX_SCAN_COUNT)
+ return 0;
+
+ /* Otherwise the device will get removed */
+ printf("Port %d over-current occurred %d times\n", i + 1,
+ hub->overcurrent_count[i]);
+ }
+
+ /*
+ * We're done with this device, so let's remove this device from
+ * scanning list
+ */
+ list_del(&usb_scan->list);
+ free(usb_scan);
+
+ return 0;
+}
+
+static int usb_device_list_scan(void)
+{
+ struct usb_device_scan *usb_scan;
+ struct usb_device_scan *tmp;
+ static int running;
+ int ret = 0;
+
+ /* Only run this loop once for each controller */
+ if (running)
+ return 0;
+
+ running = 1;
+
+ while (1) {
+ /* We're done, once the list is empty again */
+ if (list_empty(&usb_scan_list))
+ goto out;
+
+ list_for_each_entry_safe(usb_scan, tmp, &usb_scan_list, list) {
+ int ret;
+
+ /* Scan this port */
+ ret = usb_scan_port(usb_scan);
+ if (ret)
+ goto out;
+ }
+ }
+
+out:
+ /*
+ * This USB controller has finished scanning all its connected
+ * USB devices. Set "running" back to 0, so that other USB controllers
+ * will scan their devices too.
+ */
+ running = 0;
+
+ return ret;
+}
+
+static struct usb_hub_device *usb_get_hub_device(struct usb_device *dev)
+{
+ struct usb_hub_device *hub;
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+ /* "allocate" Hub device */
+ hub = usb_hub_allocate();
+#else
+ hub = dev_get_uclass_priv(dev->dev);
+#endif
+
+ return hub;
+}
+
+static int usb_hub_configure(struct usb_device *dev)
+{
+ int i, length;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, USB_BUFSIZ);
+ unsigned char *bitmap;
+ short hubCharacteristics;
+ struct usb_hub_descriptor *descriptor;
+ struct usb_hub_device *hub;
+ struct usb_hub_status *hubsts;
+ int ret;
+
+ hub = usb_get_hub_device(dev);
+ if (hub == NULL)
+ return -ENOMEM;
+ hub->pusb_dev = dev;
+
+ /* Get the the hub descriptor */
+ ret = usb_get_hub_descriptor(dev, buffer, 4);
+ if (ret < 0) {
+ debug("usb_hub_configure: failed to get hub " \
+ "descriptor, giving up %lX\n", dev->status);
+ return ret;
+ }
+ descriptor = (struct usb_hub_descriptor *)buffer;
+
+ length = min_t(int, descriptor->bLength,
+ sizeof(struct usb_hub_descriptor));
+
+ ret = usb_get_hub_descriptor(dev, buffer, length);
+ if (ret < 0) {
+ debug("usb_hub_configure: failed to get hub " \
+ "descriptor 2nd giving up %lX\n", dev->status);
+ return ret;
+ }
+ memcpy((unsigned char *)&hub->desc, buffer, length);
+ /* adjust 16bit values */
+ put_unaligned(le16_to_cpu(get_unaligned(
+ &descriptor->wHubCharacteristics)),
+ &hub->desc.wHubCharacteristics);
+ /* set the bitmap */
+ bitmap = (unsigned char *)&hub->desc.u.hs.DeviceRemovable[0];
+ /* devices not removable by default */
+ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8);
+ bitmap = (unsigned char *)&hub->desc.u.hs.PortPowerCtrlMask[0];
+ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */
+
+ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++)
+ hub->desc.u.hs.DeviceRemovable[i] =
+ descriptor->u.hs.DeviceRemovable[i];
+
+ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++)
+ hub->desc.u.hs.PortPowerCtrlMask[i] =
+ descriptor->u.hs.PortPowerCtrlMask[i];
+
+ dev->maxchild = descriptor->bNbrPorts;
+ debug("%d ports detected\n", dev->maxchild);
+
+ hubCharacteristics = get_unaligned(&hub->desc.wHubCharacteristics);
+ switch (hubCharacteristics & HUB_CHAR_LPSM) {
+ case 0x00:
+ debug("ganged power switching\n");
+ break;
+ case 0x01:
+ debug("individual port power switching\n");
+ break;
+ case 0x02:
+ case 0x03:
+ debug("unknown reserved power switching mode\n");
+ break;
+ }
+
+ if (hubCharacteristics & HUB_CHAR_COMPOUND)
+ debug("part of a compound device\n");
+ else
+ debug("standalone hub\n");
+
+ switch (hubCharacteristics & HUB_CHAR_OCPM) {
+ case 0x00:
+ debug("global over-current protection\n");
+ break;
+ case 0x08:
+ debug("individual port over-current protection\n");
+ break;
+ case 0x10:
+ case 0x18:
+ debug("no over-current protection\n");
+ break;
+ }
+
+ switch (dev->descriptor.bDeviceProtocol) {
+ case USB_HUB_PR_FS:
+ break;
+ case USB_HUB_PR_HS_SINGLE_TT:
+ debug("Single TT\n");
+ break;
+ case USB_HUB_PR_HS_MULTI_TT:
+ ret = usb_set_interface(dev, 0, 1);
+ if (ret == 0) {
+ debug("TT per port\n");
+ hub->tt.multi = true;
+ } else {
+ debug("Using single TT (err %d)\n", ret);
+ }
+ break;
+ case USB_HUB_PR_SS:
+ /* USB 3.0 hubs don't have a TT */
+ break;
+ default:
+ debug("Unrecognized hub protocol %d\n",
+ dev->descriptor.bDeviceProtocol);
+ break;
+ }
+
+ /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
+ switch (hubCharacteristics & HUB_CHAR_TTTT) {
+ case HUB_TTTT_8_BITS:
+ if (dev->descriptor.bDeviceProtocol != 0) {
+ hub->tt.think_time = 666;
+ debug("TT requires at most %d FS bit times (%d ns)\n",
+ 8, hub->tt.think_time);
+ }
+ break;
+ case HUB_TTTT_16_BITS:
+ hub->tt.think_time = 666 * 2;
+ debug("TT requires at most %d FS bit times (%d ns)\n",
+ 16, hub->tt.think_time);
+ break;
+ case HUB_TTTT_24_BITS:
+ hub->tt.think_time = 666 * 3;
+ debug("TT requires at most %d FS bit times (%d ns)\n",
+ 24, hub->tt.think_time);
+ break;
+ case HUB_TTTT_32_BITS:
+ hub->tt.think_time = 666 * 4;
+ debug("TT requires at most %d FS bit times (%d ns)\n",
+ 32, hub->tt.think_time);
+ break;
+ }
+
+ debug("power on to power good time: %dms\n",
+ descriptor->bPwrOn2PwrGood * 2);
+ debug("hub controller current requirement: %dmA\n",
+ descriptor->bHubContrCurrent);
+
+ for (i = 0; i < dev->maxchild; i++)
+ debug("port %d is%s removable\n", i + 1,
+ hub->desc.u.hs.DeviceRemovable[(i + 1) / 8] & \
+ (1 << ((i + 1) % 8)) ? " not" : "");
+
+ if (sizeof(struct usb_hub_status) > USB_BUFSIZ) {
+ debug("usb_hub_configure: failed to get Status - " \
+ "too long: %d\n", descriptor->bLength);
+ return -EFBIG;
+ }
+
+ ret = usb_get_hub_status(dev, buffer);
+ if (ret < 0) {
+ debug("usb_hub_configure: failed to get Status %lX\n",
+ dev->status);
+ return ret;
+ }
+
+ hubsts = (struct usb_hub_status *)buffer;
+
+ debug("get_hub_status returned status %X, change %X\n",
+ le16_to_cpu(hubsts->wHubStatus),
+ le16_to_cpu(hubsts->wHubChange));
+ debug("local power source is %s\n",
+ (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \
+ "lost (inactive)" : "good");
+ debug("%sover-current condition exists\n",
+ (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
+ "" : "no ");
+
+#if CONFIG_IS_ENABLED(DM_USB)
+ /*
+ * Update USB host controller's internal representation of this hub
+ * after the hub descriptor is fetched.
+ */
+ ret = usb_update_hub_device(dev);
+ if (ret < 0 && ret != -ENOSYS) {
+ debug("%s: failed to update hub device for HCD (%x)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /*
+ * A maximum of seven tiers are allowed in a USB topology, and the
+ * root hub occupies the first tier. The last tier ends with a normal
+ * USB device. USB 3.0 hubs use a 20-bit field called 'route string'
+ * to route packets to the designated downstream port. The hub uses a
+ * hub depth value multiplied by four as an offset into the 'route
+ * string' to locate the bits it uses to determine the downstream
+ * port number.
+ */
+ if (usb_hub_is_root_hub(dev->dev)) {
+ hub->hub_depth = -1;
+ } else {
+ struct udevice *hdev;
+ int depth = 0;
+
+ hdev = dev->dev->parent;
+ while (!usb_hub_is_root_hub(hdev)) {
+ depth++;
+ hdev = hdev->parent;
+ }
+
+ hub->hub_depth = depth;
+
+ if (usb_hub_is_superspeed(dev)) {
+ debug("set hub (%p) depth to %d\n", dev, depth);
+ /*
+ * This request sets the value that the hub uses to
+ * determine the index into the 'route string index'
+ * for this hub.
+ */
+ ret = usb_set_hub_depth(dev, depth);
+ if (ret < 0) {
+ debug("%s: failed to set hub depth (%lX)\n",
+ __func__, dev->status);
+ return ret;
+ }
+ }
+ }
+#endif
+
+ usb_hub_power_on(hub);
+
+ /*
+ * Reset any devices that may be in a bad state when applying
+ * the power. This is a __weak function. Resetting of the devices
+ * should occur in the board file of the device.
+ */
+ for (i = 0; i < dev->maxchild; i++)
+ usb_hub_reset_devices(hub, i + 1);
+
+ /*
+ * Only add the connected USB devices, including potential hubs,
+ * to a scanning list. This list will get scanned and devices that
+ * are detected (either via port connected or via port timeout)
+ * will get removed from this list. Scanning of the devices on this
+ * list will continue until all devices are removed.
+ */
+ for (i = 0; i < dev->maxchild; i++) {
+ struct usb_device_scan *usb_scan;
+
+ usb_scan = calloc(1, sizeof(*usb_scan));
+ if (!usb_scan) {
+ printf("Can't allocate memory for USB device!\n");
+ return -ENOMEM;
+ }
+ usb_scan->dev = dev;
+ usb_scan->hub = hub;
+ usb_scan->port = i;
+ list_add_tail(&usb_scan->list, &usb_scan_list);
+ }
+
+ /*
+ * And now call the scanning code which loops over the generated list
+ */
+ ret = usb_device_list_scan();
+
+ return ret;
+}
+
+static int usb_hub_check(struct usb_device *dev, int ifnum)
+{
+ struct usb_interface *iface;
+ struct usb_endpoint_descriptor *ep = NULL;
+
+ iface = &dev->config.if_desc[ifnum];
+ /* Is it a hub? */
+ if (iface->desc.bInterfaceClass != USB_CLASS_HUB)
+ goto err;
+ /* Some hubs have a subclass of 1, which AFAICT according to the */
+ /* specs is not defined, but it works */
+ if ((iface->desc.bInterfaceSubClass != 0) &&
+ (iface->desc.bInterfaceSubClass != 1))
+ goto err;
+ /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+ if (iface->desc.bNumEndpoints != 1)
+ goto err;
+ ep = &iface->ep_desc[0];
+ /* Output endpoint? Curiousier and curiousier.. */
+ if (!(ep->bEndpointAddress & USB_DIR_IN))
+ goto err;
+ /* If it's not an interrupt endpoint, we'd better punt! */
+ if ((ep->bmAttributes & 3) != 3)
+ goto err;
+ /* We found a hub */
+ debug("USB hub found\n");
+ return 0;
+
+err:
+ debug("USB hub not found: bInterfaceClass=%d, bInterfaceSubClass=%d, bNumEndpoints=%d\n",
+ iface->desc.bInterfaceClass, iface->desc.bInterfaceSubClass,
+ iface->desc.bNumEndpoints);
+ if (ep) {
+ debug(" bEndpointAddress=%#x, bmAttributes=%d",
+ ep->bEndpointAddress, ep->bmAttributes);
+ }
+
+ return -ENOENT;
+}
+
+int usb_hub_probe(struct usb_device *dev, int ifnum)
+{
+ int ret;
+
+ ret = usb_hub_check(dev, ifnum);
+ if (ret)
+ return 0;
+ ret = usb_hub_configure(dev);
+ return ret;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+int usb_hub_scan(struct udevice *hub)
+{
+ struct usb_device *udev = dev_get_parent_priv(hub);
+
+ return usb_hub_configure(udev);
+}
+
+static int usb_hub_post_probe(struct udevice *dev)
+{
+ debug("%s\n", __func__);
+ return usb_hub_scan(dev);
+}
+
+static const struct udevice_id usb_hub_ids[] = {
+ { .compatible = "usb-hub" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_generic_hub) = {
+ .name = "usb_hub",
+ .id = UCLASS_USB_HUB,
+ .of_match = usb_hub_ids,
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+UCLASS_DRIVER(usb_hub) = {
+ .id = UCLASS_USB_HUB,
+ .name = "usb_hub",
+ .post_bind = dm_scan_fdt_dev,
+ .post_probe = usb_hub_post_probe,
+ .child_pre_probe = usb_child_pre_probe,
+ .per_child_auto = sizeof(struct usb_device),
+ .per_child_plat_auto = sizeof(struct usb_dev_plat),
+ .per_device_auto = sizeof(struct usb_hub_device),
+};
+
+static const struct usb_device_id hub_id_table[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
+ .bDeviceClass = USB_CLASS_HUB
+ },
+ { } /* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(usb_generic_hub, hub_id_table);
+
+#endif
diff --git a/roms/u-boot/common/usb_kbd.c b/roms/u-boot/common/usb_kbd.c
new file mode 100644
index 000000000..afad260d3
--- /dev/null
+++ b/roms/u-boot/common/usb_kbd.c
@@ -0,0 +1,717 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * Part of this source has been derived from the Linux USB
+ * project.
+ */
+#include <common.h>
+#include <console.h>
+#include <dm.h>
+#include <env.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <stdio_dev.h>
+#include <watchdog.h>
+#include <asm/byteorder.h>
+
+#include <usb.h>
+
+/*
+ * If overwrite_console returns 1, the stdin, stderr and stdout
+ * are switched to the serial port, else the settings in the
+ * environment are used
+ */
+#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
+extern int overwrite_console(void);
+#else
+int overwrite_console(void)
+{
+ return 0;
+}
+#endif
+
+/* Keyboard sampling rate */
+#define REPEAT_RATE 40 /* 40msec -> 25cps */
+#define REPEAT_DELAY 10 /* 10 x REPEAT_RATE = 400msec */
+
+#define NUM_LOCK 0x53
+#define CAPS_LOCK 0x39
+#define SCROLL_LOCK 0x47
+
+/* Modifier bits */
+#define LEFT_CNTR (1 << 0)
+#define LEFT_SHIFT (1 << 1)
+#define LEFT_ALT (1 << 2)
+#define LEFT_GUI (1 << 3)
+#define RIGHT_CNTR (1 << 4)
+#define RIGHT_SHIFT (1 << 5)
+#define RIGHT_ALT (1 << 6)
+#define RIGHT_GUI (1 << 7)
+
+/* Size of the keyboard buffer */
+#define USB_KBD_BUFFER_LEN 0x20
+
+/* Device name */
+#define DEVNAME "usbkbd"
+
+/* Keyboard maps */
+static const unsigned char usb_kbd_numkey[] = {
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
+ '\r', 0x1b, '\b', '\t', ' ', '-', '=', '[', ']',
+ '\\', '#', ';', '\'', '`', ',', '.', '/'
+};
+static const unsigned char usb_kbd_numkey_shifted[] = {
+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+ '\r', 0x1b, '\b', '\t', ' ', '_', '+', '{', '}',
+ '|', '~', ':', '"', '~', '<', '>', '?'
+};
+
+static const unsigned char usb_kbd_num_keypad[] = {
+ '/', '*', '-', '+', '\r',
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
+ '.', 0, 0, 0, '='
+};
+
+static const u8 usb_special_keys[] = {
+#ifdef CONFIG_USB_KEYBOARD_FN_KEYS
+ '2', 'H', '5', '3', 'F', '6', 'C', 'D', 'B', 'A'
+#else
+ 'C', 'D', 'B', 'A'
+#endif
+};
+
+/*
+ * NOTE: It's important for the NUM, CAPS, SCROLL-lock bits to be in this
+ * order. See usb_kbd_setled() function!
+ */
+#define USB_KBD_NUMLOCK (1 << 0)
+#define USB_KBD_CAPSLOCK (1 << 1)
+#define USB_KBD_SCROLLLOCK (1 << 2)
+#define USB_KBD_CTRL (1 << 3)
+
+#define USB_KBD_LEDMASK \
+ (USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK)
+
+struct usb_kbd_pdata {
+ unsigned long intpipe;
+ int intpktsize;
+ int intinterval;
+ unsigned long last_report;
+ struct int_queue *intq;
+
+ uint32_t repeat_delay;
+
+ uint32_t usb_in_pointer;
+ uint32_t usb_out_pointer;
+ uint8_t usb_kbd_buffer[USB_KBD_BUFFER_LEN];
+
+ uint8_t *new;
+ uint8_t old[USB_KBD_BOOT_REPORT_SIZE];
+
+ uint8_t flags;
+};
+
+extern int __maybe_unused net_busy_flag;
+
+/* The period of time between two calls of usb_kbd_testc(). */
+static unsigned long __maybe_unused kbd_testc_tms;
+
+/* Puts character in the queue and sets up the in and out pointer. */
+static void usb_kbd_put_queue(struct usb_kbd_pdata *data, u8 c)
+{
+ if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
+ /* Check for buffer full. */
+ if (data->usb_out_pointer == 0)
+ return;
+
+ data->usb_in_pointer = 0;
+ } else {
+ /* Check for buffer full. */
+ if (data->usb_in_pointer == data->usb_out_pointer - 1)
+ return;
+
+ data->usb_in_pointer++;
+ }
+
+ data->usb_kbd_buffer[data->usb_in_pointer] = c;
+}
+
+/*
+ * Set the LEDs. Since this is used in the irq routine, the control job is
+ * issued with a timeout of 0. This means, that the job is queued without
+ * waiting for job completion.
+ */
+static void usb_kbd_setled(struct usb_device *dev)
+{
+ struct usb_interface *iface = &dev->config.if_desc[0];
+ struct usb_kbd_pdata *data = dev->privptr;
+ ALLOC_ALIGN_BUFFER(uint32_t, leds, 1, USB_DMA_MINALIGN);
+
+ *leds = data->flags & USB_KBD_LEDMASK;
+ usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x200, iface->desc.bInterfaceNumber, leds, 1, 0);
+}
+
+#define CAPITAL_MASK 0x20
+/* Translate the scancode in ASCII */
+static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode,
+ unsigned char modifier, int pressed)
+{
+ uint8_t keycode = 0;
+
+ /* Key released */
+ if (pressed == 0) {
+ data->repeat_delay = 0;
+ return 0;
+ }
+
+ if (pressed == 2) {
+ data->repeat_delay++;
+ if (data->repeat_delay < REPEAT_DELAY)
+ return 0;
+
+ data->repeat_delay = REPEAT_DELAY;
+ }
+
+ /* Alphanumeric values */
+ if ((scancode > 3) && (scancode <= 0x1d)) {
+ keycode = scancode - 4 + 'a';
+
+ if (data->flags & USB_KBD_CAPSLOCK)
+ keycode &= ~CAPITAL_MASK;
+
+ if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) {
+ /* Handle CAPSLock + Shift pressed simultaneously */
+ if (keycode & CAPITAL_MASK)
+ keycode &= ~CAPITAL_MASK;
+ else
+ keycode |= CAPITAL_MASK;
+ }
+ }
+
+ if ((scancode > 0x1d) && (scancode < 0x39)) {
+ /* Shift pressed */
+ if (modifier & (LEFT_SHIFT | RIGHT_SHIFT))
+ keycode = usb_kbd_numkey_shifted[scancode - 0x1e];
+ else
+ keycode = usb_kbd_numkey[scancode - 0x1e];
+ }
+
+ /* Numeric keypad */
+ if ((scancode >= 0x54) && (scancode <= 0x67))
+ keycode = usb_kbd_num_keypad[scancode - 0x54];
+
+ if (data->flags & USB_KBD_CTRL)
+ keycode = scancode - 0x3;
+
+ if (pressed == 1) {
+ if (scancode == NUM_LOCK) {
+ data->flags ^= USB_KBD_NUMLOCK;
+ return 1;
+ }
+
+ if (scancode == CAPS_LOCK) {
+ data->flags ^= USB_KBD_CAPSLOCK;
+ return 1;
+ }
+ if (scancode == SCROLL_LOCK) {
+ data->flags ^= USB_KBD_SCROLLLOCK;
+ return 1;
+ }
+ }
+
+ /* Report keycode if any */
+ if (keycode) {
+ debug("%c", keycode);
+ usb_kbd_put_queue(data, keycode);
+ return 0;
+ }
+
+#ifdef CONFIG_USB_KEYBOARD_FN_KEYS
+ if (scancode < 0x3a || scancode > 0x52 ||
+ scancode == 0x46 || scancode == 0x47)
+ return 1;
+
+ usb_kbd_put_queue(data, 0x1b);
+ if (scancode < 0x3e) {
+ /* F1 - F4 */
+ usb_kbd_put_queue(data, 0x4f);
+ usb_kbd_put_queue(data, scancode - 0x3a + 'P');
+ return 0;
+ }
+ usb_kbd_put_queue(data, '[');
+ if (scancode < 0x42) {
+ /* F5 - F8 */
+ usb_kbd_put_queue(data, '1');
+ if (scancode == 0x3e)
+ --scancode;
+ keycode = scancode - 0x3f + '7';
+ } else if (scancode < 0x49) {
+ /* F9 - F12 */
+ usb_kbd_put_queue(data, '2');
+ if (scancode > 0x43)
+ ++scancode;
+ keycode = scancode - 0x42 + '0';
+ } else {
+ /*
+ * INSERT, HOME, PAGE UP, DELETE, END, PAGE DOWN,
+ * RIGHT, LEFT, DOWN, UP
+ */
+ keycode = usb_special_keys[scancode - 0x49];
+ }
+ usb_kbd_put_queue(data, keycode);
+ if (scancode < 0x4f && scancode != 0x4a && scancode != 0x4d)
+ usb_kbd_put_queue(data, '~');
+ return 0;
+#else
+ /* Left, Right, Up, Down */
+ if (scancode > 0x4e && scancode < 0x53) {
+ usb_kbd_put_queue(data, 0x1b);
+ usb_kbd_put_queue(data, '[');
+ usb_kbd_put_queue(data, usb_special_keys[scancode - 0x4f]);
+ return 0;
+ }
+ return 1;
+#endif /* CONFIG_USB_KEYBOARD_FN_KEYS */
+}
+
+static uint32_t usb_kbd_service_key(struct usb_device *dev, int i, int up)
+{
+ uint32_t res = 0;
+ struct usb_kbd_pdata *data = dev->privptr;
+ uint8_t *new;
+ uint8_t *old;
+
+ if (up) {
+ new = data->old;
+ old = data->new;
+ } else {
+ new = data->new;
+ old = data->old;
+ }
+
+ if ((old[i] > 3) &&
+ (memscan(new + 2, old[i], USB_KBD_BOOT_REPORT_SIZE - 2) ==
+ new + USB_KBD_BOOT_REPORT_SIZE)) {
+ res |= usb_kbd_translate(data, old[i], data->new[0], up);
+ }
+
+ return res;
+}
+
+/* Interrupt service routine */
+static int usb_kbd_irq_worker(struct usb_device *dev)
+{
+ struct usb_kbd_pdata *data = dev->privptr;
+ int i, res = 0;
+
+ /* No combo key pressed */
+ if (data->new[0] == 0x00)
+ data->flags &= ~USB_KBD_CTRL;
+ /* Left or Right Ctrl pressed */
+ else if ((data->new[0] == LEFT_CNTR) || (data->new[0] == RIGHT_CNTR))
+ data->flags |= USB_KBD_CTRL;
+
+ for (i = 2; i < USB_KBD_BOOT_REPORT_SIZE; i++) {
+ res |= usb_kbd_service_key(dev, i, 0);
+ res |= usb_kbd_service_key(dev, i, 1);
+ }
+
+ /* Key is still pressed */
+ if ((data->new[2] > 3) && (data->old[2] == data->new[2]))
+ res |= usb_kbd_translate(data, data->new[2], data->new[0], 2);
+
+ if (res == 1)
+ usb_kbd_setled(dev);
+
+ memcpy(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE);
+
+ return 1;
+}
+
+/* Keyboard interrupt handler */
+static int usb_kbd_irq(struct usb_device *dev)
+{
+ if ((dev->irq_status != 0) ||
+ (dev->irq_act_len != USB_KBD_BOOT_REPORT_SIZE)) {
+ debug("USB KBD: Error %lX, len %d\n",
+ dev->irq_status, dev->irq_act_len);
+ return 1;
+ }
+
+ return usb_kbd_irq_worker(dev);
+}
+
+/* Interrupt polling */
+static inline void usb_kbd_poll_for_event(struct usb_device *dev)
+{
+#if defined(CONFIG_SYS_USB_EVENT_POLL)
+ struct usb_kbd_pdata *data = dev->privptr;
+
+ /* Submit an interrupt transfer request */
+ if (usb_int_msg(dev, data->intpipe, &data->new[0],
+ data->intpktsize, data->intinterval, true) >= 0)
+ usb_kbd_irq_worker(dev);
+#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) || \
+ defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)
+#if defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)
+ struct usb_interface *iface;
+ struct usb_kbd_pdata *data = dev->privptr;
+ iface = &dev->config.if_desc[0];
+ usb_get_report(dev, iface->desc.bInterfaceNumber,
+ 1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE);
+ if (memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE)) {
+ usb_kbd_irq_worker(dev);
+#else
+ struct usb_kbd_pdata *data = dev->privptr;
+ if (poll_int_queue(dev, data->intq)) {
+ usb_kbd_irq_worker(dev);
+ /* We've consumed all queued int packets, create new */
+ destroy_int_queue(dev, data->intq);
+ data->intq = create_int_queue(dev, data->intpipe, 1,
+ USB_KBD_BOOT_REPORT_SIZE, data->new,
+ data->intinterval);
+#endif
+ data->last_report = get_timer(0);
+ /* Repeat last usb hid report every REPEAT_RATE ms for keyrepeat */
+ } else if (data->last_report != -1 &&
+ get_timer(data->last_report) > REPEAT_RATE) {
+ usb_kbd_irq_worker(dev);
+ data->last_report = get_timer(0);
+ }
+#endif
+}
+
+/* test if a character is in the queue */
+static int usb_kbd_testc(struct stdio_dev *sdev)
+{
+ struct stdio_dev *dev;
+ struct usb_device *usb_kbd_dev;
+ struct usb_kbd_pdata *data;
+
+#ifdef CONFIG_CMD_NET
+ /*
+ * If net_busy_flag is 1, NET transfer is running,
+ * then we check key-pressed every second (first check may be
+ * less than 1 second) to improve TFTP booting performance.
+ */
+ if (net_busy_flag && (get_timer(kbd_testc_tms) < CONFIG_SYS_HZ))
+ return 0;
+ kbd_testc_tms = get_timer(0);
+#endif
+ dev = stdio_get_by_name(sdev->name);
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+ data = usb_kbd_dev->privptr;
+
+ usb_kbd_poll_for_event(usb_kbd_dev);
+
+ return !(data->usb_in_pointer == data->usb_out_pointer);
+}
+
+/* gets the character from the queue */
+static int usb_kbd_getc(struct stdio_dev *sdev)
+{
+ struct stdio_dev *dev;
+ struct usb_device *usb_kbd_dev;
+ struct usb_kbd_pdata *data;
+
+ dev = stdio_get_by_name(sdev->name);
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+ data = usb_kbd_dev->privptr;
+
+ while (data->usb_in_pointer == data->usb_out_pointer) {
+ WATCHDOG_RESET();
+ usb_kbd_poll_for_event(usb_kbd_dev);
+ }
+
+ if (data->usb_out_pointer == USB_KBD_BUFFER_LEN - 1)
+ data->usb_out_pointer = 0;
+ else
+ data->usb_out_pointer++;
+
+ return data->usb_kbd_buffer[data->usb_out_pointer];
+}
+
+/* probes the USB device dev for keyboard type. */
+static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
+{
+ struct usb_interface *iface;
+ struct usb_endpoint_descriptor *ep;
+ struct usb_kbd_pdata *data;
+ int epNum;
+
+ if (dev->descriptor.bNumConfigurations != 1)
+ return 0;
+
+ iface = &dev->config.if_desc[ifnum];
+
+ if (iface->desc.bInterfaceClass != USB_CLASS_HID)
+ return 0;
+
+ if (iface->desc.bInterfaceSubClass != USB_SUB_HID_BOOT)
+ return 0;
+
+ if (iface->desc.bInterfaceProtocol != USB_PROT_HID_KEYBOARD)
+ return 0;
+
+ for (epNum = 0; epNum < iface->desc.bNumEndpoints; epNum++) {
+ ep = &iface->ep_desc[epNum];
+
+ /* Check if endpoint is interrupt IN endpoint */
+ if ((ep->bmAttributes & 3) != 3)
+ continue;
+
+ if (ep->bEndpointAddress & 0x80)
+ break;
+ }
+
+ if (epNum == iface->desc.bNumEndpoints)
+ return 0;
+
+ debug("USB KBD: found interrupt EP: 0x%x\n", ep->bEndpointAddress);
+
+ data = malloc(sizeof(struct usb_kbd_pdata));
+ if (!data) {
+ printf("USB KBD: Error allocating private data\n");
+ return 0;
+ }
+
+ /* Clear private data */
+ memset(data, 0, sizeof(struct usb_kbd_pdata));
+
+ /* allocate input buffer aligned and sized to USB DMA alignment */
+ data->new = memalign(USB_DMA_MINALIGN,
+ roundup(USB_KBD_BOOT_REPORT_SIZE, USB_DMA_MINALIGN));
+
+ /* Insert private data into USB device structure */
+ dev->privptr = data;
+
+ /* Set IRQ handler */
+ dev->irq_handle = usb_kbd_irq;
+
+ data->intpipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
+ data->intpktsize = min(usb_maxpacket(dev, data->intpipe),
+ USB_KBD_BOOT_REPORT_SIZE);
+ data->intinterval = ep->bInterval;
+ data->last_report = -1;
+
+ /* We found a USB Keyboard, install it. */
+ debug("USB KBD: set boot protocol\n");
+ usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
+
+#if !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) && \
+ !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)
+ debug("USB KBD: set idle interval...\n");
+ usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE / 4, 0);
+#else
+ debug("USB KBD: set idle interval=0...\n");
+ usb_set_idle(dev, iface->desc.bInterfaceNumber, 0, 0);
+#endif
+
+ debug("USB KBD: enable interrupt pipe...\n");
+#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
+ data->intq = create_int_queue(dev, data->intpipe, 1,
+ USB_KBD_BOOT_REPORT_SIZE, data->new,
+ data->intinterval);
+ if (!data->intq) {
+#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)
+ if (usb_get_report(dev, iface->desc.bInterfaceNumber,
+ 1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE) < 0) {
+#else
+ if (usb_int_msg(dev, data->intpipe, data->new, data->intpktsize,
+ data->intinterval, false) < 0) {
+#endif
+ printf("Failed to get keyboard state from device %04x:%04x\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ /* Abort, we don't want to use that non-functional keyboard. */
+ return 0;
+ }
+
+ /* Success. */
+ return 1;
+}
+
+static int probe_usb_keyboard(struct usb_device *dev)
+{
+ char *stdinname;
+ struct stdio_dev usb_kbd_dev;
+ int error;
+
+ /* Try probing the keyboard */
+ if (usb_kbd_probe_dev(dev, 0) != 1)
+ return -ENOENT;
+
+ /* Register the keyboard */
+ debug("USB KBD: register.\n");
+ memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev));
+ strcpy(usb_kbd_dev.name, DEVNAME);
+ usb_kbd_dev.flags = DEV_FLAGS_INPUT;
+ usb_kbd_dev.getc = usb_kbd_getc;
+ usb_kbd_dev.tstc = usb_kbd_testc;
+ usb_kbd_dev.priv = (void *)dev;
+ error = stdio_register(&usb_kbd_dev);
+ if (error)
+ return error;
+
+ stdinname = env_get("stdin");
+#if CONFIG_IS_ENABLED(CONSOLE_MUX)
+ error = iomux_doenv(stdin, stdinname);
+ if (error)
+ return error;
+#else
+ /* Check if this is the standard input device. */
+ if (strcmp(stdinname, DEVNAME))
+ return 1;
+
+ /* Reassign the console */
+ if (overwrite_console())
+ return 1;
+
+ error = console_assign(stdin, DEVNAME);
+ if (error)
+ return error;
+#endif
+
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+/* Search for keyboard and register it if found. */
+int drv_usb_kbd_init(void)
+{
+ int error, i;
+
+ debug("%s: Probing for keyboard\n", __func__);
+ /* Scan all USB Devices */
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ struct usb_device *dev;
+
+ /* Get USB device. */
+ dev = usb_get_dev_index(i);
+ if (!dev)
+ break;
+
+ if (dev->devnum == -1)
+ continue;
+
+ error = probe_usb_keyboard(dev);
+ if (!error)
+ return 1;
+ if (error && error != -ENOENT)
+ return error;
+ }
+
+ /* No USB Keyboard found */
+ return -1;
+}
+
+/* Deregister the keyboard. */
+int usb_kbd_deregister(int force)
+{
+#if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER)
+ struct stdio_dev *dev;
+ struct usb_device *usb_kbd_dev;
+ struct usb_kbd_pdata *data;
+
+ dev = stdio_get_by_name(DEVNAME);
+ if (dev) {
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+ data = usb_kbd_dev->privptr;
+#if CONFIG_IS_ENABLED(CONSOLE_MUX)
+ if (iomux_replace_device(stdin, DEVNAME, force ? "nulldev" : ""))
+ return 1;
+#endif
+ if (stdio_deregister_dev(dev, force) != 0)
+ return 1;
+#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
+ destroy_int_queue(usb_kbd_dev, data->intq);
+#endif
+ free(data->new);
+ free(data);
+ }
+
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB)
+
+static int usb_kbd_probe(struct udevice *dev)
+{
+ struct usb_device *udev = dev_get_parent_priv(dev);
+
+ return probe_usb_keyboard(udev);
+}
+
+static int usb_kbd_remove(struct udevice *dev)
+{
+ struct usb_device *udev = dev_get_parent_priv(dev);
+ struct usb_kbd_pdata *data;
+ struct stdio_dev *sdev;
+ int ret;
+
+ sdev = stdio_get_by_name(DEVNAME);
+ if (!sdev) {
+ ret = -ENXIO;
+ goto err;
+ }
+ data = udev->privptr;
+#if CONFIG_IS_ENABLED(CONSOLE_MUX)
+ if (iomux_replace_device(stdin, DEVNAME, "nulldev")) {
+ ret = -ENOLINK;
+ goto err;
+ }
+#endif
+ if (stdio_deregister_dev(sdev, true)) {
+ ret = -EPERM;
+ goto err;
+ }
+#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
+ destroy_int_queue(udev, data->intq);
+#endif
+ free(data->new);
+ free(data);
+
+ return 0;
+err:
+ printf("%s: warning, ret=%d", __func__, ret);
+ return ret;
+}
+
+static const struct udevice_id usb_kbd_ids[] = {
+ { .compatible = "usb-keyboard" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_kbd) = {
+ .name = "usb_kbd",
+ .id = UCLASS_KEYBOARD,
+ .of_match = usb_kbd_ids,
+ .probe = usb_kbd_probe,
+ .remove = usb_kbd_remove,
+};
+
+static const struct usb_device_id kbd_id_table[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceSubClass = USB_SUB_HID_BOOT,
+ .bInterfaceProtocol = USB_PROT_HID_KEYBOARD,
+ },
+ { } /* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(usb_kbd, kbd_id_table);
+
+#endif
diff --git a/roms/u-boot/common/usb_storage.c b/roms/u-boot/common/usb_storage.c
new file mode 100644
index 000000000..946c6b2b3
--- /dev/null
+++ b/roms/u-boot/common/usb_storage.c
@@ -0,0 +1,1570 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Most of this source has been derived from the Linux USB
+ * project:
+ * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ * (c) 2000 Yggdrasil Computing, Inc.
+ *
+ *
+ * Adapted for U-Boot:
+ * (C) Copyright 2001 Denis Peter, MPL AG Switzerland
+ * Driver model conversion:
+ * (C) Copyright 2015 Google, Inc
+ *
+ * For BBB support (C) Copyright 2003
+ * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
+ *
+ * BBB support based on /sys/dev/usb/umass.c from
+ * FreeBSD.
+ */
+
+/* Note:
+ * Currently only the CBI transport protocoll has been implemented, and it
+ * is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB
+ * transport protocoll may work as well.
+ */
+/*
+ * New Note:
+ * Support for USB Mass Storage Devices (BBB) has been added. It has
+ * only been tested with USB memory sticks.
+ */
+
+
+#include <common.h>
+#include <blk.h>
+#include <command.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <mapmem.h>
+#include <memalign.h>
+#include <asm/byteorder.h>
+#include <asm/cache.h>
+#include <asm/processor.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <linux/delay.h>
+
+#include <part.h>
+#include <usb.h>
+
+#undef BBB_COMDAT_TRACE
+#undef BBB_XPORT_TRACE
+
+#include <scsi.h>
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code -- a 1 indicates input
+ */
+static const unsigned char us_direction[256/8] = {
+ 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+ 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
+
+static struct scsi_cmd usb_ccb __aligned(ARCH_DMA_MINALIGN);
+static __u32 CBWTag;
+
+static int usb_max_devs; /* number of highest available usb device */
+
+#if !CONFIG_IS_ENABLED(BLK)
+static struct blk_desc usb_dev_desc[USB_MAX_STOR_DEV];
+#endif
+
+struct us_data;
+typedef int (*trans_cmnd)(struct scsi_cmd *cb, struct us_data *data);
+typedef int (*trans_reset)(struct us_data *data);
+
+struct us_data {
+ struct usb_device *pusb_dev; /* this usb_device */
+
+ unsigned int flags; /* from filter initially */
+# define USB_READY (1 << 0)
+ unsigned char ifnum; /* interface number */
+ unsigned char ep_in; /* in endpoint */
+ unsigned char ep_out; /* out ....... */
+ unsigned char ep_int; /* interrupt . */
+ unsigned char subclass; /* as in overview */
+ unsigned char protocol; /* .............. */
+ unsigned char attention_done; /* force attn on first cmd */
+ unsigned short ip_data; /* interrupt data */
+ int action; /* what to do */
+ int ip_wanted; /* needed */
+ int *irq_handle; /* for USB int requests */
+ unsigned int irqpipe; /* pipe for release_irq */
+ unsigned char irqmaxp; /* max packed for irq Pipe */
+ unsigned char irqinterval; /* Intervall for IRQ Pipe */
+ struct scsi_cmd *srb; /* current srb */
+ trans_reset transport_reset; /* reset routine */
+ trans_cmnd transport; /* transport routine */
+ unsigned short max_xfer_blk; /* maximum transfer blocks */
+};
+
+#if !CONFIG_IS_ENABLED(BLK)
+static struct us_data usb_stor[USB_MAX_STOR_DEV];
+#endif
+
+#define USB_STOR_TRANSPORT_GOOD 0
+#define USB_STOR_TRANSPORT_FAILED -1
+#define USB_STOR_TRANSPORT_ERROR -2
+
+int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
+ struct blk_desc *dev_desc);
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
+ struct us_data *ss);
+#if CONFIG_IS_ENABLED(BLK)
+static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
+ lbaint_t blkcnt, void *buffer);
+static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
+ lbaint_t blkcnt, const void *buffer);
+#else
+static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
+ lbaint_t blkcnt, void *buffer);
+static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
+ lbaint_t blkcnt, const void *buffer);
+#endif
+void uhci_show_temp_int_td(void);
+
+static void usb_show_progress(void)
+{
+ debug(".");
+}
+
+/*******************************************************************************
+ * show info on storage devices; 'usb start/init' must be invoked earlier
+ * as we only retrieve structures populated during devices initialization
+ */
+int usb_stor_info(void)
+{
+ int count = 0;
+#if CONFIG_IS_ENABLED(BLK)
+ struct udevice *dev;
+
+ for (blk_first_device(IF_TYPE_USB, &dev);
+ dev;
+ blk_next_device(&dev)) {
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
+
+ printf(" Device %d: ", desc->devnum);
+ dev_print(desc);
+ count++;
+ }
+#else
+ int i;
+
+ if (usb_max_devs > 0) {
+ for (i = 0; i < usb_max_devs; i++) {
+ printf(" Device %d: ", i);
+ dev_print(&usb_dev_desc[i]);
+ }
+ return 0;
+ }
+#endif
+ if (!count) {
+ printf("No storage devices, perhaps not 'usb start'ed..?\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static unsigned int usb_get_max_lun(struct us_data *us)
+{
+ int len;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, result, 1);
+ len = usb_control_msg(us->pusb_dev,
+ usb_rcvctrlpipe(us->pusb_dev, 0),
+ US_BBB_GET_MAX_LUN,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ 0, us->ifnum,
+ result, sizeof(char),
+ USB_CNTL_TIMEOUT * 5);
+ debug("Get Max LUN -> len = %i, result = %i\n", len, (int) *result);
+ return (len > 0) ? *result : 0;
+}
+
+static int usb_stor_probe_device(struct usb_device *udev)
+{
+ int lun, max_lun;
+
+#if CONFIG_IS_ENABLED(BLK)
+ struct us_data *data;
+ int ret;
+#else
+ int start;
+
+ if (udev == NULL)
+ return -ENOENT; /* no more devices available */
+#endif
+
+ debug("\n\nProbing for storage\n");
+#if CONFIG_IS_ENABLED(BLK)
+ /*
+ * We store the us_data in the mass storage device's plat. It
+ * is shared by all LUNs (block devices) attached to this mass storage
+ * device.
+ */
+ data = dev_get_plat(udev->dev);
+ if (!usb_storage_probe(udev, 0, data))
+ return 0;
+ max_lun = usb_get_max_lun(data);
+ for (lun = 0; lun <= max_lun; lun++) {
+ struct blk_desc *blkdev;
+ struct udevice *dev;
+ char str[10];
+
+ snprintf(str, sizeof(str), "lun%d", lun);
+ ret = blk_create_devicef(udev->dev, "usb_storage_blk", str,
+ IF_TYPE_USB, usb_max_devs, 512, 0,
+ &dev);
+ if (ret) {
+ debug("Cannot bind driver\n");
+ return ret;
+ }
+
+ blkdev = dev_get_uclass_plat(dev);
+ blkdev->target = 0xff;
+ blkdev->lun = lun;
+
+ ret = usb_stor_get_info(udev, data, blkdev);
+ if (ret == 1) {
+ usb_max_devs++;
+ debug("%s: Found device %p\n", __func__, udev);
+ } else {
+ debug("usb_stor_get_info: Invalid device\n");
+ ret = device_unbind(dev);
+ if (ret)
+ return ret;
+ }
+ }
+#else
+ /* We don't have space to even probe if we hit the maximum */
+ if (usb_max_devs == USB_MAX_STOR_DEV) {
+ printf("max USB Storage Device reached: %d stopping\n",
+ usb_max_devs);
+ return -ENOSPC;
+ }
+
+ if (!usb_storage_probe(udev, 0, &usb_stor[usb_max_devs]))
+ return 0;
+
+ /*
+ * OK, it's a storage device. Iterate over its LUNs and populate
+ * usb_dev_desc'
+ */
+ start = usb_max_devs;
+
+ max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
+ for (lun = 0; lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
+ lun++) {
+ struct blk_desc *blkdev;
+
+ blkdev = &usb_dev_desc[usb_max_devs];
+ memset(blkdev, '\0', sizeof(struct blk_desc));
+ blkdev->if_type = IF_TYPE_USB;
+ blkdev->devnum = usb_max_devs;
+ blkdev->part_type = PART_TYPE_UNKNOWN;
+ blkdev->target = 0xff;
+ blkdev->type = DEV_TYPE_UNKNOWN;
+ blkdev->block_read = usb_stor_read;
+ blkdev->block_write = usb_stor_write;
+ blkdev->lun = lun;
+ blkdev->priv = udev;
+
+ if (usb_stor_get_info(udev, &usb_stor[start],
+ &usb_dev_desc[usb_max_devs]) == 1) {
+ debug("partype: %d\n", blkdev->part_type);
+ part_init(blkdev);
+ debug("partype: %d\n", blkdev->part_type);
+ usb_max_devs++;
+ debug("%s: Found device %p\n", __func__, udev);
+ }
+ }
+#endif
+
+ return 0;
+}
+
+void usb_stor_reset(void)
+{
+ usb_max_devs = 0;
+}
+
+/*******************************************************************************
+ * scan the usb and reports device info
+ * to the user if mode = 1
+ * returns current device or -1 if no
+ */
+int usb_stor_scan(int mode)
+{
+ if (mode == 1)
+ printf(" scanning usb for storage devices... ");
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+ unsigned char i;
+
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+
+ usb_stor_reset();
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ struct usb_device *dev;
+
+ dev = usb_get_dev_index(i); /* get device */
+ debug("i=%d\n", i);
+ if (usb_stor_probe_device(dev))
+ break;
+ } /* for */
+
+ usb_disable_asynch(0); /* asynch transfer allowed */
+#endif
+ printf("%d Storage Device(s) found\n", usb_max_devs);
+ if (usb_max_devs > 0)
+ return 0;
+ return -1;
+}
+
+static int usb_stor_irq(struct usb_device *dev)
+{
+ struct us_data *us;
+ us = (struct us_data *)dev->privptr;
+
+ if (us->ip_wanted)
+ us->ip_wanted = 0;
+ return 0;
+}
+
+
+#ifdef DEBUG
+
+static void usb_show_srb(struct scsi_cmd *pccb)
+{
+ int i;
+ printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen);
+ for (i = 0; i < 12; i++)
+ printf("%02X ", pccb->cmd[i]);
+ printf("\n");
+}
+
+static void display_int_status(unsigned long tmp)
+{
+ printf("Status: %s %s %s %s %s %s %s\n",
+ (tmp & USB_ST_ACTIVE) ? "Active" : "",
+ (tmp & USB_ST_STALLED) ? "Stalled" : "",
+ (tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
+ (tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
+ (tmp & USB_ST_NAK_REC) ? "NAKed" : "",
+ (tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
+ (tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
+}
+#endif
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
+{
+ int max_size;
+ int this_xfer;
+ int result;
+ int partial;
+ int maxtry;
+ int stat;
+
+ /* determine the maximum packet size for these transfers */
+ max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
+
+ /* while we have data left to transfer */
+ while (length) {
+
+ /* calculate how long this will be -- maximum or a remainder */
+ this_xfer = length > max_size ? max_size : length;
+ length -= this_xfer;
+
+ /* setup the retry counter */
+ maxtry = 10;
+
+ /* set up the transfer loop */
+ do {
+ /* transfer the data */
+ debug("Bulk xfer 0x%lx(%d) try #%d\n",
+ (ulong)map_to_sysmem(buf), this_xfer,
+ 11 - maxtry);
+ result = usb_bulk_msg(us->pusb_dev, pipe, buf,
+ this_xfer, &partial,
+ USB_CNTL_TIMEOUT * 5);
+ debug("bulk_msg returned %d xferred %d/%d\n",
+ result, partial, this_xfer);
+ if (us->pusb_dev->status != 0) {
+ /* if we stall, we need to clear it before
+ * we go on
+ */
+#ifdef DEBUG
+ display_int_status(us->pusb_dev->status);
+#endif
+ if (us->pusb_dev->status & USB_ST_STALLED) {
+ debug("stalled ->clearing endpoint" \
+ "halt for pipe 0x%x\n", pipe);
+ stat = us->pusb_dev->status;
+ usb_clear_halt(us->pusb_dev, pipe);
+ us->pusb_dev->status = stat;
+ if (this_xfer == partial) {
+ debug("bulk transferred" \
+ "with error %lX," \
+ " but data ok\n",
+ us->pusb_dev->status);
+ return 0;
+ }
+ else
+ return result;
+ }
+ if (us->pusb_dev->status & USB_ST_NAK_REC) {
+ debug("Device NAKed bulk_msg\n");
+ return result;
+ }
+ debug("bulk transferred with error");
+ if (this_xfer == partial) {
+ debug(" %ld, but data ok\n",
+ us->pusb_dev->status);
+ return 0;
+ }
+ /* if our try counter reaches 0, bail out */
+ debug(" %ld, data %d\n",
+ us->pusb_dev->status, partial);
+ if (!maxtry--)
+ return result;
+ }
+ /* update to show what data was transferred */
+ this_xfer -= partial;
+ buf += partial;
+ /* continue until this transfer is done */
+ } while (this_xfer);
+ }
+
+ /* if we get here, we're done and successful */
+ return 0;
+}
+
+static int usb_stor_BBB_reset(struct us_data *us)
+{
+ int result;
+ unsigned int pipe;
+
+ /*
+ * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
+ *
+ * For Reset Recovery the host shall issue in the following order:
+ * a) a Bulk-Only Mass Storage Reset
+ * b) a Clear Feature HALT to the Bulk-In endpoint
+ * c) a Clear Feature HALT to the Bulk-Out endpoint
+ *
+ * This is done in 3 steps.
+ *
+ * If the reset doesn't succeed, the device should be port reset.
+ *
+ * This comment stolen from FreeBSD's /sys/dev/usb/umass.c.
+ */
+ debug("BBB_reset\n");
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ US_BBB_RESET,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, NULL, 0, USB_CNTL_TIMEOUT * 5);
+
+ if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
+ debug("RESET:stall\n");
+ return -1;
+ }
+
+ /* long wait for reset */
+ mdelay(150);
+ debug("BBB_reset result %d: status %lX reset\n",
+ result, us->pusb_dev->status);
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ result = usb_clear_halt(us->pusb_dev, pipe);
+ /* long wait for reset */
+ mdelay(150);
+ debug("BBB_reset result %d: status %lX clearing IN endpoint\n",
+ result, us->pusb_dev->status);
+ /* long wait for reset */
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+ result = usb_clear_halt(us->pusb_dev, pipe);
+ mdelay(150);
+ debug("BBB_reset result %d: status %lX clearing OUT endpoint\n",
+ result, us->pusb_dev->status);
+ debug("BBB_reset done\n");
+ return 0;
+}
+
+/* FIXME: this reset function doesn't really reset the port, and it
+ * should. Actually it should probably do what it's doing here, and
+ * reset the port physically
+ */
+static int usb_stor_CB_reset(struct us_data *us)
+{
+ unsigned char cmd[12];
+ int result;
+
+ debug("CB_reset\n");
+ memset(cmd, 0xff, sizeof(cmd));
+ cmd[0] = SCSI_SEND_DIAG;
+ cmd[1] = 4;
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, cmd, sizeof(cmd),
+ USB_CNTL_TIMEOUT * 5);
+
+ /* long wait for reset */
+ mdelay(1500);
+ debug("CB_reset result %d: status %lX clearing endpoint halt\n",
+ result, us->pusb_dev->status);
+ usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+
+ debug("CB_reset done\n");
+ return 0;
+}
+
+/*
+ * Set up the command for a BBB device. Note that the actual SCSI
+ * command is copied into cbw.CBWCDB.
+ */
+static int usb_stor_BBB_comdat(struct scsi_cmd *srb, struct us_data *us)
+{
+ int result;
+ int actlen;
+ int dir_in;
+ unsigned int pipe;
+ ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_cbw, cbw, 1);
+
+ dir_in = US_DIRECTION(srb->cmd[0]);
+
+#ifdef BBB_COMDAT_TRACE
+ printf("dir %d lun %d cmdlen %d cmd %p datalen %lu pdata %p\n",
+ dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen,
+ srb->pdata);
+ if (srb->cmdlen) {
+ for (result = 0; result < srb->cmdlen; result++)
+ printf("cmd[%d] %#x ", result, srb->cmd[result]);
+ printf("\n");
+ }
+#endif
+ /* sanity checks */
+ if (!(srb->cmdlen <= CBWCDBLENGTH)) {
+ debug("usb_stor_BBB_comdat:cmdlen too large\n");
+ return -1;
+ }
+
+ /* always OUT to the ep */
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ cbw->dCBWSignature = cpu_to_le32(CBWSIGNATURE);
+ cbw->dCBWTag = cpu_to_le32(CBWTag++);
+ cbw->dCBWDataTransferLength = cpu_to_le32(srb->datalen);
+ cbw->bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT);
+ cbw->bCBWLUN = srb->lun;
+ cbw->bCDBLength = srb->cmdlen;
+ /* copy the command data into the CBW command data buffer */
+ /* DST SRC LEN!!! */
+
+ memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen);
+ result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE,
+ &actlen, USB_CNTL_TIMEOUT * 5);
+ if (result < 0)
+ debug("usb_stor_BBB_comdat:usb_bulk_msg error\n");
+ return result;
+}
+
+/* FIXME: we also need a CBI_command which sets up the completion
+ * interrupt, and waits for it
+ */
+static int usb_stor_CB_comdat(struct scsi_cmd *srb, struct us_data *us)
+{
+ int result = 0;
+ int dir_in, retry;
+ unsigned int pipe;
+ unsigned long status;
+
+ retry = 5;
+ dir_in = US_DIRECTION(srb->cmd[0]);
+
+ if (dir_in)
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ while (retry--) {
+ debug("CBI gets a command: Try %d\n", 5 - retry);
+#ifdef DEBUG
+ usb_show_srb(srb);
+#endif
+ /* let's send the command via the control pipe */
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev , 0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum,
+ srb->cmd, srb->cmdlen,
+ USB_CNTL_TIMEOUT * 5);
+ debug("CB_transport: control msg returned %d, status %lX\n",
+ result, us->pusb_dev->status);
+ /* check the return code for the command */
+ if (result < 0) {
+ if (us->pusb_dev->status & USB_ST_STALLED) {
+ status = us->pusb_dev->status;
+ debug(" stall during command found," \
+ " clear pipe\n");
+ usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev, 0));
+ us->pusb_dev->status = status;
+ }
+ debug(" error during command %02X" \
+ " Stat = %lX\n", srb->cmd[0],
+ us->pusb_dev->status);
+ return result;
+ }
+ /* transfer the data payload for this command, if one exists*/
+
+ debug("CB_transport: control msg returned %d," \
+ " direction is %s to go 0x%lx\n", result,
+ dir_in ? "IN" : "OUT", srb->datalen);
+ if (srb->datalen) {
+ result = us_one_transfer(us, pipe, (char *)srb->pdata,
+ srb->datalen);
+ debug("CBI attempted to transfer data," \
+ " result is %d status %lX, len %d\n",
+ result, us->pusb_dev->status,
+ us->pusb_dev->act_len);
+ if (!(us->pusb_dev->status & USB_ST_NAK_REC))
+ break;
+ } /* if (srb->datalen) */
+ else
+ break;
+ }
+ /* return result */
+
+ return result;
+}
+
+
+static int usb_stor_CBI_get_status(struct scsi_cmd *srb, struct us_data *us)
+{
+ int timeout;
+
+ us->ip_wanted = 1;
+ usb_int_msg(us->pusb_dev, us->irqpipe,
+ (void *)&us->ip_data, us->irqmaxp, us->irqinterval, false);
+ timeout = 1000;
+ while (timeout--) {
+ if (us->ip_wanted == 0)
+ break;
+ mdelay(10);
+ }
+ if (us->ip_wanted) {
+ printf(" Did not get interrupt on CBI\n");
+ us->ip_wanted = 0;
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ debug("Got interrupt data 0x%x, transferred %d status 0x%lX\n",
+ us->ip_data, us->pusb_dev->irq_act_len,
+ us->pusb_dev->irq_status);
+ /* UFI gives us ASC and ASCQ, like a request sense */
+ if (us->subclass == US_SC_UFI) {
+ if (srb->cmd[0] == SCSI_REQ_SENSE ||
+ srb->cmd[0] == SCSI_INQUIRY)
+ return USB_STOR_TRANSPORT_GOOD; /* Good */
+ else if (us->ip_data)
+ return USB_STOR_TRANSPORT_FAILED;
+ else
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+ /* otherwise, we interpret the data normally */
+ switch (us->ip_data) {
+ case 0x0001:
+ return USB_STOR_TRANSPORT_GOOD;
+ case 0x0002:
+ return USB_STOR_TRANSPORT_FAILED;
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
+ } /* switch */
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+#define USB_TRANSPORT_UNKNOWN_RETRY 5
+#define USB_TRANSPORT_NOT_READY_RETRY 10
+
+/* clear a stall on an endpoint - special for BBB devices */
+static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt)
+{
+ /* ENDPOINT_HALT = 0, so set value to 0 */
+ return usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
+ endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
+}
+
+static int usb_stor_BBB_transport(struct scsi_cmd *srb, struct us_data *us)
+{
+ int result, retry;
+ int dir_in;
+ int actlen, data_actlen;
+ unsigned int pipe, pipein, pipeout;
+ ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_csw, csw, 1);
+#ifdef BBB_XPORT_TRACE
+ unsigned char *ptr;
+ int index;
+#endif
+
+ dir_in = US_DIRECTION(srb->cmd[0]);
+
+ /* COMMAND phase */
+ debug("COMMAND phase\n");
+ result = usb_stor_BBB_comdat(srb, us);
+ if (result < 0) {
+ debug("failed to send CBW status %ld\n",
+ us->pusb_dev->status);
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+ if (!(us->flags & USB_READY))
+ mdelay(5);
+ pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+ /* DATA phase + error handling */
+ data_actlen = 0;
+ /* no data, go immediately to the STATUS phase */
+ if (srb->datalen == 0)
+ goto st;
+ debug("DATA phase\n");
+ if (dir_in)
+ pipe = pipein;
+ else
+ pipe = pipeout;
+
+ result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
+ &data_actlen, USB_CNTL_TIMEOUT * 5);
+ /* special handling of STALL in DATA phase */
+ if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
+ debug("DATA:stall\n");
+ /* clear the STALL on the endpoint */
+ result = usb_stor_BBB_clear_endpt_stall(us,
+ dir_in ? us->ep_in : us->ep_out);
+ if (result >= 0)
+ /* continue on to STATUS phase */
+ goto st;
+ }
+ if (result < 0) {
+ debug("usb_bulk_msg error status %ld\n",
+ us->pusb_dev->status);
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+#ifdef BBB_XPORT_TRACE
+ for (index = 0; index < data_actlen; index++)
+ printf("pdata[%d] %#x ", index, srb->pdata[index]);
+ printf("\n");
+#endif
+ /* STATUS phase + error handling */
+st:
+ retry = 0;
+again:
+ debug("STATUS phase\n");
+ result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE,
+ &actlen, USB_CNTL_TIMEOUT*5);
+
+ /* special handling of STALL in STATUS phase */
+ if ((result < 0) && (retry < 1) &&
+ (us->pusb_dev->status & USB_ST_STALLED)) {
+ debug("STATUS:stall\n");
+ /* clear the STALL on the endpoint */
+ result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
+ if (result >= 0 && (retry++ < 1))
+ /* do a retry */
+ goto again;
+ }
+ if (result < 0) {
+ debug("usb_bulk_msg error status %ld\n",
+ us->pusb_dev->status);
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+#ifdef BBB_XPORT_TRACE
+ ptr = (unsigned char *)csw;
+ for (index = 0; index < UMASS_BBB_CSW_SIZE; index++)
+ printf("ptr[%d] %#x ", index, ptr[index]);
+ printf("\n");
+#endif
+ /* misuse pipe to get the residue */
+ pipe = le32_to_cpu(csw->dCSWDataResidue);
+ if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0)
+ pipe = srb->datalen - data_actlen;
+ if (CSWSIGNATURE != le32_to_cpu(csw->dCSWSignature)) {
+ debug("!CSWSIGNATURE\n");
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if ((CBWTag - 1) != le32_to_cpu(csw->dCSWTag)) {
+ debug("!Tag\n");
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if (csw->bCSWStatus > CSWSTATUS_PHASE) {
+ debug(">PHASE\n");
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if (csw->bCSWStatus == CSWSTATUS_PHASE) {
+ debug("=PHASE\n");
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if (data_actlen > srb->datalen) {
+ debug("transferred %dB instead of %ldB\n",
+ data_actlen, srb->datalen);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if (csw->bCSWStatus == CSWSTATUS_FAILED) {
+ debug("FAILED\n");
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ return result;
+}
+
+static int usb_stor_CB_transport(struct scsi_cmd *srb, struct us_data *us)
+{
+ int result, status;
+ struct scsi_cmd *psrb;
+ struct scsi_cmd reqsrb;
+ int retry, notready;
+
+ psrb = &reqsrb;
+ status = USB_STOR_TRANSPORT_GOOD;
+ retry = 0;
+ notready = 0;
+ /* issue the command */
+do_retry:
+ result = usb_stor_CB_comdat(srb, us);
+ debug("command / Data returned %d, status %lX\n",
+ result, us->pusb_dev->status);
+ /* if this is an CBI Protocol, get IRQ */
+ if (us->protocol == US_PR_CBI) {
+ status = usb_stor_CBI_get_status(srb, us);
+ /* if the status is error, report it */
+ if (status == USB_STOR_TRANSPORT_ERROR) {
+ debug(" USB CBI Command Error\n");
+ return status;
+ }
+ srb->sense_buf[12] = (unsigned char)(us->ip_data >> 8);
+ srb->sense_buf[13] = (unsigned char)(us->ip_data & 0xff);
+ if (!us->ip_data) {
+ /* if the status is good, report it */
+ if (status == USB_STOR_TRANSPORT_GOOD) {
+ debug(" USB CBI Command Good\n");
+ return status;
+ }
+ }
+ }
+ /* do we have to issue an auto request? */
+ /* HERE we have to check the result */
+ if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
+ debug("ERROR %lX\n", us->pusb_dev->status);
+ us->transport_reset(us);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ if ((us->protocol == US_PR_CBI) &&
+ ((srb->cmd[0] == SCSI_REQ_SENSE) ||
+ (srb->cmd[0] == SCSI_INQUIRY))) {
+ /* do not issue an autorequest after request sense */
+ debug("No auto request and good\n");
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+ /* issue an request_sense */
+ memset(&psrb->cmd[0], 0, 12);
+ psrb->cmd[0] = SCSI_REQ_SENSE;
+ psrb->cmd[1] = srb->lun << 5;
+ psrb->cmd[4] = 18;
+ psrb->datalen = 18;
+ psrb->pdata = &srb->sense_buf[0];
+ psrb->cmdlen = 12;
+ /* issue the command */
+ result = usb_stor_CB_comdat(psrb, us);
+ debug("auto request returned %d\n", result);
+ /* if this is an CBI Protocol, get IRQ */
+ if (us->protocol == US_PR_CBI)
+ status = usb_stor_CBI_get_status(psrb, us);
+
+ if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
+ debug(" AUTO REQUEST ERROR %ld\n",
+ us->pusb_dev->status);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ debug("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
+ srb->sense_buf[0], srb->sense_buf[2],
+ srb->sense_buf[12], srb->sense_buf[13]);
+ /* Check the auto request result */
+ if ((srb->sense_buf[2] == 0) &&
+ (srb->sense_buf[12] == 0) &&
+ (srb->sense_buf[13] == 0)) {
+ /* ok, no sense */
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ /* Check the auto request result */
+ switch (srb->sense_buf[2]) {
+ case 0x01:
+ /* Recovered Error */
+ return USB_STOR_TRANSPORT_GOOD;
+ break;
+ case 0x02:
+ /* Not Ready */
+ if (notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
+ printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
+ " 0x%02X (NOT READY)\n", srb->cmd[0],
+ srb->sense_buf[0], srb->sense_buf[2],
+ srb->sense_buf[12], srb->sense_buf[13]);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else {
+ mdelay(100);
+ goto do_retry;
+ }
+ break;
+ default:
+ if (retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
+ printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
+ " 0x%02X\n", srb->cmd[0], srb->sense_buf[0],
+ srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else
+ goto do_retry;
+ break;
+ }
+ return USB_STOR_TRANSPORT_FAILED;
+}
+
+static void usb_stor_set_max_xfer_blk(struct usb_device *udev,
+ struct us_data *us)
+{
+ /*
+ * Limit the total size of a transfer to 120 KB.
+ *
+ * Some devices are known to choke with anything larger. It seems like
+ * the problem stems from the fact that original IDE controllers had
+ * only an 8-bit register to hold the number of sectors in one transfer
+ * and even those couldn't handle a full 256 sectors.
+ *
+ * Because we want to make sure we interoperate with as many devices as
+ * possible, we will maintain a 240 sector transfer size limit for USB
+ * Mass Storage devices.
+ *
+ * Tests show that other operating have similar limits with Microsoft
+ * Windows 7 limiting transfers to 128 sectors for both USB2 and USB3
+ * and Apple Mac OS X 10.11 limiting transfers to 256 sectors for USB2
+ * and 2048 for USB3 devices.
+ */
+ unsigned short blk = 240;
+
+#if CONFIG_IS_ENABLED(DM_USB)
+ size_t size;
+ int ret;
+
+ ret = usb_get_max_xfer_size(udev, (size_t *)&size);
+ if ((ret >= 0) && (size < blk * 512))
+ blk = size / 512;
+#endif
+
+ us->max_xfer_blk = blk;
+}
+
+static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss)
+{
+ int retry, i;
+ retry = 5;
+ do {
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_INQUIRY;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[4] = 36;
+ srb->datalen = 36;
+ srb->cmdlen = 12;
+ i = ss->transport(srb, ss);
+ debug("inquiry returns %d\n", i);
+ if (i == 0)
+ break;
+ } while (--retry);
+
+ if (!retry) {
+ printf("error in inquiry\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss)
+{
+ char *ptr;
+
+ ptr = (char *)srb->pdata;
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_REQ_SENSE;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[4] = 18;
+ srb->datalen = 18;
+ srb->pdata = &srb->sense_buf[0];
+ srb->cmdlen = 12;
+ ss->transport(srb, ss);
+ debug("Request Sense returned %02X %02X %02X\n",
+ srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
+ srb->pdata = (uchar *)ptr;
+ return 0;
+}
+
+static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss)
+{
+ int retries = 10;
+
+ do {
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_TST_U_RDY;
+ srb->cmd[1] = srb->lun << 5;
+ srb->datalen = 0;
+ srb->cmdlen = 12;
+ if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) {
+ ss->flags |= USB_READY;
+ return 0;
+ }
+ usb_request_sense(srb, ss);
+ /*
+ * Check the Key Code Qualifier, if it matches
+ * "Not Ready - medium not present"
+ * (the sense Key equals 0x2 and the ASC is 0x3a)
+ * return immediately as the medium being absent won't change
+ * unless there is a user action.
+ */
+ if ((srb->sense_buf[2] == 0x02) &&
+ (srb->sense_buf[12] == 0x3a))
+ return -1;
+ mdelay(100);
+ } while (retries--);
+
+ return -1;
+}
+
+static int usb_read_capacity(struct scsi_cmd *srb, struct us_data *ss)
+{
+ int retry;
+ /* XXX retries */
+ retry = 3;
+ do {
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_RD_CAPAC;
+ srb->cmd[1] = srb->lun << 5;
+ srb->datalen = 8;
+ srb->cmdlen = 12;
+ if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
+ return 0;
+ } while (retry--);
+
+ return -1;
+}
+
+static int usb_read_10(struct scsi_cmd *srb, struct us_data *ss,
+ unsigned long start, unsigned short blocks)
+{
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_READ10;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
+ srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
+ srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
+ srb->cmd[5] = ((unsigned char) (start)) & 0xff;
+ srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
+ srb->cmd[8] = (unsigned char) blocks & 0xff;
+ srb->cmdlen = 12;
+ debug("read10: start %lx blocks %x\n", start, blocks);
+ return ss->transport(srb, ss);
+}
+
+static int usb_write_10(struct scsi_cmd *srb, struct us_data *ss,
+ unsigned long start, unsigned short blocks)
+{
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_WRITE10;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
+ srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
+ srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
+ srb->cmd[5] = ((unsigned char) (start)) & 0xff;
+ srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
+ srb->cmd[8] = (unsigned char) blocks & 0xff;
+ srb->cmdlen = 12;
+ debug("write10: start %lx blocks %x\n", start, blocks);
+ return ss->transport(srb, ss);
+}
+
+
+#ifdef CONFIG_USB_BIN_FIXUP
+/*
+ * Some USB storage devices queried for SCSI identification data respond with
+ * binary strings, which if output to the console freeze the terminal. The
+ * workaround is to modify the vendor and product strings read from such
+ * device with proper values (as reported by 'usb info').
+ *
+ * Vendor and product length limits are taken from the definition of
+ * struct blk_desc in include/part.h.
+ */
+static void usb_bin_fixup(struct usb_device_descriptor descriptor,
+ unsigned char vendor[],
+ unsigned char product[]) {
+ const unsigned char max_vendor_len = 40;
+ const unsigned char max_product_len = 20;
+ if (descriptor.idVendor == 0x0424 && descriptor.idProduct == 0x223a) {
+ strncpy((char *)vendor, "SMSC", max_vendor_len);
+ strncpy((char *)product, "Flash Media Cntrller",
+ max_product_len);
+ }
+}
+#endif /* CONFIG_USB_BIN_FIXUP */
+
+#if CONFIG_IS_ENABLED(BLK)
+static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
+ lbaint_t blkcnt, void *buffer)
+#else
+static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
+ lbaint_t blkcnt, void *buffer)
+#endif
+{
+ lbaint_t start, blks;
+ uintptr_t buf_addr;
+ unsigned short smallblks;
+ struct usb_device *udev;
+ struct us_data *ss;
+ int retry;
+ struct scsi_cmd *srb = &usb_ccb;
+#if CONFIG_IS_ENABLED(BLK)
+ struct blk_desc *block_dev;
+#endif
+
+ if (blkcnt == 0)
+ return 0;
+ /* Setup device */
+#if CONFIG_IS_ENABLED(BLK)
+ block_dev = dev_get_uclass_plat(dev);
+ udev = dev_get_parent_priv(dev_get_parent(dev));
+ debug("\nusb_read: udev %d\n", block_dev->devnum);
+#else
+ debug("\nusb_read: udev %d\n", block_dev->devnum);
+ udev = usb_dev_desc[block_dev->devnum].priv;
+ if (!udev) {
+ debug("%s: No device\n", __func__);
+ return 0;
+ }
+#endif
+ ss = (struct us_data *)udev->privptr;
+
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+ usb_lock_async(udev, 1);
+ srb->lun = block_dev->lun;
+ buf_addr = (uintptr_t)buffer;
+ start = blknr;
+ blks = blkcnt;
+
+ debug("\nusb_read: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
+ block_dev->devnum, start, blks, buf_addr);
+
+ do {
+ /* XXX need some comment here */
+ retry = 2;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (blks > ss->max_xfer_blk)
+ smallblks = ss->max_xfer_blk;
+ else
+ smallblks = (unsigned short) blks;
+retry_it:
+ if (smallblks == ss->max_xfer_blk)
+ usb_show_progress();
+ srb->datalen = block_dev->blksz * smallblks;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (usb_read_10(srb, ss, start, smallblks)) {
+ debug("Read ERROR\n");
+ ss->flags &= ~USB_READY;
+ usb_request_sense(srb, ss);
+ if (retry--)
+ goto retry_it;
+ blkcnt -= blks;
+ break;
+ }
+ start += smallblks;
+ blks -= smallblks;
+ buf_addr += srb->datalen;
+ } while (blks != 0);
+
+ debug("usb_read: end startblk " LBAF ", blccnt %x buffer %lx\n",
+ start, smallblks, buf_addr);
+
+ usb_lock_async(udev, 0);
+ usb_disable_asynch(0); /* asynch transfer allowed */
+ if (blkcnt >= ss->max_xfer_blk)
+ debug("\n");
+ return blkcnt;
+}
+
+#if CONFIG_IS_ENABLED(BLK)
+static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
+ lbaint_t blkcnt, const void *buffer)
+#else
+static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
+ lbaint_t blkcnt, const void *buffer)
+#endif
+{
+ lbaint_t start, blks;
+ uintptr_t buf_addr;
+ unsigned short smallblks;
+ struct usb_device *udev;
+ struct us_data *ss;
+ int retry;
+ struct scsi_cmd *srb = &usb_ccb;
+#if CONFIG_IS_ENABLED(BLK)
+ struct blk_desc *block_dev;
+#endif
+
+ if (blkcnt == 0)
+ return 0;
+
+ /* Setup device */
+#if CONFIG_IS_ENABLED(BLK)
+ block_dev = dev_get_uclass_plat(dev);
+ udev = dev_get_parent_priv(dev_get_parent(dev));
+ debug("\nusb_read: udev %d\n", block_dev->devnum);
+#else
+ debug("\nusb_read: udev %d\n", block_dev->devnum);
+ udev = usb_dev_desc[block_dev->devnum].priv;
+ if (!udev) {
+ debug("%s: No device\n", __func__);
+ return 0;
+ }
+#endif
+ ss = (struct us_data *)udev->privptr;
+
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+ usb_lock_async(udev, 1);
+
+ srb->lun = block_dev->lun;
+ buf_addr = (uintptr_t)buffer;
+ start = blknr;
+ blks = blkcnt;
+
+ debug("\nusb_write: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
+ block_dev->devnum, start, blks, buf_addr);
+
+ do {
+ /* If write fails retry for max retry count else
+ * return with number of blocks written successfully.
+ */
+ retry = 2;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (blks > ss->max_xfer_blk)
+ smallblks = ss->max_xfer_blk;
+ else
+ smallblks = (unsigned short) blks;
+retry_it:
+ if (smallblks == ss->max_xfer_blk)
+ usb_show_progress();
+ srb->datalen = block_dev->blksz * smallblks;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (usb_write_10(srb, ss, start, smallblks)) {
+ debug("Write ERROR\n");
+ ss->flags &= ~USB_READY;
+ usb_request_sense(srb, ss);
+ if (retry--)
+ goto retry_it;
+ blkcnt -= blks;
+ break;
+ }
+ start += smallblks;
+ blks -= smallblks;
+ buf_addr += srb->datalen;
+ } while (blks != 0);
+
+ debug("usb_write: end startblk " LBAF ", blccnt %x buffer %lx\n",
+ start, smallblks, buf_addr);
+
+ usb_lock_async(udev, 0);
+ usb_disable_asynch(0); /* asynch transfer allowed */
+ if (blkcnt >= ss->max_xfer_blk)
+ debug("\n");
+ return blkcnt;
+
+}
+
+/* Probe to see if a new device is actually a Storage device */
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
+ struct us_data *ss)
+{
+ struct usb_interface *iface;
+ int i;
+ struct usb_endpoint_descriptor *ep_desc;
+ unsigned int flags = 0;
+
+ /* let's examine the device now */
+ iface = &dev->config.if_desc[ifnum];
+
+ if (dev->descriptor.bDeviceClass != 0 ||
+ iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
+ iface->desc.bInterfaceSubClass < US_SC_MIN ||
+ iface->desc.bInterfaceSubClass > US_SC_MAX) {
+ debug("Not mass storage\n");
+ /* if it's not a mass storage, we go no further */
+ return 0;
+ }
+
+ memset(ss, 0, sizeof(struct us_data));
+
+ /* At this point, we know we've got a live one */
+ debug("\n\nUSB Mass Storage device detected\n");
+
+ /* Initialize the us_data structure with some useful info */
+ ss->flags = flags;
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
+ ss->attention_done = 0;
+ ss->subclass = iface->desc.bInterfaceSubClass;
+ ss->protocol = iface->desc.bInterfaceProtocol;
+
+ /* set the handler pointers based on the protocol */
+ debug("Transport: ");
+ switch (ss->protocol) {
+ case US_PR_CB:
+ debug("Control/Bulk\n");
+ ss->transport = usb_stor_CB_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ break;
+
+ case US_PR_CBI:
+ debug("Control/Bulk/Interrupt\n");
+ ss->transport = usb_stor_CB_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ break;
+ case US_PR_BULK:
+ debug("Bulk/Bulk/Bulk\n");
+ ss->transport = usb_stor_BBB_transport;
+ ss->transport_reset = usb_stor_BBB_reset;
+ break;
+ default:
+ printf("USB Storage Transport unknown / not yet implemented\n");
+ return 0;
+ break;
+ }
+
+ /*
+ * We are expecting a minimum of 2 endpoints - in and out (bulk).
+ * An optional interrupt is OK (necessary for CBI protocol).
+ * We will ignore any others.
+ */
+ for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+ ep_desc = &iface->ep_desc[i];
+ /* is it an BULK endpoint? */
+ if ((ep_desc->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ if (ep_desc->bEndpointAddress & USB_DIR_IN)
+ ss->ep_in = ep_desc->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ else
+ ss->ep_out =
+ ep_desc->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ }
+
+ /* is it an interrupt endpoint? */
+ if ((ep_desc->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+ ss->ep_int = ep_desc->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ ss->irqinterval = ep_desc->bInterval;
+ }
+ }
+ debug("Endpoints In %d Out %d Int %d\n",
+ ss->ep_in, ss->ep_out, ss->ep_int);
+
+ /* Do some basic sanity checks, and bail if we find a problem */
+ if (usb_set_interface(dev, iface->desc.bInterfaceNumber, 0) ||
+ !ss->ep_in || !ss->ep_out ||
+ (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
+ debug("Problems with device\n");
+ return 0;
+ }
+ /* set class specific stuff */
+ /* We only handle certain protocols. Currently, these are
+ * the only ones.
+ * The SFF8070 accepts the requests used in u-boot
+ */
+ if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
+ ss->subclass != US_SC_8070) {
+ printf("Sorry, protocol %d not yet supported.\n", ss->subclass);
+ return 0;
+ }
+ if (ss->ep_int) {
+ /* we had found an interrupt endpoint, prepare irq pipe
+ * set up the IRQ pipe and handler
+ */
+ ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
+ ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+ ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
+ dev->irq_handle = usb_stor_irq;
+ }
+
+ /* Set the maximum transfer size per host controller setting */
+ usb_stor_set_max_xfer_blk(dev, ss);
+
+ dev->privptr = (void *)ss;
+ return 1;
+}
+
+int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
+ struct blk_desc *dev_desc)
+{
+ unsigned char perq, modi;
+ ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2);
+ ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36);
+ u32 capacity, blksz;
+ struct scsi_cmd *pccb = &usb_ccb;
+
+ pccb->pdata = usb_stor_buf;
+
+ dev_desc->target = dev->devnum;
+ pccb->lun = dev_desc->lun;
+ debug(" address %d\n", dev_desc->target);
+
+ if (usb_inquiry(pccb, ss)) {
+ debug("%s: usb_inquiry() failed\n", __func__);
+ return -1;
+ }
+
+ perq = usb_stor_buf[0];
+ modi = usb_stor_buf[1];
+
+ /*
+ * Skip unknown devices (0x1f) and enclosure service devices (0x0d),
+ * they would not respond to test_unit_ready .
+ */
+ if (((perq & 0x1f) == 0x1f) || ((perq & 0x1f) == 0x0d)) {
+ debug("%s: unknown/unsupported device\n", __func__);
+ return 0;
+ }
+ if ((modi&0x80) == 0x80) {
+ /* drive is removable */
+ dev_desc->removable = 1;
+ }
+ memcpy(dev_desc->vendor, (const void *)&usb_stor_buf[8], 8);
+ memcpy(dev_desc->product, (const void *)&usb_stor_buf[16], 16);
+ memcpy(dev_desc->revision, (const void *)&usb_stor_buf[32], 4);
+ dev_desc->vendor[8] = 0;
+ dev_desc->product[16] = 0;
+ dev_desc->revision[4] = 0;
+#ifdef CONFIG_USB_BIN_FIXUP
+ usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor,
+ (uchar *)dev_desc->product);
+#endif /* CONFIG_USB_BIN_FIXUP */
+ debug("ISO Vers %X, Response Data %X\n", usb_stor_buf[2],
+ usb_stor_buf[3]);
+ if (usb_test_unit_ready(pccb, ss)) {
+ printf("Device NOT ready\n"
+ " Request Sense returned %02X %02X %02X\n",
+ pccb->sense_buf[2], pccb->sense_buf[12],
+ pccb->sense_buf[13]);
+ if (dev_desc->removable == 1)
+ dev_desc->type = perq;
+ return 0;
+ }
+ pccb->pdata = (unsigned char *)cap;
+ memset(pccb->pdata, 0, 8);
+ if (usb_read_capacity(pccb, ss) != 0) {
+ printf("READ_CAP ERROR\n");
+ ss->flags &= ~USB_READY;
+ cap[0] = 2880;
+ cap[1] = 0x200;
+ }
+ debug("Read Capacity returns: 0x%08x, 0x%08x\n", cap[0], cap[1]);
+#if 0
+ if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
+ cap[0] >>= 16;
+
+ cap[0] = cpu_to_be32(cap[0]);
+ cap[1] = cpu_to_be32(cap[1]);
+#endif
+
+ capacity = be32_to_cpu(cap[0]) + 1;
+ blksz = be32_to_cpu(cap[1]);
+
+ debug("Capacity = 0x%08x, blocksz = 0x%08x\n", capacity, blksz);
+ dev_desc->lba = capacity;
+ dev_desc->blksz = blksz;
+ dev_desc->log2blksz = LOG2(dev_desc->blksz);
+ dev_desc->type = perq;
+ debug(" address %d\n", dev_desc->target);
+
+ return 1;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+
+static int usb_mass_storage_probe(struct udevice *dev)
+{
+ struct usb_device *udev = dev_get_parent_priv(dev);
+ int ret;
+
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+ ret = usb_stor_probe_device(udev);
+ usb_disable_asynch(0); /* asynch transfer allowed */
+
+ return ret;
+}
+
+static const struct udevice_id usb_mass_storage_ids[] = {
+ { .compatible = "usb-mass-storage" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_mass_storage) = {
+ .name = "usb_mass_storage",
+ .id = UCLASS_MASS_STORAGE,
+ .of_match = usb_mass_storage_ids,
+ .probe = usb_mass_storage_probe,
+#if CONFIG_IS_ENABLED(BLK)
+ .plat_auto = sizeof(struct us_data),
+#endif
+};
+
+UCLASS_DRIVER(usb_mass_storage) = {
+ .id = UCLASS_MASS_STORAGE,
+ .name = "usb_mass_storage",
+};
+
+static const struct usb_device_id mass_storage_id_table[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE
+ },
+ { } /* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);
+#endif
+
+#if CONFIG_IS_ENABLED(BLK)
+static const struct blk_ops usb_storage_ops = {
+ .read = usb_stor_read,
+ .write = usb_stor_write,
+};
+
+U_BOOT_DRIVER(usb_storage_blk) = {
+ .name = "usb_storage_blk",
+ .id = UCLASS_BLK,
+ .ops = &usb_storage_ops,
+};
+#else
+U_BOOT_LEGACY_BLK(usb) = {
+ .if_typename = "usb",
+ .if_type = IF_TYPE_USB,
+ .max_devs = USB_MAX_STOR_DEV,
+ .desc = usb_dev_desc,
+};
+#endif
diff --git a/roms/u-boot/common/xyzModem.c b/roms/u-boot/common/xyzModem.c
new file mode 100644
index 000000000..fc3459ebb
--- /dev/null
+++ b/roms/u-boot/common/xyzModem.c
@@ -0,0 +1,711 @@
+// SPDX-License-Identifier: eCos-2.0
+/*
+ *==========================================================================
+ *
+ * xyzModem.c
+ *
+ * RedBoot stream handler for xyzModem protocol
+ *
+ *==========================================================================
+ *#####DESCRIPTIONBEGIN####
+ *
+ * Author(s): gthomas
+ * Contributors: gthomas, tsmith, Yoshinori Sato
+ * Date: 2000-07-14
+ * Purpose:
+ * Description:
+ *
+ * This code is part of RedBoot (tm).
+ *
+ *####DESCRIPTIONEND####
+ *
+ *==========================================================================
+ */
+#include <common.h>
+#include <xyzModem.h>
+#include <stdarg.h>
+#include <u-boot/crc.h>
+#include <watchdog.h>
+
+/* Assumption - run xyzModem protocol over the console port */
+
+/* Values magic to the protocol */
+#define SOH 0x01
+#define STX 0x02
+#define EOT 0x04
+#define ACK 0x06
+#define BSP 0x08
+#define NAK 0x15
+#define CAN 0x18
+#define EOF 0x1A /* ^Z for DOS officionados */
+
+/* Data & state local to the protocol */
+static struct
+{
+ int *__chan;
+ unsigned char pkt[1024], *bufp;
+ unsigned char blk, cblk, crc1, crc2;
+ unsigned char next_blk; /* Expected block */
+ int len, mode, total_retries;
+ int total_SOH, total_STX, total_CAN;
+ bool crc_mode, at_eof, tx_ack;
+ unsigned long file_length, read_length;
+} xyz;
+
+#define xyzModem_CHAR_TIMEOUT 2000 /* 2 seconds */
+#define xyzModem_MAX_RETRIES 20
+#define xyzModem_MAX_RETRIES_WITH_CRC 10
+#define xyzModem_CAN_COUNT 3 /* Wait for 3 CAN before quitting */
+
+
+typedef int cyg_int32;
+static int
+CYGACC_COMM_IF_GETC_TIMEOUT (char chan, char *c)
+{
+
+ ulong now = get_timer(0);
+ WATCHDOG_RESET();
+ while (!tstc ())
+ {
+ if (get_timer(now) > xyzModem_CHAR_TIMEOUT)
+ break;
+ }
+ if (tstc ())
+ {
+ *c = getchar();
+ return 1;
+ }
+ return 0;
+}
+
+static void
+CYGACC_COMM_IF_PUTC (char x, char y)
+{
+ putc (y);
+}
+
+/* Validate a hex character */
+__inline__ static bool
+_is_hex (char c)
+{
+ return (((c >= '0') && (c <= '9')) ||
+ ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')));
+}
+
+/* Convert a single hex nibble */
+__inline__ static int
+_from_hex (char c)
+{
+ int ret = 0;
+
+ if ((c >= '0') && (c <= '9'))
+ {
+ ret = (c - '0');
+ }
+ else if ((c >= 'a') && (c <= 'f'))
+ {
+ ret = (c - 'a' + 0x0a);
+ }
+ else if ((c >= 'A') && (c <= 'F'))
+ {
+ ret = (c - 'A' + 0x0A);
+ }
+ return ret;
+}
+
+/* Convert a character to lower case */
+__inline__ static char
+_tolower (char c)
+{
+ if ((c >= 'A') && (c <= 'Z'))
+ {
+ c = (c - 'A') + 'a';
+ }
+ return c;
+}
+
+/* Parse (scan) a number */
+static bool
+parse_num (char *s, unsigned long *val, char **es, char *delim)
+{
+ bool first = true;
+ int radix = 10;
+ char c;
+ unsigned long result = 0;
+ int digit;
+
+ while (*s == ' ')
+ s++;
+ while (*s)
+ {
+ if (first && (s[0] == '0') && (_tolower (s[1]) == 'x'))
+ {
+ radix = 16;
+ s += 2;
+ }
+ first = false;
+ c = *s++;
+ if (_is_hex (c) && ((digit = _from_hex (c)) < radix))
+ {
+ /* Valid digit */
+ result = (result * radix) + digit;
+ }
+ else
+ {
+ if (delim != (char *) 0)
+ {
+ /* See if this character is one of the delimiters */
+ char *dp = delim;
+ while (*dp && (c != *dp))
+ dp++;
+ if (*dp)
+ break; /* Found a good delimiter */
+ }
+ return false; /* Malformatted number */
+ }
+ }
+ *val = result;
+ if (es != (char **) 0)
+ {
+ *es = s;
+ }
+ return true;
+}
+
+
+#if defined(DEBUG) && !CONFIG_IS_ENABLED(USE_TINY_PRINTF)
+/*
+ * Note: this debug setup works by storing the strings in a fixed buffer
+ */
+static char zm_debug_buf[8192];
+static char *zm_out = zm_debug_buf;
+static char *zm_out_start = zm_debug_buf;
+
+static int
+zm_dprintf(char *fmt, ...)
+{
+ int len;
+ va_list args;
+
+ va_start(args, fmt);
+ len = diag_vsprintf(zm_out, fmt, args);
+ va_end(args);
+ zm_out += len;
+ return len;
+}
+
+static void
+zm_flush (void)
+{
+ zm_out = zm_out_start;
+}
+
+static void
+zm_dump_buf (void *buf, int len)
+{
+
+}
+
+static unsigned char zm_buf[2048];
+static unsigned char *zm_bp;
+
+static void
+zm_new (void)
+{
+ zm_bp = zm_buf;
+}
+
+static void
+zm_save (unsigned char c)
+{
+ *zm_bp++ = c;
+}
+
+static void
+zm_dump (int line)
+{
+ zm_dprintf ("Packet at line: %d\n", line);
+ zm_dump_buf (zm_buf, zm_bp - zm_buf);
+}
+
+#define ZM_DEBUG(x) x
+#else
+#define ZM_DEBUG(x)
+#endif
+
+/* Wait for the line to go idle */
+static void
+xyzModem_flush (void)
+{
+ int res;
+ char c;
+ while (true)
+ {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
+ if (!res)
+ return;
+ }
+}
+
+static int
+xyzModem_get_hdr (void)
+{
+ char c;
+ int res;
+ bool hdr_found = false;
+ int i, can_total, hdr_chars;
+ unsigned short cksum;
+
+ ZM_DEBUG (zm_new ());
+ /* Find the start of a header */
+ can_total = 0;
+ hdr_chars = 0;
+
+ if (xyz.tx_ack)
+ {
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ xyz.tx_ack = false;
+ }
+ while (!hdr_found)
+ {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
+ ZM_DEBUG (zm_save (c));
+ if (res)
+ {
+ hdr_chars++;
+ switch (c)
+ {
+ case SOH:
+ xyz.total_SOH++;
+ case STX:
+ if (c == STX)
+ xyz.total_STX++;
+ hdr_found = true;
+ break;
+ case CAN:
+ xyz.total_CAN++;
+ ZM_DEBUG (zm_dump (__LINE__));
+ if (++can_total == xyzModem_CAN_COUNT)
+ {
+ return xyzModem_cancel;
+ }
+ else
+ {
+ /* Wait for multiple CAN to avoid early quits */
+ break;
+ }
+ case EOT:
+ /* EOT only supported if no noise */
+ if (hdr_chars == 1)
+ {
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ ZM_DEBUG (zm_dprintf ("ACK on EOT #%d\n", __LINE__));
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_eof;
+ }
+ default:
+ /* Ignore, waiting for start of header */
+ ;
+ }
+ }
+ else
+ {
+ /* Data stream timed out */
+ xyzModem_flush (); /* Toss any current input */
+ ZM_DEBUG (zm_dump (__LINE__));
+ CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
+ return xyzModem_timeout;
+ }
+ }
+
+ /* Header found, now read the data */
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.blk);
+ ZM_DEBUG (zm_save (xyz.blk));
+ if (!res)
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.cblk);
+ ZM_DEBUG (zm_save (xyz.cblk));
+ if (!res)
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ xyz.len = (c == SOH) ? 128 : 1024;
+ xyz.bufp = xyz.pkt;
+ for (i = 0; i < xyz.len; i++)
+ {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
+ ZM_DEBUG (zm_save (c));
+ if (res)
+ {
+ xyz.pkt[i] = c;
+ }
+ else
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ }
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc1);
+ ZM_DEBUG (zm_save (xyz.crc1));
+ if (!res)
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ if (xyz.crc_mode)
+ {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc2);
+ ZM_DEBUG (zm_save (xyz.crc2));
+ if (!res)
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ }
+ ZM_DEBUG (zm_dump (__LINE__));
+ /* Validate the message */
+ if ((xyz.blk ^ xyz.cblk) != (unsigned char) 0xFF)
+ {
+ ZM_DEBUG (zm_dprintf
+ ("Framing error - blk: %x/%x/%x\n", xyz.blk, xyz.cblk,
+ (xyz.blk ^ xyz.cblk)));
+ ZM_DEBUG (zm_dump_buf (xyz.pkt, xyz.len));
+ xyzModem_flush ();
+ return xyzModem_frame;
+ }
+ /* Verify checksum/CRC */
+ if (xyz.crc_mode)
+ {
+ cksum = crc16_ccitt(0, xyz.pkt, xyz.len);
+ if (cksum != ((xyz.crc1 << 8) | xyz.crc2))
+ {
+ ZM_DEBUG (zm_dprintf ("CRC error - recvd: %02x%02x, computed: %x\n",
+ xyz.crc1, xyz.crc2, cksum & 0xFFFF));
+ return xyzModem_cksum;
+ }
+ }
+ else
+ {
+ cksum = 0;
+ for (i = 0; i < xyz.len; i++)
+ {
+ cksum += xyz.pkt[i];
+ }
+ if (xyz.crc1 != (cksum & 0xFF))
+ {
+ ZM_DEBUG (zm_dprintf
+ ("Checksum error - recvd: %x, computed: %x\n", xyz.crc1,
+ cksum & 0xFF));
+ return xyzModem_cksum;
+ }
+ }
+ /* If we get here, the message passes [structural] muster */
+ return 0;
+}
+
+int
+xyzModem_stream_open (connection_info_t * info, int *err)
+{
+ int stat = 0;
+ int retries = xyzModem_MAX_RETRIES;
+ int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;
+
+/* ZM_DEBUG(zm_out = zm_out_start); */
+#ifdef xyzModem_zmodem
+ if (info->mode == xyzModem_zmodem)
+ {
+ *err = xyzModem_noZmodem;
+ return -1;
+ }
+#endif
+
+/* TODO: CHECK ! */
+ int dummy = 0;
+ xyz.__chan = &dummy;
+ xyz.len = 0;
+ xyz.crc_mode = true;
+ xyz.at_eof = false;
+ xyz.tx_ack = false;
+ xyz.mode = info->mode;
+ xyz.total_retries = 0;
+ xyz.total_SOH = 0;
+ xyz.total_STX = 0;
+ xyz.total_CAN = 0;
+ xyz.read_length = 0;
+ xyz.file_length = 0;
+
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+
+ if (xyz.mode == xyzModem_xmodem)
+ {
+ /* X-modem doesn't have an information header - exit here */
+ xyz.next_blk = 1;
+ return 0;
+ }
+
+ while (retries-- > 0)
+ {
+ stat = xyzModem_get_hdr ();
+ if (stat == 0)
+ {
+ /* Y-modem file information header */
+ if (xyz.blk == 0)
+ {
+ /* skip filename */
+ while (*xyz.bufp++);
+ /* get the length */
+ parse_num ((char *) xyz.bufp, &xyz.file_length, NULL, " ");
+ /* The rest of the file name data block quietly discarded */
+ xyz.tx_ack = true;
+ }
+ xyz.next_blk = 1;
+ xyz.len = 0;
+ return 0;
+ }
+ else if (stat == xyzModem_timeout)
+ {
+ if (--crc_retries <= 0)
+ xyz.crc_mode = false;
+ CYGACC_CALL_IF_DELAY_US (5 * 100000); /* Extra delay for startup */
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+ xyz.total_retries++;
+ ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__));
+ }
+ if (stat == xyzModem_cancel)
+ {
+ break;
+ }
+ }
+ *err = stat;
+ ZM_DEBUG (zm_flush ());
+ return -1;
+}
+
+int
+xyzModem_stream_read (char *buf, int size, int *err)
+{
+ int stat, total, len;
+ int retries;
+
+ total = 0;
+ stat = xyzModem_cancel;
+ /* Try and get 'size' bytes into the buffer */
+ while (!xyz.at_eof && (size > 0))
+ {
+ if (xyz.len == 0)
+ {
+ retries = xyzModem_MAX_RETRIES;
+ while (retries-- > 0)
+ {
+ stat = xyzModem_get_hdr ();
+ if (stat == 0)
+ {
+ if (xyz.blk == xyz.next_blk)
+ {
+ xyz.tx_ack = true;
+ ZM_DEBUG (zm_dprintf
+ ("ACK block %d (%d)\n", xyz.blk, __LINE__));
+ xyz.next_blk = (xyz.next_blk + 1) & 0xFF;
+
+ if (xyz.mode == xyzModem_xmodem || xyz.file_length == 0)
+ {
+ /* Data blocks can be padded with ^Z (EOF) characters */
+ /* This code tries to detect and remove them */
+ if ((xyz.bufp[xyz.len - 1] == EOF) &&
+ (xyz.bufp[xyz.len - 2] == EOF) &&
+ (xyz.bufp[xyz.len - 3] == EOF))
+ {
+ while (xyz.len
+ && (xyz.bufp[xyz.len - 1] == EOF))
+ {
+ xyz.len--;
+ }
+ }
+ }
+
+ /*
+ * See if accumulated length exceeds that of the file.
+ * If so, reduce size (i.e., cut out pad bytes)
+ * Only do this for Y-modem (and Z-modem should it ever
+ * be supported since it can fall back to Y-modem mode).
+ */
+ if (xyz.mode != xyzModem_xmodem && 0 != xyz.file_length)
+ {
+ xyz.read_length += xyz.len;
+ if (xyz.read_length > xyz.file_length)
+ {
+ xyz.len -= (xyz.read_length - xyz.file_length);
+ }
+ }
+ break;
+ }
+ else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF))
+ {
+ /* Just re-ACK this so sender will get on with it */
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ continue; /* Need new header */
+ }
+ else
+ {
+ stat = xyzModem_sequence;
+ }
+ }
+ if (stat == xyzModem_cancel)
+ {
+ break;
+ }
+ if (stat == xyzModem_eof)
+ {
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ ZM_DEBUG (zm_dprintf ("ACK (%d)\n", __LINE__));
+ if (xyz.mode == xyzModem_ymodem)
+ {
+ CYGACC_COMM_IF_PUTC (*xyz.__chan,
+ (xyz.crc_mode ? 'C' : NAK));
+ xyz.total_retries++;
+ ZM_DEBUG (zm_dprintf ("Reading Final Header\n"));
+ stat = xyzModem_get_hdr ();
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ ZM_DEBUG (zm_dprintf ("FINAL ACK (%d)\n", __LINE__));
+ }
+ xyz.at_eof = true;
+ break;
+ }
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+ xyz.total_retries++;
+ ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__));
+ }
+ if (stat < 0)
+ {
+ *err = stat;
+ xyz.len = -1;
+ return total;
+ }
+ }
+ /* Don't "read" data from the EOF protocol package */
+ if (!xyz.at_eof)
+ {
+ len = xyz.len;
+ if (size < len)
+ len = size;
+ memcpy (buf, xyz.bufp, len);
+ size -= len;
+ buf += len;
+ total += len;
+ xyz.len -= len;
+ xyz.bufp += len;
+ }
+ }
+ return total;
+}
+
+void
+xyzModem_stream_close (int *err)
+{
+ diag_printf
+ ("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets, %d retries\n",
+ xyz.crc_mode ? "CRC" : "Cksum", xyz.total_SOH, xyz.total_STX,
+ xyz.total_CAN, xyz.total_retries);
+ ZM_DEBUG (zm_flush ());
+}
+
+/* Need to be able to clean out the input buffer, so have to take the */
+/* getc */
+void
+xyzModem_stream_terminate (bool abort, int (*getc) (void))
+{
+ int c;
+
+ if (abort)
+ {
+ ZM_DEBUG (zm_dprintf ("!!!! TRANSFER ABORT !!!!\n"));
+ switch (xyz.mode)
+ {
+ case xyzModem_xmodem:
+ case xyzModem_ymodem:
+ /* The X/YMODEM Spec seems to suggest that multiple CAN followed by an equal */
+ /* number of Backspaces is a friendly way to get the other end to abort. */
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
+ /* Now consume the rest of what's waiting on the line. */
+ ZM_DEBUG (zm_dprintf ("Flushing serial line.\n"));
+ xyzModem_flush ();
+ xyz.at_eof = true;
+ break;
+#ifdef xyzModem_zmodem
+ case xyzModem_zmodem:
+ /* Might support it some day I suppose. */
+#endif
+ break;
+ }
+ }
+ else
+ {
+ ZM_DEBUG (zm_dprintf ("Engaging cleanup mode...\n"));
+ /*
+ * Consume any trailing crap left in the inbuffer from
+ * previous received blocks. Since very few files are an exact multiple
+ * of the transfer block size, there will almost always be some gunk here.
+ * If we don't eat it now, RedBoot will think the user typed it.
+ */
+ ZM_DEBUG (zm_dprintf ("Trailing gunk:\n"));
+ while ((c = (*getc) ()) > -1)
+ ;
+ ZM_DEBUG (zm_dprintf ("\n"));
+ /*
+ * Make a small delay to give terminal programs like minicom
+ * time to get control again after their file transfer program
+ * exits.
+ */
+ CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
+ }
+}
+
+char *
+xyzModem_error (int err)
+{
+ switch (err)
+ {
+ case xyzModem_access:
+ return "Can't access file";
+ break;
+ case xyzModem_noZmodem:
+ return "Sorry, zModem not available yet";
+ break;
+ case xyzModem_timeout:
+ return "Timed out";
+ break;
+ case xyzModem_eof:
+ return "End of file";
+ break;
+ case xyzModem_cancel:
+ return "Cancelled";
+ break;
+ case xyzModem_frame:
+ return "Invalid framing";
+ break;
+ case xyzModem_cksum:
+ return "CRC/checksum error";
+ break;
+ case xyzModem_sequence:
+ return "Block sequence error";
+ break;
+ default:
+ return "Unknown error";
+ break;
+ }
+}
+
+/*
+ * RedBoot interface
+ */