"Jiaxun Yang" <jiaxun.yang@xxxxxxxxxxx> writes: > 在2024年8月24日八月 下午3:41,Bjørn Mork写道: >> Boards based on the same SoC family can use different boot loaders. >> These may pass numeric arguments which we erroneously interpret as >> command line or environment pointers. Such errors will cause boot >> to halt at an early stage since commit 056a68cea01e ("mips: allow >> firmware to pass RNG seed to kernel"). >> >> One known example of this issue is a HPE switch using a BootWare >> boot loader. It was found to pass these arguments to the kernel: >> >> 0x00020000 0x00060000 0xfffdffff 0x0000416c >> >> We can avoid hanging by validating that both passed pointers are in >> KSEG1 as expected. > > Hi Bjorn, > > This is actually breaking 64 bit systems passing fw_args in XKPHYS or KSEG0. Ouch. Thanks for the feedback. But if so, then aren't those already broken with the current test against CKSEG0? I didn't add that. IIUC, CKSEGx is the sign extendend version of KSEGx on 64BIT: #ifdef CONFIG_64BIT /* * Memory segments (64bit kernel mode addresses) * The compatibility segments use the full 64-bit sign extended value. Note * the R8000 doesn't have them so don't reference these in generic MIPS code. */ #define XKUSEG _CONST64_(0x0000000000000000) #define XKSSEG _CONST64_(0x4000000000000000) #define XKPHYS _CONST64_(0x8000000000000000) #define XKSEG _CONST64_(0xc000000000000000) #define CKSEG0 _CONST64_(0xffffffff80000000) #define CKSEG1 _CONST64_(0xffffffffa0000000) #define CKSSEG _CONST64_(0xffffffffc0000000) #define CKSEG3 _CONST64_(0xffffffffe0000000) #define CKSEG0ADDR(a) (CPHYSADDR(a) | CKSEG0) #define CKSEG1ADDR(a) (CPHYSADDR(a) | CKSEG1) #define CKSEG2ADDR(a) (CPHYSADDR(a) | CKSEG2) #define CKSEG3ADDR(a) (CPHYSADDR(a) | CKSEG3) > Maybe something like: > > static inline bool valid_fw_arg(unsigned long arg) > { > #ifdef CONFIG_64BIT > if (arg >= XKPHYS && arg < XKSEG) > return TRUE; > #endif > return arg >= CKSEG0 && arg < CKSSEG; > } > > Will be more robust. Maybe? But I can't make that match what U-Boot does. AFAICS, u-boot/arch/mips/lib/bootm.c doesn't care about 32 or 64 bit, and simply does: static void linux_cmdline_init(void) { linux_argc = 1; linux_argv = (char **)CKSEG1ADDR(gd->bd->bi_boot_params); linux_argv[0] = 0; linux_argp = (char *)(linux_argv + LINUX_MAX_ARGS); } Then it derives the argument and environment pointers from linux_argv. Which means that all these pointers end up somewhere between CKSEG1 and CKSEG2 on both 32 and 64 bit. Or am I missing something? Tried looking for other MIPS code in U-Boot handling this for 64 bit, but all I found was arch/mips/mach-octeon/bootoctlinux.c which uses a completely different protocol. Sorry if I am asking stupid questions here. Trying a rather steep learning curve. Maybe too steep :-) Bjørn