blob: 4357acaef6c4315b46c7a1bbe8fea0609ae61994 [file] [log] [blame]
Dzmitry Sankouskia3463062022-02-22 21:49:52 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * save_prev_bl_data - saving previous bootloader data
4 * to environment variables.
5 *
6 * Copyright (c) 2022 Dzmitry Sankouski (dsankouski@gmail.com)
7 */
8#include <init.h>
9#include <env.h>
10#include <fdtdec.h>
11#include <fdt_support.h>
12#include <fdt.h>
Dzmitry Sankouskia3463062022-02-22 21:49:52 +030013#include <linux/errno.h>
14#include <asm/system.h>
15#include <asm/armv8/mmu.h>
16
17static ulong reg0 __section(".data");
18
19/**
20 * Save x0 register value, assuming previous bootloader set it to
21 * point on loaded fdt or (for older linux kernels)atags.
22 */
23void save_boot_params(ulong r0)
24{
25 reg0 = r0;
26 save_boot_params_ret();
27}
28
29bool is_addr_accessible(phys_addr_t addr)
30{
31 struct mm_region *mem = mem_map;
32 phys_addr_t bank_start;
33 phys_addr_t bank_end;
34
35 while (mem->size) {
36 bank_start = mem->phys;
37 bank_end = bank_start + mem->size;
38 debug("check if block %pap - %pap includes %pap\n", &bank_start, &bank_end, &addr);
39 if (addr > bank_start && addr < bank_end)
40 return true;
41 mem++;
42 }
43
44 return false;
45}
46
Caleb Connolly5a9a5d32024-02-26 17:26:05 +000047phys_addr_t get_prev_bl_fdt_addr(void)
48{
49 return reg0;
50}
51
Dzmitry Sankouskia3463062022-02-22 21:49:52 +030052int save_prev_bl_data(void)
53{
54 struct fdt_header *fdt_blob;
55 int node;
56 u64 initrd_start_prop;
57
58 if (!is_addr_accessible((phys_addr_t)reg0))
59 return -ENODATA;
60
61 fdt_blob = (struct fdt_header *)reg0;
62 if (!fdt_valid(&fdt_blob)) {
63 pr_warn("%s: address 0x%lx is not a valid fdt\n", __func__, reg0);
64 return -ENODATA;
65 }
66
Simon Glass9e0417e2023-02-05 15:40:44 -070067 if (IS_ENABLED(CONFIG_SAVE_PREV_BL_FDT_ADDR))
Dzmitry Sankouskia3463062022-02-22 21:49:52 +030068 env_set_addr("prevbl_fdt_addr", (void *)reg0);
Simon Glassc19fee52023-02-05 17:55:03 -070069 if (!IS_ENABLED(CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR))
Dzmitry Sankouskia3463062022-02-22 21:49:52 +030070 return 0;
71
72 node = fdt_path_offset(fdt_blob, "/chosen");
73 if (!node) {
74 pr_warn("%s: chosen node not found in device tree at addr: 0x%lx\n",
75 __func__, reg0);
76 return -ENODATA;
77 }
78 /*
79 * linux,initrd-start property might be either 64 or 32 bit,
80 * depending on primary bootloader implementation.
81 */
82 initrd_start_prop = fdtdec_get_uint64(fdt_blob, node, "linux,initrd-start", 0);
83 if (!initrd_start_prop) {
84 debug("%s: attempt to get uint64 linux,initrd-start property failed, trying uint\n",
85 __func__);
86 initrd_start_prop = fdtdec_get_uint(fdt_blob, node, "linux,initrd-start", 0);
87 if (!initrd_start_prop) {
88 debug("%s: attempt to get uint failed, too\n", __func__);
89 return -ENODATA;
90 }
91 }
92 env_set_addr("prevbl_initrd_start_addr", (void *)initrd_start_prop);
93
94 return 0;
95}