Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63b48880df | ||
|
|
7418d98fef | ||
|
|
cfcb9b1ac8 | ||
|
|
5841e78ed6 | ||
|
|
8fa2f3610d | ||
|
|
ea9e72801c | ||
|
|
796206b5ac | ||
|
|
1c56f6babc | ||
|
|
62ba2d48dd | ||
|
|
7b94a32be2 | ||
|
|
9e7b8db24d | ||
|
|
d47b5693e2 | ||
|
|
811fcc0738 |
2
Kconfig
2
Kconfig
@@ -551,7 +551,7 @@ config SYS_LOAD_ADDR
|
||||
default 0x12000000 if ARCH_MX6 && !(MX6SL || MX6SLL || MX6SX || MX6UL || MX6ULL)
|
||||
default 0x80800000 if ARCH_MX7
|
||||
default 0x90000000 if FSL_LSCH2 || FSL_LSCH3
|
||||
default 0x02000000 if ARCH_EFI
|
||||
default 0 if ARCH_EFI
|
||||
default 0x0 if ARCH_SC5XX
|
||||
help
|
||||
Address in memory to use as the default safe load address.
|
||||
|
||||
@@ -28,7 +28,7 @@ choice
|
||||
config TARGET_VEXPRESS64_BASE_FVP
|
||||
bool "Support Versatile Express ARMv8a FVP BASE model"
|
||||
select VEXPRESS64_BASE_MODEL
|
||||
imply OF_HAS_PRIOR_STAGE
|
||||
imply OF_HAS_PRIOR_STAGE if !BLOBLIST
|
||||
|
||||
config TARGET_VEXPRESS64_BASER_FVP
|
||||
bool "Support Versatile Express ARMv8r64 FVP BASE model"
|
||||
|
||||
@@ -3,5 +3,8 @@
|
||||
# (C) Copyright 2000-2004
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
obj-y := vexpress64.o lowlevel_init.o
|
||||
obj-y := vexpress64.o
|
||||
|
||||
obj-$(CONFIG_OF_HAS_PRIOR_STAGE) += lowlevel_init.o
|
||||
|
||||
obj-$(CONFIG_TARGET_VEXPRESS64_JUNO) += pcie.o
|
||||
|
||||
@@ -100,7 +100,9 @@ int dram_init_banksize(void)
|
||||
* Push the variable into the .data section so that it
|
||||
* does not get cleared later.
|
||||
*/
|
||||
#ifdef CONFIG_OF_HAS_PRIOR_STAGE
|
||||
unsigned long __section(".data") prior_stage_fdt_address[2];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_BOARD
|
||||
|
||||
@@ -151,6 +153,7 @@ static phys_addr_t find_dtb_in_nor_flash(const char *partname)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_HAS_PRIOR_STAGE
|
||||
/*
|
||||
* Filter for a valid DTB, as TF-A happens to provide a pointer to some
|
||||
* data structure using the DTB format, which we cannot use.
|
||||
@@ -201,6 +204,7 @@ int board_fdt_blob_setup(void **fdtp)
|
||||
return -ENXIO;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Actual reset is done via PSCI. */
|
||||
void reset_cpu(void)
|
||||
|
||||
@@ -17,7 +17,7 @@ config TARGET_EFI_X86_APP32
|
||||
help
|
||||
This target is used for running U-Boot on top of EFI. In
|
||||
this case EFI does the early initialisation, and U-Boot
|
||||
takes over once the RAM, video and CPU are fully running.
|
||||
starts once the RAM, video and CPU are fully running.
|
||||
U-Boot is loaded as an application from EFI.
|
||||
|
||||
config TARGET_EFI_X86_APP64
|
||||
@@ -27,7 +27,7 @@ config TARGET_EFI_X86_APP64
|
||||
help
|
||||
This target is used for running U-Boot on top of EFI in 64-bit mode.
|
||||
In this case EFI does the early initialisation, and U-Boot
|
||||
takes over once the RAM, video and CPU are fully running.
|
||||
starts once the RAM, video and CPU are fully running.
|
||||
U-Boot is loaded as an application from EFI.
|
||||
|
||||
config TARGET_EFI_X86_PAYLOAD
|
||||
@@ -59,7 +59,7 @@ config TARGET_EFI_ARM_APP64
|
||||
help
|
||||
This target is used for running U-Boot on top of EFI in 64-bit mode.
|
||||
In this case EFI does the early initialisation, and U-Boot
|
||||
takes over once the RAM, video and CPU are fully running.
|
||||
starts once the RAM, video and CPU are fully running.
|
||||
U-Boot is loaded as an application from EFI.
|
||||
|
||||
endchoice
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
EFI-ARM_APP32 BOARD
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
F: board/efi/Kconfig
|
||||
F: board/efi/efi-arm_app/
|
||||
F: configs/efi-arm_app32_defconfig
|
||||
|
||||
EFI-ARM_APP64 BOARD
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
|
||||
@@ -1055,8 +1055,8 @@ choice
|
||||
config BLOBLIST_FIXED
|
||||
bool "Place bloblist at a fixed address in memory"
|
||||
help
|
||||
Select this to used a fixed memory address for the bloblist. If the
|
||||
bloblist exists at this address from a previous phase, it used as is.
|
||||
Select this to use a fixed memory address for the bloblist. If the
|
||||
bloblist exists at this address from a previous phase, it is used as is.
|
||||
If not it is created at this address in U-Boot.
|
||||
|
||||
config BLOBLIST_ALLOC
|
||||
@@ -1066,6 +1066,12 @@ config BLOBLIST_ALLOC
|
||||
specify a fixed address on systems where this is unknown or can
|
||||
change at runtime.
|
||||
|
||||
config BLOBLIST_PASSAGE
|
||||
bool "Use bloblist in-place"
|
||||
help
|
||||
Use a bloblist in the incoming standard passage. The size is detected
|
||||
automatically so CONFIG_BLOBLIST_SIZE can be 0.
|
||||
|
||||
endchoice
|
||||
|
||||
config BLOBLIST_ADDR
|
||||
@@ -1080,17 +1086,17 @@ config BLOBLIST_ADDR
|
||||
|
||||
config BLOBLIST_SIZE
|
||||
hex "Size of bloblist"
|
||||
default 0x0 if BLOBLIST_PASSAGE
|
||||
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 phases.
|
||||
proper), and this same bloblist is used for subsequent phases.
|
||||
|
||||
config BLOBLIST_SIZE_RELOC
|
||||
hex "Size of bloblist after relocation"
|
||||
default BLOBLIST_SIZE if BLOBLIST_FIXED || BLOBLIST_ALLOC
|
||||
default 0x0 if BLOBLIST_PASSAGE
|
||||
default 0x20000 if (ARM && EFI_LOADER && GENERATE_ACPI_TABLE)
|
||||
help
|
||||
Sets the size of the bloblist in bytes after relocation. Since U-Boot
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
@@ -489,6 +489,9 @@ int bloblist_reloc(void *to, uint to_size)
|
||||
{
|
||||
struct bloblist_hdr *hdr;
|
||||
|
||||
if (!to_size)
|
||||
return 0;
|
||||
|
||||
if (to_size < gd->bloblist->total_size)
|
||||
return -ENOSPC;
|
||||
|
||||
@@ -519,13 +522,6 @@ int bloblist_init(void)
|
||||
* at a fixed address.
|
||||
*/
|
||||
bool from_addr = fixed && !xpl_is_first_phase();
|
||||
/*
|
||||
* If U-Boot is in the first phase that an arch custom routine should
|
||||
* install the bloblist passed from previous loader to this fixed
|
||||
* address.
|
||||
*/
|
||||
bool from_boot_arg = fixed && xpl_is_first_phase();
|
||||
|
||||
if (xpl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST))
|
||||
from_addr = false;
|
||||
if (fixed)
|
||||
@@ -533,7 +529,13 @@ int bloblist_init(void)
|
||||
CONFIG_BLOBLIST_ADDR);
|
||||
size = CONFIG_BLOBLIST_SIZE;
|
||||
|
||||
if (from_boot_arg)
|
||||
|
||||
/*
|
||||
* If the current boot stage is the first phase of U-Boot, then an
|
||||
* architecture-specific routine should be used to handle the bloblist
|
||||
* passed from the previous boot loader
|
||||
*/
|
||||
if (xpl_is_first_phase() && !IS_ENABLED(CONFIG_BLOBLIST_ALLOC))
|
||||
ret = xferlist_from_boot_arg(addr, size);
|
||||
else if (from_addr)
|
||||
ret = bloblist_check(addr, size);
|
||||
|
||||
5
configs/vexpress_fvp_bloblist_defconfig
Normal file
5
configs/vexpress_fvp_bloblist_defconfig
Normal file
@@ -0,0 +1,5 @@
|
||||
#include <configs/vexpress_fvp_defconfig>
|
||||
|
||||
CONFIG_BLOBLIST=y
|
||||
CONFIG_BLOBLIST_PASSAGE=y
|
||||
CONFIG_BLOBLIST_SIZE_RELOC=0x10000
|
||||
@@ -43,6 +43,22 @@ Juno is an Arm development board with the following features:
|
||||
|
||||
More details can be found in the board documentation [3]_.
|
||||
|
||||
Bloblist Support
|
||||
----------------
|
||||
|
||||
The ``vexpress_fvp_bloblist_defconfig`` configures U-Boot to be compiled for
|
||||
Vexpress64 with Bloblist as the primary method for information handoff between
|
||||
boot stages. U-Boot offers three methods to set up a bloblist: using a
|
||||
predefined bloblist at a specified address, dynamically allocating memory for a
|
||||
bloblist, or utilizing a standard passage-provided bloblist with automatic size
|
||||
detection.
|
||||
|
||||
By default, ``vexpress_fvp_bloblist_defconfig`` uses the standard passage method
|
||||
(CONFIG_BLOBLIST_PASSAGE) because TF-A provides a Transfer List in non-secure
|
||||
memory that U-Boot can utilise. This Bloblist, which is referred to as a Transfer List in
|
||||
TF-A, contains all necessary data for the handoff process, including DT and ACPI
|
||||
tables.
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
|
||||
@@ -737,13 +737,9 @@ static int cr50_i2c_report_state(struct udevice *dev, char *str, int str_max)
|
||||
|
||||
static int cr50_i2c_open(struct udevice *dev)
|
||||
{
|
||||
struct cr50_priv *priv = dev_get_priv(dev);
|
||||
char buf[80];
|
||||
int ret;
|
||||
|
||||
if (priv->locality != -1)
|
||||
return -EBUSY;
|
||||
|
||||
ret = process_reset(dev);
|
||||
if (ret)
|
||||
return log_msg_ret("reset", ret);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <malloc.h>
|
||||
#include <memalign.h>
|
||||
#include <part.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/stat.h>
|
||||
#include <div64.h>
|
||||
#include "ext4_common.h"
|
||||
@@ -108,8 +109,15 @@ int ext4fs_get_bgdtable(void)
|
||||
{
|
||||
int status;
|
||||
struct ext_filesystem *fs = get_fs();
|
||||
int gdsize_total = ROUND(fs->no_blkgrp * fs->gdsize, fs->blksz);
|
||||
size_t alloc_size;
|
||||
int gdsize_total;
|
||||
|
||||
if (check_mul_overflow(fs->no_blkgrp, fs->gdsize, &alloc_size))
|
||||
return -1;
|
||||
gdsize_total = ROUND(alloc_size, fs->blksz);
|
||||
fs->no_blk_pergdt = gdsize_total / fs->blksz;
|
||||
if (!fs->no_blk_pergdt)
|
||||
return -1;
|
||||
|
||||
/* allocate memory for gdtable */
|
||||
fs->gdtable = zalloc(gdsize_total);
|
||||
@@ -117,7 +125,7 @@ int ext4fs_get_bgdtable(void)
|
||||
return -ENOMEM;
|
||||
/* read the group descriptor table */
|
||||
status = ext4fs_devread((lbaint_t)fs->gdtable_blkno * fs->sect_perblk,
|
||||
0, fs->blksz * fs->no_blk_pergdt, fs->gdtable);
|
||||
0, gdsize_total, fs->gdtable);
|
||||
if (status == 0)
|
||||
goto fail;
|
||||
|
||||
@@ -599,10 +607,17 @@ int ext4fs_init(void)
|
||||
int i;
|
||||
uint32_t real_free_blocks = 0;
|
||||
struct ext_filesystem *fs = get_fs();
|
||||
size_t alloc_size;
|
||||
|
||||
/* check for a reasonable block size, no more than 64K */
|
||||
if (LOG2_BLOCK_SIZE(ext4fs_root) > 16)
|
||||
goto fail;
|
||||
|
||||
/* populate fs */
|
||||
fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
|
||||
fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
|
||||
if (!fs->sect_perblk)
|
||||
goto fail;
|
||||
|
||||
/* get the superblock */
|
||||
fs->sb = zalloc(SUPERBLOCK_SIZE);
|
||||
@@ -629,7 +644,9 @@ int ext4fs_init(void)
|
||||
}
|
||||
|
||||
/* load all the available bitmap block of the partition */
|
||||
fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
|
||||
if (check_mul_overflow(fs->no_blkgrp, sizeof(char *), &alloc_size))
|
||||
goto fail;
|
||||
fs->blk_bmaps = zalloc(alloc_size);
|
||||
if (!fs->blk_bmaps)
|
||||
goto fail;
|
||||
for (i = 0; i < fs->no_blkgrp; i++) {
|
||||
@@ -649,7 +666,7 @@ int ext4fs_init(void)
|
||||
}
|
||||
|
||||
/* load all the available inode bitmap of the partition */
|
||||
fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
|
||||
fs->inode_bmaps = zalloc(alloc_size);
|
||||
if (!fs->inode_bmaps)
|
||||
goto fail;
|
||||
for (i = 0; i < fs->no_blkgrp; i++) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause */
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* This provides a standard way of passing information between boot phases
|
||||
* (TPL -> SPL -> U-Boot proper.)
|
||||
@@ -475,7 +475,7 @@ int bloblist_init(void);
|
||||
/**
|
||||
* bloblist_maybe_init() - Init the bloblist system if not already done
|
||||
*
|
||||
* Calls bloblist_init() if the GD_FLG_BLOBLIST_READY flag is not et
|
||||
* Calls bloblist_init() if the GD_FLG_BLOBLIST_READY flag is not set
|
||||
*
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
|
||||
@@ -169,12 +169,14 @@
|
||||
" if load hostfs - ${kernel_addr_r} ${kernel_name}; then" \
|
||||
" setenv fdt_high 0xffffffffffffffff;" \
|
||||
" setenv initrd_high 0xffffffffffffffff;" \
|
||||
" load hostfs - ${fdt_addr_r} ${fdtfile};" \
|
||||
" if test -n load hostfs - ${fdt_addr_r} ${fdtfile}; then" \
|
||||
" fdt move $fdtcontroladdr $fdt_addr_r;" \
|
||||
" fi;" \
|
||||
" load hostfs - ${ramdisk_addr_r} ${ramdisk_name};" \
|
||||
" fdt addr ${fdt_addr_r};" \
|
||||
" fdt resize;" \
|
||||
" fdt chosen ${ramdisk_addr_r} ${filesize};" \
|
||||
" booti $kernel_addr_r - $fdt_addr_r;" \
|
||||
" booti $kernel_addr_r - ${fdt_addr_r};" \
|
||||
" fi;" \
|
||||
"fi\0"
|
||||
#define BOOTENV_DEV_NAME_SMH(devtypeu, devtypel, instance) "smh "
|
||||
|
||||
@@ -67,8 +67,7 @@ struct cmd_tbl;
|
||||
#define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data))
|
||||
|
||||
/* Log2 size of ext2 block in bytes. */
|
||||
#define LOG2_BLOCK_SIZE(data) (le32_to_cpu \
|
||||
(data->sblock.log2_block_size) \
|
||||
#define LOG2_BLOCK_SIZE(data) (le32_to_cpu((data)->sblock.log2_block_size) \
|
||||
+ EXT2_MIN_BLOCK_LOG_SIZE)
|
||||
|
||||
#define EXT2_FT_DIR 2
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#ifndef _LIMITS_H
|
||||
#define _LIMITS_H
|
||||
|
||||
#include <linux/limits.h>
|
||||
|
||||
#define INT_MAX 0x7fffffff
|
||||
#define UINT_MAX 0xffffffffU
|
||||
#define CHAR_BIT 8
|
||||
|
||||
@@ -16,18 +16,6 @@
|
||||
#define LLONG_MIN (-LLONG_MAX - 1)
|
||||
#define ULLONG_MAX (~0ULL)
|
||||
|
||||
#define U8_MAX ((u8)~0U)
|
||||
#define S8_MAX ((s8)(U8_MAX>>1))
|
||||
#define S8_MIN ((s8)(-S8_MAX - 1))
|
||||
#define U16_MAX ((u16)~0U)
|
||||
#define S16_MAX ((s16)(U16_MAX>>1))
|
||||
#define S16_MIN ((s16)(-S16_MAX - 1))
|
||||
#define U32_MAX ((u32)~0U)
|
||||
#define S32_MAX ((s32)(U32_MAX>>1))
|
||||
#define S32_MIN ((s32)(-S32_MAX - 1))
|
||||
#define U64_MAX ((u64)~0ULL)
|
||||
#define S64_MAX ((s64)(U64_MAX>>1))
|
||||
#define S64_MIN ((s64)(-S64_MAX - 1))
|
||||
|
||||
#define INT32_MAX S32_MAX
|
||||
|
||||
|
||||
21
include/linux/limits.h
Normal file
21
include/linux/limits.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_LIMITS_H
|
||||
#define _LINUX_LIMITS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define U8_MAX ((u8)~0U)
|
||||
#define S8_MAX ((s8)(U8_MAX >> 1))
|
||||
#define S8_MIN ((s8)(-S8_MAX - 1))
|
||||
#define U16_MAX ((u16)~0U)
|
||||
#define S16_MAX ((s16)(U16_MAX >> 1))
|
||||
#define S16_MIN ((s16)(-S16_MAX - 1))
|
||||
#define U32_MAX ((u32)~0U)
|
||||
#define U32_MIN ((u32)0)
|
||||
#define S32_MAX ((s32)(U32_MAX >> 1))
|
||||
#define S32_MIN ((s32)(-S32_MAX - 1))
|
||||
#define U64_MAX ((u64)~0ULL)
|
||||
#define S64_MAX ((s64)(U64_MAX >> 1))
|
||||
#define S64_MIN ((s64)(-S64_MAX - 1))
|
||||
|
||||
#endif /* _LINUX_LIMITS_H */
|
||||
443
include/linux/overflow.h
Normal file
443
include/linux/overflow.h
Normal file
@@ -0,0 +1,443 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||
#ifndef __LINUX_OVERFLOW_H
|
||||
#define __LINUX_OVERFLOW_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/const.h>
|
||||
|
||||
/*
|
||||
* We need to compute the minimum and maximum values representable in a given
|
||||
* type. These macros may also be useful elsewhere. It would seem more obvious
|
||||
* to do something like:
|
||||
*
|
||||
* #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0)
|
||||
* #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0)
|
||||
*
|
||||
* Unfortunately, the middle expressions, strictly speaking, have
|
||||
* undefined behaviour, and at least some versions of gcc warn about
|
||||
* the type_max expression (but not if -fsanitize=undefined is in
|
||||
* effect; in that case, the warning is deferred to runtime...).
|
||||
*
|
||||
* The slightly excessive casting in type_min is to make sure the
|
||||
* macros also produce sensible values for the exotic type _Bool. [The
|
||||
* overflow checkers only almost work for _Bool, but that's
|
||||
* a-feature-not-a-bug, since people shouldn't be doing arithmetic on
|
||||
* _Bools. Besides, the gcc builtins don't allow _Bool* as third
|
||||
* argument.]
|
||||
*
|
||||
* Idea stolen from
|
||||
* https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html -
|
||||
* credit to Christian Biere.
|
||||
*/
|
||||
#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
|
||||
#define __type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
|
||||
#define type_max(t) __type_max(typeof(t))
|
||||
#define __type_min(T) ((T)((T)-type_max(T)-(T)1))
|
||||
#define type_min(t) __type_min(typeof(t))
|
||||
|
||||
/*
|
||||
* Avoids triggering -Wtype-limits compilation warning,
|
||||
* while using unsigned data types to check a < 0.
|
||||
*/
|
||||
#define is_non_negative(a) ((a) > 0 || (a) == 0)
|
||||
#define is_negative(a) (!(is_non_negative(a)))
|
||||
|
||||
/*
|
||||
* Allows for effectively applying __must_check to a macro so we can have
|
||||
* both the type-agnostic benefits of the macros while also being able to
|
||||
* enforce that the return value is, in fact, checked.
|
||||
*/
|
||||
static inline bool __must_check __must_check_overflow(bool overflow)
|
||||
{
|
||||
return unlikely(overflow);
|
||||
}
|
||||
|
||||
/**
|
||||
* check_add_overflow() - Calculate addition with overflow checking
|
||||
* @a: first addend
|
||||
* @b: second addend
|
||||
* @d: pointer to store sum
|
||||
*
|
||||
* Returns true on wrap-around, false otherwise.
|
||||
*
|
||||
* *@d holds the results of the attempted addition, regardless of whether
|
||||
* wrap-around occurred.
|
||||
*/
|
||||
#define check_add_overflow(a, b, d) \
|
||||
__must_check_overflow(__builtin_add_overflow(a, b, d))
|
||||
|
||||
/**
|
||||
* wrapping_add() - Intentionally perform a wrapping addition
|
||||
* @type: type for result of calculation
|
||||
* @a: first addend
|
||||
* @b: second addend
|
||||
*
|
||||
* Return the potentially wrapped-around addition without
|
||||
* tripping any wrap-around sanitizers that may be enabled.
|
||||
*/
|
||||
#define wrapping_add(type, a, b) \
|
||||
({ \
|
||||
type __val; \
|
||||
__builtin_add_overflow(a, b, &__val); \
|
||||
__val; \
|
||||
})
|
||||
|
||||
/**
|
||||
* wrapping_assign_add() - Intentionally perform a wrapping increment assignment
|
||||
* @var: variable to be incremented
|
||||
* @offset: amount to add
|
||||
*
|
||||
* Increments @var by @offset with wrap-around. Returns the resulting
|
||||
* value of @var. Will not trip any wrap-around sanitizers.
|
||||
*
|
||||
* Returns the new value of @var.
|
||||
*/
|
||||
#define wrapping_assign_add(var, offset) \
|
||||
({ \
|
||||
typeof(var) *__ptr = &(var); \
|
||||
*__ptr = wrapping_add(typeof(var), *__ptr, offset); \
|
||||
})
|
||||
|
||||
/**
|
||||
* check_sub_overflow() - Calculate subtraction with overflow checking
|
||||
* @a: minuend; value to subtract from
|
||||
* @b: subtrahend; value to subtract from @a
|
||||
* @d: pointer to store difference
|
||||
*
|
||||
* Returns true on wrap-around, false otherwise.
|
||||
*
|
||||
* *@d holds the results of the attempted subtraction, regardless of whether
|
||||
* wrap-around occurred.
|
||||
*/
|
||||
#define check_sub_overflow(a, b, d) \
|
||||
__must_check_overflow(__builtin_sub_overflow(a, b, d))
|
||||
|
||||
/**
|
||||
* wrapping_sub() - Intentionally perform a wrapping subtraction
|
||||
* @type: type for result of calculation
|
||||
* @a: minuend; value to subtract from
|
||||
* @b: subtrahend; value to subtract from @a
|
||||
*
|
||||
* Return the potentially wrapped-around subtraction without
|
||||
* tripping any wrap-around sanitizers that may be enabled.
|
||||
*/
|
||||
#define wrapping_sub(type, a, b) \
|
||||
({ \
|
||||
type __val; \
|
||||
__builtin_sub_overflow(a, b, &__val); \
|
||||
__val; \
|
||||
})
|
||||
|
||||
/**
|
||||
* wrapping_assign_sub() - Intentionally perform a wrapping decrement assign
|
||||
* @var: variable to be decremented
|
||||
* @offset: amount to subtract
|
||||
*
|
||||
* Decrements @var by @offset with wrap-around. Returns the resulting
|
||||
* value of @var. Will not trip any wrap-around sanitizers.
|
||||
*
|
||||
* Returns the new value of @var.
|
||||
*/
|
||||
#define wrapping_assign_sub(var, offset) \
|
||||
({ \
|
||||
typeof(var) *__ptr = &(var); \
|
||||
*__ptr = wrapping_sub(typeof(var), *__ptr, offset); \
|
||||
})
|
||||
|
||||
/**
|
||||
* check_mul_overflow() - Calculate multiplication with overflow checking
|
||||
* @a: first factor
|
||||
* @b: second factor
|
||||
* @d: pointer to store product
|
||||
*
|
||||
* Returns true on wrap-around, false otherwise.
|
||||
*
|
||||
* *@d holds the results of the attempted multiplication, regardless of whether
|
||||
* wrap-around occurred.
|
||||
*/
|
||||
#define check_mul_overflow(a, b, d) \
|
||||
__must_check_overflow(__builtin_mul_overflow(a, b, d))
|
||||
|
||||
/**
|
||||
* wrapping_mul() - Intentionally perform a wrapping multiplication
|
||||
* @type: type for result of calculation
|
||||
* @a: first factor
|
||||
* @b: second factor
|
||||
*
|
||||
* Return the potentially wrapped-around multiplication without
|
||||
* tripping any wrap-around sanitizers that may be enabled.
|
||||
*/
|
||||
#define wrapping_mul(type, a, b) \
|
||||
({ \
|
||||
type __val; \
|
||||
__builtin_mul_overflow(a, b, &__val); \
|
||||
__val; \
|
||||
})
|
||||
|
||||
/**
|
||||
* check_shl_overflow() - Calculate a left-shifted value and check overflow
|
||||
* @a: Value to be shifted
|
||||
* @s: How many bits left to shift
|
||||
* @d: Pointer to where to store the result
|
||||
*
|
||||
* Computes *@d = (@a << @s)
|
||||
*
|
||||
* Returns true if '*@d' cannot hold the result or when '@a << @s' doesn't
|
||||
* make sense. Example conditions:
|
||||
*
|
||||
* - '@a << @s' causes bits to be lost when stored in *@d.
|
||||
* - '@s' is garbage (e.g. negative) or so large that the result of
|
||||
* '@a << @s' is guaranteed to be 0.
|
||||
* - '@a' is negative.
|
||||
* - '@a << @s' sets the sign bit, if any, in '*@d'.
|
||||
*
|
||||
* '*@d' will hold the results of the attempted shift, but is not
|
||||
* considered "safe for use" if true is returned.
|
||||
*/
|
||||
#define check_shl_overflow(a, s, d) __must_check_overflow(({ \
|
||||
typeof(a) _a = a; \
|
||||
typeof(s) _s = s; \
|
||||
typeof(d) _d = d; \
|
||||
unsigned long long _a_full = _a; \
|
||||
unsigned int _to_shift = \
|
||||
is_non_negative(_s) && _s < 8 * sizeof(*d) ? _s : 0; \
|
||||
*_d = (_a_full << _to_shift); \
|
||||
(_to_shift != _s || is_negative(*_d) || is_negative(_a) || \
|
||||
(*_d >> _to_shift) != _a); \
|
||||
}))
|
||||
|
||||
#define __overflows_type_constexpr(x, T) ( \
|
||||
is_unsigned_type(typeof(x)) ? \
|
||||
(x) > type_max(T) : \
|
||||
is_unsigned_type(typeof(T)) ? \
|
||||
(x) < 0 || (x) > type_max(T) : \
|
||||
(x) < type_min(T) || (x) > type_max(T))
|
||||
|
||||
#define __overflows_type(x, T) ({ \
|
||||
typeof(T) v = 0; \
|
||||
check_add_overflow((x), v, &v); \
|
||||
})
|
||||
|
||||
/**
|
||||
* overflows_type - helper for checking the overflows between value, variables,
|
||||
* or data type
|
||||
*
|
||||
* @n: source constant value or variable to be checked
|
||||
* @T: destination variable or data type proposed to store @x
|
||||
*
|
||||
* Compares the @x expression for whether or not it can safely fit in
|
||||
* the storage of the type in @T. @x and @T can have different types.
|
||||
* If @x is a constant expression, this will also resolve to a constant
|
||||
* expression.
|
||||
*
|
||||
* Returns: true if overflow can occur, false otherwise.
|
||||
*/
|
||||
#define overflows_type(n, T) \
|
||||
__builtin_choose_expr(__is_constexpr(n), \
|
||||
__overflows_type_constexpr(n, T), \
|
||||
__overflows_type(n, T))
|
||||
|
||||
/**
|
||||
* castable_to_type - like __same_type(), but also allows for casted literals
|
||||
*
|
||||
* @n: variable or constant value
|
||||
* @T: variable or data type
|
||||
*
|
||||
* Unlike the __same_type() macro, this allows a constant value as the
|
||||
* first argument. If this value would not overflow into an assignment
|
||||
* of the second argument's type, it returns true. Otherwise, this falls
|
||||
* back to __same_type().
|
||||
*/
|
||||
#define castable_to_type(n, T) \
|
||||
__builtin_choose_expr(__is_constexpr(n), \
|
||||
!__overflows_type_constexpr(n, T), \
|
||||
__same_type(n, T))
|
||||
|
||||
/**
|
||||
* size_mul() - Calculate size_t multiplication with saturation at SIZE_MAX
|
||||
* @factor1: first factor
|
||||
* @factor2: second factor
|
||||
*
|
||||
* Returns: calculate @factor1 * @factor2, both promoted to size_t,
|
||||
* with any overflow causing the return value to be SIZE_MAX. The
|
||||
* lvalue must be size_t to avoid implicit type conversion.
|
||||
*/
|
||||
static inline size_t __must_check size_mul(size_t factor1, size_t factor2)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (check_mul_overflow(factor1, factor2, &bytes))
|
||||
return SIZE_MAX;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* size_add() - Calculate size_t addition with saturation at SIZE_MAX
|
||||
* @addend1: first addend
|
||||
* @addend2: second addend
|
||||
*
|
||||
* Returns: calculate @addend1 + @addend2, both promoted to size_t,
|
||||
* with any overflow causing the return value to be SIZE_MAX. The
|
||||
* lvalue must be size_t to avoid implicit type conversion.
|
||||
*/
|
||||
static inline size_t __must_check size_add(size_t addend1, size_t addend2)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (check_add_overflow(addend1, addend2, &bytes))
|
||||
return SIZE_MAX;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* size_sub() - Calculate size_t subtraction with saturation at SIZE_MAX
|
||||
* @minuend: value to subtract from
|
||||
* @subtrahend: value to subtract from @minuend
|
||||
*
|
||||
* Returns: calculate @minuend - @subtrahend, both promoted to size_t,
|
||||
* with any overflow causing the return value to be SIZE_MAX. For
|
||||
* composition with the size_add() and size_mul() helpers, neither
|
||||
* argument may be SIZE_MAX (or the result with be forced to SIZE_MAX).
|
||||
* The lvalue must be size_t to avoid implicit type conversion.
|
||||
*/
|
||||
static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (minuend == SIZE_MAX || subtrahend == SIZE_MAX ||
|
||||
check_sub_overflow(minuend, subtrahend, &bytes))
|
||||
return SIZE_MAX;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* array_size() - Calculate size of 2-dimensional array.
|
||||
* @a: dimension one
|
||||
* @b: dimension two
|
||||
*
|
||||
* Calculates size of 2-dimensional array: @a * @b.
|
||||
*
|
||||
* Returns: number of bytes needed to represent the array or SIZE_MAX on
|
||||
* overflow.
|
||||
*/
|
||||
#define array_size(a, b) size_mul(a, b)
|
||||
|
||||
/**
|
||||
* array3_size() - Calculate size of 3-dimensional array.
|
||||
* @a: dimension one
|
||||
* @b: dimension two
|
||||
* @c: dimension three
|
||||
*
|
||||
* Calculates size of 3-dimensional array: @a * @b * @c.
|
||||
*
|
||||
* Returns: number of bytes needed to represent the array or SIZE_MAX on
|
||||
* overflow.
|
||||
*/
|
||||
#define array3_size(a, b, c) size_mul(size_mul(a, b), c)
|
||||
|
||||
/**
|
||||
* flex_array_size() - Calculate size of a flexible array member
|
||||
* within an enclosing structure.
|
||||
* @p: Pointer to the structure.
|
||||
* @member: Name of the flexible array member.
|
||||
* @count: Number of elements in the array.
|
||||
*
|
||||
* Calculates size of a flexible array of @count number of @member
|
||||
* elements, at the end of structure @p.
|
||||
*
|
||||
* Return: number of bytes needed or SIZE_MAX on overflow.
|
||||
*/
|
||||
#define flex_array_size(p, member, count) \
|
||||
__builtin_choose_expr(__is_constexpr(count), \
|
||||
(count) * sizeof(*(p)->member) + __must_be_array((p)->member), \
|
||||
size_mul(count, sizeof(*(p)->member) + __must_be_array((p)->member)))
|
||||
|
||||
/**
|
||||
* struct_size() - Calculate size of structure with trailing flexible array.
|
||||
* @p: Pointer to the structure.
|
||||
* @member: Name of the array member.
|
||||
* @count: Number of elements in the array.
|
||||
*
|
||||
* Calculates size of memory needed for structure of @p followed by an
|
||||
* array of @count number of @member elements.
|
||||
*
|
||||
* Return: number of bytes needed or SIZE_MAX on overflow.
|
||||
*/
|
||||
#define struct_size(p, member, count) \
|
||||
__builtin_choose_expr(__is_constexpr(count), \
|
||||
sizeof(*(p)) + flex_array_size(p, member, count), \
|
||||
size_add(sizeof(*(p)), flex_array_size(p, member, count)))
|
||||
|
||||
/**
|
||||
* struct_size_t() - Calculate size of structure with trailing flexible array
|
||||
* @type: structure type name.
|
||||
* @member: Name of the array member.
|
||||
* @count: Number of elements in the array.
|
||||
*
|
||||
* Calculates size of memory needed for structure @type followed by an
|
||||
* array of @count number of @member elements. Prefer using struct_size()
|
||||
* when possible instead, to keep calculations associated with a specific
|
||||
* instance variable of type @type.
|
||||
*
|
||||
* Return: number of bytes needed or SIZE_MAX on overflow.
|
||||
*/
|
||||
#define struct_size_t(type, member, count) \
|
||||
struct_size((type *)NULL, member, count)
|
||||
|
||||
/**
|
||||
* _DEFINE_FLEX() - helper macro for DEFINE_FLEX() family.
|
||||
* Enables caller macro to pass (different) initializer.
|
||||
*
|
||||
* @type: structure type name, including "struct" keyword.
|
||||
* @name: Name for a variable to define.
|
||||
* @member: Name of the array member.
|
||||
* @count: Number of elements in the array; must be compile-time const.
|
||||
* @initializer: initializer expression (could be empty for no init).
|
||||
*/
|
||||
#define _DEFINE_FLEX(type, name, member, count, initializer...) \
|
||||
_Static_assert(__builtin_constant_p(count), \
|
||||
"onstack flex array members require compile-time const count"); \
|
||||
union { \
|
||||
u8 bytes[struct_size_t(type, member, count)]; \
|
||||
type obj; \
|
||||
} name##_u initializer; \
|
||||
type *name = (type *)&name##_u
|
||||
|
||||
/**
|
||||
* DEFINE_RAW_FLEX() - Define an on-stack instance of structure with a trailing
|
||||
* flexible array member, when it does not have a __counted_by annotation.
|
||||
*
|
||||
* @type: structure type name, including "struct" keyword.
|
||||
* @name: Name for a variable to define.
|
||||
* @member: Name of the array member.
|
||||
* @count: Number of elements in the array; must be compile-time const.
|
||||
*
|
||||
* Define a zeroed, on-stack, instance of @type structure with a trailing
|
||||
* flexible array member.
|
||||
* Use __struct_size(@name) to get compile-time size of it afterwards.
|
||||
*/
|
||||
#define DEFINE_RAW_FLEX(type, name, member, count) \
|
||||
_DEFINE_FLEX(type, name, member, count, = {})
|
||||
|
||||
/**
|
||||
* DEFINE_FLEX() - Define an on-stack instance of structure with a trailing
|
||||
* flexible array member.
|
||||
*
|
||||
* @TYPE: structure type name, including "struct" keyword.
|
||||
* @NAME: Name for a variable to define.
|
||||
* @MEMBER: Name of the array member.
|
||||
* @COUNTER: Name of the __counted_by member.
|
||||
* @COUNT: Number of elements in the array; must be compile-time const.
|
||||
*
|
||||
* Define a zeroed, on-stack, instance of @TYPE structure with a trailing
|
||||
* flexible array member.
|
||||
* Use __struct_size(@NAME) to get compile-time size of it afterwards.
|
||||
*/
|
||||
#define DEFINE_FLEX(TYPE, NAME, MEMBER, COUNTER, COUNT) \
|
||||
_DEFINE_FLEX(TYPE, NAME, MEMBER, COUNT, = { .obj.COUNTER = COUNT, })
|
||||
|
||||
#endif /* __LINUX_OVERFLOW_H */
|
||||
Reference in New Issue
Block a user