lib: sbi: Fix how to check whether the domain contains fw_region
[platform/kernel/opensbi.git] / lib / sbi / sbi_domain.c
1 /*
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
5  *
6  * Authors:
7  *   Anup Patel <anup.patel@wdc.com>
8  */
9
10 #include <sbi/riscv_asm.h>
11 #include <sbi/sbi_console.h>
12 #include <sbi/sbi_domain.h>
13 #include <sbi/sbi_hartmask.h>
14 #include <sbi/sbi_hsm.h>
15 #include <sbi/sbi_math.h>
16 #include <sbi/sbi_platform.h>
17 #include <sbi/sbi_scratch.h>
18 #include <sbi/sbi_string.h>
19
20 /*
21  * We allocate an extra element because sbi_domain_for_each() expects
22  * the array to be null-terminated.
23  */
24 struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX + 1] = { 0 };
25 struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
26 static u32 domain_count = 0;
27 static bool domain_finalized = false;
28
29 static struct sbi_hartmask root_hmask = { 0 };
30
31 #define ROOT_REGION_MAX 16
32 static u32 root_memregs_count = 0;
33 static struct sbi_domain_memregion root_memregs[ROOT_REGION_MAX + 1] = { 0 };
34
35 struct sbi_domain root = {
36         .name = "root",
37         .possible_harts = &root_hmask,
38         .regions = root_memregs,
39         .system_reset_allowed = true,
40         .system_suspend_allowed = true,
41         .fw_region_inited = false,
42 };
43
44 bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
45 {
46         if (dom)
47                 return sbi_hartmask_test_hart(hartid, &dom->assigned_harts);
48
49         return false;
50 }
51
52 ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
53                                        ulong hbase)
54 {
55         ulong ret, bword, boff;
56
57         if (!dom)
58                 return 0;
59
60         bword = BIT_WORD(hbase);
61         boff = BIT_WORD_OFFSET(hbase);
62
63         ret = sbi_hartmask_bits(&dom->assigned_harts)[bword++] >> boff;
64         if (boff && bword < BIT_WORD(SBI_HARTMASK_MAX_BITS)) {
65                 ret |= (sbi_hartmask_bits(&dom->assigned_harts)[bword] &
66                         (BIT(boff) - 1UL)) << (BITS_PER_LONG - boff);
67         }
68
69         return ret;
70 }
71
72 void sbi_domain_memregion_init(unsigned long addr,
73                                 unsigned long size,
74                                 unsigned long flags,
75                                 struct sbi_domain_memregion *reg)
76 {
77         unsigned long base = 0, order;
78
79         for (order = log2roundup(size) ; order <= __riscv_xlen; order++) {
80                 if (order < __riscv_xlen) {
81                         base = addr & ~((1UL << order) - 1UL);
82                         if ((base <= addr) &&
83                             (addr < (base + (1UL << order))) &&
84                             (base <= (addr + size - 1UL)) &&
85                             ((addr + size - 1UL) < (base + (1UL << order))))
86                                 break;
87                 } else {
88                         base = 0;
89                         break;
90                 }
91
92         }
93
94         if (reg) {
95                 reg->base = base;
96                 reg->order = order;
97                 reg->flags = flags;
98         }
99 }
100
101 bool sbi_domain_check_addr(const struct sbi_domain *dom,
102                            unsigned long addr, unsigned long mode,
103                            unsigned long access_flags)
104 {
105         bool rmmio, mmio = false;
106         struct sbi_domain_memregion *reg;
107         unsigned long rstart, rend, rflags, rwx = 0, rrwx = 0;
108
109         if (!dom)
110                 return false;
111
112         /*
113          * Use M_{R/W/X} bits because the SU-bits are at the
114          * same relative offsets. If the mode is not M, the SU
115          * bits will fall at same offsets after the shift.
116          */
117         if (access_flags & SBI_DOMAIN_READ)
118                 rwx |= SBI_DOMAIN_MEMREGION_M_READABLE;
119
120         if (access_flags & SBI_DOMAIN_WRITE)
121                 rwx |= SBI_DOMAIN_MEMREGION_M_WRITABLE;
122
123         if (access_flags & SBI_DOMAIN_EXECUTE)
124                 rwx |= SBI_DOMAIN_MEMREGION_M_EXECUTABLE;
125
126         if (access_flags & SBI_DOMAIN_MMIO)
127                 mmio = true;
128
129         sbi_domain_for_each_memregion(dom, reg) {
130                 rflags = reg->flags;
131                 rrwx = (mode == PRV_M ?
132                         (rflags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) :
133                         (rflags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK)
134                         >> SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT);
135
136                 rstart = reg->base;
137                 rend = (reg->order < __riscv_xlen) ?
138                         rstart + ((1UL << reg->order) - 1) : -1UL;
139                 if (rstart <= addr && addr <= rend) {
140                         rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? true : false;
141                         if (mmio != rmmio)
142                                 return false;
143                         return ((rrwx & rwx) == rwx) ? true : false;
144                 }
145         }
146
147         return (mode == PRV_M) ? true : false;
148 }
149
150 /* Check if region complies with constraints */
151 static bool is_region_valid(const struct sbi_domain_memregion *reg)
152 {
153         if (reg->order < 3 || __riscv_xlen < reg->order)
154                 return false;
155
156         if (reg->order == __riscv_xlen && reg->base != 0)
157                 return false;
158
159         if (reg->order < __riscv_xlen && (reg->base & (BIT(reg->order) - 1)))
160                 return false;
161
162         return true;
163 }
164
165 /** Check if regionA is sub-region of regionB */
166 static bool is_region_subset(const struct sbi_domain_memregion *regA,
167                              const struct sbi_domain_memregion *regB)
168 {
169         ulong regA_start = regA->base;
170         ulong regA_end = regA->base + (BIT(regA->order) - 1);
171         ulong regB_start = regB->base;
172         ulong regB_end = regB->base + (BIT(regB->order) - 1);
173
174         if ((regB_start <= regA_start) &&
175             (regA_start < regB_end) &&
176             (regB_start < regA_end) &&
177             (regA_end <= regB_end))
178                 return true;
179
180         return false;
181 }
182
183 /** Check if regionA conflicts regionB */
184 static bool is_region_conflict(const struct sbi_domain_memregion *regA,
185                                 const struct sbi_domain_memregion *regB)
186 {
187         if ((is_region_subset(regA, regB) || is_region_subset(regB, regA)) &&
188             regA->flags == regB->flags)
189                 return true;
190
191         return false;
192 }
193
194 /** Check if regionA should be placed before regionB */
195 static bool is_region_before(const struct sbi_domain_memregion *regA,
196                              const struct sbi_domain_memregion *regB)
197 {
198         if (regA->order < regB->order)
199                 return true;
200
201         if ((regA->order == regB->order) &&
202             (regA->base < regB->base))
203                 return true;
204
205         return false;
206 }
207
208 static const struct sbi_domain_memregion *find_region(
209                                                 const struct sbi_domain *dom,
210                                                 unsigned long addr)
211 {
212         unsigned long rstart, rend;
213         struct sbi_domain_memregion *reg;
214
215         sbi_domain_for_each_memregion(dom, reg) {
216                 rstart = reg->base;
217                 rend = (reg->order < __riscv_xlen) ?
218                         rstart + ((1UL << reg->order) - 1) : -1UL;
219                 if (rstart <= addr && addr <= rend)
220                         return reg;
221         }
222
223         return NULL;
224 }
225
226 static const struct sbi_domain_memregion *find_next_subset_region(
227                                 const struct sbi_domain *dom,
228                                 const struct sbi_domain_memregion *reg,
229                                 unsigned long addr)
230 {
231         struct sbi_domain_memregion *sreg, *ret = NULL;
232
233         sbi_domain_for_each_memregion(dom, sreg) {
234                 if (sreg == reg || (sreg->base <= addr) ||
235                     !is_region_subset(sreg, reg))
236                         continue;
237
238                 if (!ret || (sreg->base < ret->base) ||
239                     ((sreg->base == ret->base) && (sreg->order < ret->order)))
240                         ret = sreg;
241         }
242
243         return ret;
244 }
245
246 static int sanitize_domain(const struct sbi_platform *plat,
247                            struct sbi_domain *dom)
248 {
249         u32 i, j, count;
250         struct sbi_domain_memregion treg, *reg, *reg1;
251
252         /* Check possible HARTs */
253         if (!dom->possible_harts) {
254                 sbi_printf("%s: %s possible HART mask is NULL\n",
255                            __func__, dom->name);
256                 return SBI_EINVAL;
257         }
258         sbi_hartmask_for_each_hart(i, dom->possible_harts) {
259                 if (sbi_platform_hart_invalid(plat, i)) {
260                         sbi_printf("%s: %s possible HART mask has invalid "
261                                    "hart %d\n", __func__, dom->name, i);
262                         return SBI_EINVAL;
263                 }
264         };
265
266         /* Check memory regions */
267         if (!dom->regions) {
268                 sbi_printf("%s: %s regions is NULL\n",
269                            __func__, dom->name);
270                 return SBI_EINVAL;
271         }
272         sbi_domain_for_each_memregion(dom, reg) {
273                 if (!is_region_valid(reg)) {
274                         sbi_printf("%s: %s has invalid region base=0x%lx "
275                                    "order=%lu flags=0x%lx\n", __func__,
276                                    dom->name, reg->base, reg->order,
277                                    reg->flags);
278                         return SBI_EINVAL;
279                 }
280         }
281
282         /* Count memory regions */
283         count = 0;
284         sbi_domain_for_each_memregion(dom, reg)
285                 count++;
286
287         /* Check presence of firmware regions */
288         if (!dom->fw_region_inited) {
289                 sbi_printf("%s: %s does not have firmware region\n",
290                            __func__, dom->name);
291                 return SBI_EINVAL;
292         }
293
294         /* Sort the memory regions */
295         for (i = 0; i < (count - 1); i++) {
296                 reg = &dom->regions[i];
297                 for (j = i + 1; j < count; j++) {
298                         reg1 = &dom->regions[j];
299
300                         if (is_region_conflict(reg1, reg)) {
301                                 sbi_printf("%s: %s conflict between regions "
302                                         "(base=0x%lx order=%lu flags=0x%lx) and "
303                                         "(base=0x%lx order=%lu flags=0x%lx)\n",
304                                         __func__, dom->name,
305                                         reg->base, reg->order, reg->flags,
306                                         reg1->base, reg1->order, reg1->flags);
307                                 return SBI_EINVAL;
308                         }
309
310                         if (!is_region_before(reg1, reg))
311                                 continue;
312
313                         sbi_memcpy(&treg, reg1, sizeof(treg));
314                         sbi_memcpy(reg1, reg, sizeof(treg));
315                         sbi_memcpy(reg, &treg, sizeof(treg));
316                 }
317         }
318
319         /*
320          * We don't need to check boot HART id of domain because if boot
321          * HART id is not possible/assigned to this domain then it won't
322          * be started at boot-time by sbi_domain_finalize().
323          */
324
325         /*
326          * Check next mode
327          *
328          * We only allow next mode to be S-mode or U-mode, so that we can
329          * protect M-mode context and enforce checks on memory accesses.
330          */
331         if (dom->next_mode != PRV_S &&
332             dom->next_mode != PRV_U) {
333                 sbi_printf("%s: %s invalid next booting stage mode 0x%lx\n",
334                            __func__, dom->name, dom->next_mode);
335                 return SBI_EINVAL;
336         }
337
338         /* Check next address and next mode */
339         if (!sbi_domain_check_addr(dom, dom->next_addr, dom->next_mode,
340                                    SBI_DOMAIN_EXECUTE)) {
341                 sbi_printf("%s: %s next booting stage address 0x%lx can't "
342                            "execute\n", __func__, dom->name, dom->next_addr);
343                 return SBI_EINVAL;
344         }
345
346         return 0;
347 }
348
349 bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
350                                  unsigned long addr, unsigned long size,
351                                  unsigned long mode,
352                                  unsigned long access_flags)
353 {
354         unsigned long max = addr + size;
355         const struct sbi_domain_memregion *reg, *sreg;
356
357         if (!dom)
358                 return false;
359
360         while (addr < max) {
361                 reg = find_region(dom, addr);
362                 if (!reg)
363                         return false;
364
365                 if (!sbi_domain_check_addr(dom, addr, mode, access_flags))
366                         return false;
367
368                 sreg = find_next_subset_region(dom, reg, addr);
369                 if (sreg)
370                         addr = sreg->base;
371                 else if (reg->order < __riscv_xlen)
372                         addr = reg->base + (1UL << reg->order);
373                 else
374                         break;
375         }
376
377         return true;
378 }
379
380 void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
381 {
382         u32 i, k;
383         unsigned long rstart, rend;
384         struct sbi_domain_memregion *reg;
385
386         sbi_printf("Domain%d Name        %s: %s\n",
387                    dom->index, suffix, dom->name);
388
389         sbi_printf("Domain%d Boot HART   %s: %d\n",
390                    dom->index, suffix, dom->boot_hartid);
391
392         k = 0;
393         sbi_printf("Domain%d HARTs       %s: ", dom->index, suffix);
394         sbi_hartmask_for_each_hart(i, dom->possible_harts)
395                 sbi_printf("%s%d%s", (k++) ? "," : "",
396                            i, sbi_domain_is_assigned_hart(dom, i) ? "*" : "");
397         sbi_printf("\n");
398
399         i = 0;
400         sbi_domain_for_each_memregion(dom, reg) {
401                 rstart = reg->base;
402                 rend = (reg->order < __riscv_xlen) ?
403                         rstart + ((1UL << reg->order) - 1) : -1UL;
404
405                 sbi_printf("Domain%d Region%02d    %s: 0x%" PRILX "-0x%" PRILX " ",
406                            dom->index, i, suffix, rstart, rend);
407
408                 k = 0;
409
410                 sbi_printf("M: ");
411                 if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
412                         sbi_printf("%cI", (k++) ? ',' : '(');
413                 if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
414                         sbi_printf("%cR", (k++) ? ',' : '(');
415                 if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
416                         sbi_printf("%cW", (k++) ? ',' : '(');
417                 if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
418                         sbi_printf("%cX", (k++) ? ',' : '(');
419                 sbi_printf("%s ", (k++) ? ")" : "()");
420
421                 k = 0;
422                 sbi_printf("S/U: ");
423                 if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
424                         sbi_printf("%cR", (k++) ? ',' : '(');
425                 if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
426                         sbi_printf("%cW", (k++) ? ',' : '(');
427                 if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
428                         sbi_printf("%cX", (k++) ? ',' : '(');
429                 sbi_printf("%s\n", (k++) ? ")" : "()");
430
431                 i++;
432         }
433
434         sbi_printf("Domain%d Next Address%s: 0x%" PRILX "\n",
435                    dom->index, suffix, dom->next_addr);
436
437         sbi_printf("Domain%d Next Arg1   %s: 0x%" PRILX "\n",
438                    dom->index, suffix, dom->next_arg1);
439
440         sbi_printf("Domain%d Next Mode   %s: ", dom->index, suffix);
441         switch (dom->next_mode) {
442         case PRV_M:
443                 sbi_printf("M-mode\n");
444                 break;
445         case PRV_S:
446                 sbi_printf("S-mode\n");
447                 break;
448         case PRV_U:
449                 sbi_printf("U-mode\n");
450                 break;
451         default:
452                 sbi_printf("Unknown\n");
453                 break;
454         };
455
456         sbi_printf("Domain%d SysReset    %s: %s\n",
457                    dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
458
459         sbi_printf("Domain%d SysSuspend  %s: %s\n",
460                    dom->index, suffix, (dom->system_suspend_allowed) ? "yes" : "no");
461 }
462
463 void sbi_domain_dump_all(const char *suffix)
464 {
465         u32 i;
466         const struct sbi_domain *dom;
467
468         sbi_domain_for_each(i, dom) {
469                 sbi_domain_dump(dom, suffix);
470                 sbi_printf("\n");
471         }
472 }
473
474 int sbi_domain_register(struct sbi_domain *dom,
475                         const struct sbi_hartmask *assign_mask)
476 {
477         u32 i;
478         int rc;
479         struct sbi_domain *tdom;
480         u32 cold_hartid = current_hartid();
481         const struct sbi_platform *plat = sbi_platform_thishart_ptr();
482
483         /* Sanity checks */
484         if (!dom || !assign_mask || domain_finalized)
485                 return SBI_EINVAL;
486
487         /* Check if domain already discovered */
488         sbi_domain_for_each(i, tdom) {
489                 if (tdom == dom)
490                         return SBI_EALREADY;
491         }
492
493         /*
494          * Ensure that we have room for Domain Index to
495          * HART ID mapping
496          */
497         if (SBI_DOMAIN_MAX_INDEX <= domain_count) {
498                 sbi_printf("%s: No room for %s\n",
499                            __func__, dom->name);
500                 return SBI_ENOSPC;
501         }
502
503         /* Sanitize discovered domain */
504         rc = sanitize_domain(plat, dom);
505         if (rc) {
506                 sbi_printf("%s: sanity checks failed for"
507                            " %s (error %d)\n", __func__,
508                            dom->name, rc);
509                 return rc;
510         }
511
512         /* Assign index to domain */
513         dom->index = domain_count++;
514         domidx_to_domain_table[dom->index] = dom;
515
516         /* Clear assigned HARTs of domain */
517         sbi_hartmask_clear_all(&dom->assigned_harts);
518
519         /* Assign domain to HART if HART is a possible HART */
520         sbi_hartmask_for_each_hart(i, assign_mask) {
521                 if (!sbi_hartmask_test_hart(i, dom->possible_harts))
522                         continue;
523
524                 tdom = hartid_to_domain_table[i];
525                 if (tdom)
526                         sbi_hartmask_clear_hart(i,
527                                         &tdom->assigned_harts);
528                 hartid_to_domain_table[i] = dom;
529                 sbi_hartmask_set_hart(i, &dom->assigned_harts);
530
531                 /*
532                  * If cold boot HART is assigned to this domain then
533                  * override boot HART of this domain.
534                  */
535                 if (i == cold_hartid &&
536                     dom->boot_hartid != cold_hartid) {
537                         sbi_printf("Domain%d Boot HARTID forced to"
538                                    " %d\n", dom->index, cold_hartid);
539                         dom->boot_hartid = cold_hartid;
540                 }
541         }
542
543         return 0;
544 }
545
546 int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
547 {
548         int rc;
549         bool reg_merged;
550         struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
551         const struct sbi_platform *plat = sbi_platform_thishart_ptr();
552
553         /* Sanity checks */
554         if (!reg || domain_finalized ||
555             (root.regions != root_memregs) ||
556             (ROOT_REGION_MAX <= root_memregs_count))
557                 return SBI_EINVAL;
558
559         /* Check for conflicts */
560         sbi_domain_for_each_memregion(&root, nreg) {
561                 if (is_region_conflict(reg, nreg)) {
562                         sbi_printf("%s: is_region_conflict check failed"
563                         " 0x%lx conflicts existing 0x%lx\n", __func__,
564                                    reg->base, nreg->base);
565                         return SBI_EALREADY;
566                 }
567         }
568
569         /* Append the memregion to root memregions */
570         nreg = &root_memregs[root_memregs_count];
571         sbi_memcpy(nreg, reg, sizeof(*reg));
572         root_memregs_count++;
573         root_memregs[root_memregs_count].order = 0;
574
575         /* Sort and optimize root regions */
576         do {
577                 /* Sanitize the root domain so that memregions are sorted */
578                 rc = sanitize_domain(plat, &root);
579                 if (rc) {
580                         sbi_printf("%s: sanity checks failed for"
581                                    " %s (error %d)\n", __func__,
582                                    root.name, rc);
583                         return rc;
584                 }
585
586                 /* Merge consecutive memregions with same order and flags */
587                 reg_merged = false;
588                 sbi_domain_for_each_memregion(&root, nreg) {
589                         nreg1 = nreg + 1;
590                         if (!nreg1->order)
591                                 continue;
592
593                         if (!(nreg->base & (BIT(nreg->order + 1) - 1)) &&
594                             (nreg->base + BIT(nreg->order)) == nreg1->base &&
595                             nreg->order == nreg1->order &&
596                             nreg->flags == nreg1->flags) {
597                                 nreg->order++;
598                                 while (nreg1->order) {
599                                         nreg2 = nreg1 + 1;
600                                         sbi_memcpy(nreg1, nreg2, sizeof(*nreg1));
601                                         nreg1++;
602                                 }
603                                 reg_merged = true;
604                                 root_memregs_count--;
605                         }
606                 }
607         } while (reg_merged);
608
609         return 0;
610 }
611
612 int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
613                            unsigned long align, unsigned long region_flags)
614 {
615         int rc;
616         unsigned long pos, end, rsize;
617         struct sbi_domain_memregion reg;
618
619         pos = addr;
620         end = addr + size;
621         while (pos < end) {
622                 rsize = pos & (align - 1);
623                 if (rsize)
624                         rsize = 1UL << sbi_ffs(pos);
625                 else
626                         rsize = ((end - pos) < align) ?
627                                 (end - pos) : align;
628
629                 sbi_domain_memregion_init(pos, rsize, region_flags, &reg);
630                 rc = sbi_domain_root_add_memregion(&reg);
631                 if (rc)
632                         return rc;
633                 pos += rsize;
634         }
635
636         return 0;
637 }
638
639 int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
640 {
641         int rc;
642         u32 i, dhart;
643         struct sbi_domain *dom;
644         const struct sbi_platform *plat = sbi_platform_ptr(scratch);
645
646         /* Initialize and populate domains for the platform */
647         rc = sbi_platform_domains_init(plat);
648         if (rc) {
649                 sbi_printf("%s: platform domains_init() failed (error %d)\n",
650                            __func__, rc);
651                 return rc;
652         }
653
654         /* Startup boot HART of domains */
655         sbi_domain_for_each(i, dom) {
656                 /* Domain boot HART */
657                 dhart = dom->boot_hartid;
658
659                 /* Ignore of boot HART is off limits */
660                 if (SBI_HARTMASK_MAX_BITS <= dhart)
661                         continue;
662
663                 /* Ignore if boot HART not possible for this domain */
664                 if (!sbi_hartmask_test_hart(dhart, dom->possible_harts))
665                         continue;
666
667                 /* Ignore if boot HART assigned different domain */
668                 if (sbi_hartid_to_domain(dhart) != dom ||
669                     !sbi_hartmask_test_hart(dhart, &dom->assigned_harts))
670                         continue;
671
672                 /* Startup boot HART of domain */
673                 if (dhart == cold_hartid) {
674                         scratch->next_addr = dom->next_addr;
675                         scratch->next_mode = dom->next_mode;
676                         scratch->next_arg1 = dom->next_arg1;
677                 } else {
678                         rc = sbi_hsm_hart_start(scratch, NULL, dhart,
679                                                 dom->next_addr,
680                                                 dom->next_mode,
681                                                 dom->next_arg1);
682                         if (rc) {
683                                 sbi_printf("%s: failed to start boot HART %d"
684                                            " for %s (error %d)\n", __func__,
685                                            dhart, dom->name, rc);
686                                 return rc;
687                         }
688                 }
689         }
690
691         /*
692          * Set the finalized flag so that the root domain
693          * regions can't be changed.
694          */
695         domain_finalized = true;
696
697         return 0;
698 }
699
700 int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
701 {
702         u32 i;
703         const struct sbi_platform *plat = sbi_platform_ptr(scratch);
704
705         if (scratch->fw_rw_offset == 0 ||
706             (scratch->fw_rw_offset & (scratch->fw_rw_offset - 1)) != 0) {
707                 sbi_printf("%s: fw_rw_offset is not a power of 2 (0x%lx)\n",
708                            __func__, scratch->fw_rw_offset);
709                 return SBI_EINVAL;
710         }
711
712         if ((scratch->fw_start & (scratch->fw_rw_offset - 1)) != 0) {
713                 sbi_printf("%s: fw_start and fw_rw_offset not aligned\n",
714                            __func__);
715                 return SBI_EINVAL;
716         }
717
718         /* Root domain firmware memory region */
719         sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
720                                   (SBI_DOMAIN_MEMREGION_M_READABLE |
721                                    SBI_DOMAIN_MEMREGION_M_EXECUTABLE),
722                                   &root_memregs[root_memregs_count++]);
723
724         sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
725                                   (scratch->fw_size - scratch->fw_rw_offset),
726                                   (SBI_DOMAIN_MEMREGION_M_READABLE |
727                                    SBI_DOMAIN_MEMREGION_M_WRITABLE),
728                                   &root_memregs[root_memregs_count++]);
729
730         root.fw_region_inited = true;
731
732         /* Root domain allow everything memory region */
733         sbi_domain_memregion_init(0, ~0UL,
734                                   (SBI_DOMAIN_MEMREGION_READABLE |
735                                    SBI_DOMAIN_MEMREGION_WRITEABLE |
736                                    SBI_DOMAIN_MEMREGION_EXECUTABLE),
737                                   &root_memregs[root_memregs_count++]);
738
739         /* Root domain memory region end */
740         root_memregs[root_memregs_count].order = 0;
741
742         /* Root domain boot HART id is same as coldboot HART id */
743         root.boot_hartid = cold_hartid;
744
745         /* Root domain next booting stage details */
746         root.next_arg1 = scratch->next_arg1;
747         root.next_addr = scratch->next_addr;
748         root.next_mode = scratch->next_mode;
749
750         /* Root domain possible and assigned HARTs */
751         for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
752                 if (sbi_platform_hart_invalid(plat, i))
753                         continue;
754                 sbi_hartmask_set_hart(i, &root_hmask);
755         }
756
757         return sbi_domain_register(&root, &root_hmask);
758 }