1 /******************************************************************************
2 *
3 * Copyright (C) 2014 - 2017 Xilinx, Inc. All rights reserved.
4 * Copyright (C) 2021 WangHuachen. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 *
25 *
26 ******************************************************************************/
27 /*****************************************************************************/
28 /**
29 * @file xil_mpu.c
30 *
31 * This file provides APIs for enabling/disabling MPU and setting the memory
32 * attributes for sections, in the MPU translation table.
33 *
34 * <pre>
35 * MODIFICATION HISTORY:
36 *
37 * Ver   Who  Date     Changes
38 * ----- ---- -------- ---------------------------------------------------
39 * 5.00  pkp  02/10/14 Initial version
40 * 6.2   mus  01/27/17 Updated to support IAR compiler
41 * 6.4   asa  08/16/17 Added many APIs for MPU access to make MPU usage
42 *                       user-friendly. The APIs added are: Xil_UpdateMPUConfig,
43 *                       Xil_GetMPUConfig, Xil_GetNumOfFreeRegions,
44 *                       Xil_GetNextMPURegion, Xil_DisableMPURegionByRegNum,
45 *                       Xil_GetMPUFreeRegMask, Xil_SetMPURegionByRegNum, and
46 *                       Xil_InitializeExistingMPURegConfig.
47 *                       Added a new array of structure of type XMpuConfig to
48 *                       represent the MPU configuration table.
49 * 6.8  aru  07/02/18 Returned the pointer instead of address
50 *            of that pointer in Xil_MemMap().
51 * </pre>
52 *
53 *
54 ******************************************************************************/
55 
56 /***************************** Include Files *********************************/
57 
58 #include "xil_cache.h"
59 #include "xpseudo_asm_gcc.h"
60 #include "xil_types.h"
61 #include "xil_mpu.h"
62 // #include "xdebug.h"
63 #include "xreg_cortexr5.h"
64 #include "xstatus.h"
65 
66 #include <rtthread.h>
67 #define DBG_TAG           "xil_mpu"
68 #define DBG_LVL           DBG_INFO
69 #include <rtdbg.h>
70 
71 extern void Xil_DCacheFlush(void);
72 extern void Xil_ICacheInvalidate(void);
73 extern void Xil_DCacheDisable(void);
74 extern void Xil_ICacheDisable(void);
75 extern void Xil_DCacheEnable(void);
76 extern void Xil_ICacheEnable(void);
77 
78 /***************** Macros (Inline Functions) Definitions *********************/
79 
80 /**************************** Type Definitions *******************************/
81 
82 /************************** Constant Definitions *****************************/
83 #define MPU_REGION_SIZE_MIN 0x20
84 /************************** Variable Definitions *****************************/
85 
86 static const struct {
87     u64 size;
88     unsigned int encoding;
89 }region_size[] = {
90     { 0x20, REGION_32B },
91     { 0x40, REGION_64B },
92     { 0x80, REGION_128B },
93     { 0x100, REGION_256B },
94     { 0x200, REGION_512B },
95     { 0x400, REGION_1K },
96     { 0x800, REGION_2K },
97     { 0x1000, REGION_4K },
98     { 0x2000, REGION_8K },
99     { 0x4000, REGION_16K },
100     { 0x8000, REGION_32K },
101     { 0x10000, REGION_64K },
102     { 0x20000, REGION_128K },
103     { 0x40000, REGION_256K },
104     { 0x80000, REGION_512K },
105     { 0x100000, REGION_1M },
106     { 0x200000, REGION_2M },
107     { 0x400000, REGION_4M },
108     { 0x800000, REGION_8M },
109     { 0x1000000, REGION_16M },
110     { 0x2000000, REGION_32M },
111     { 0x4000000, REGION_64M },
112     { 0x8000000, REGION_128M },
113     { 0x10000000, REGION_256M },
114     { 0x20000000, REGION_512M },
115     { 0x40000000, REGION_1G },
116     { 0x80000000, REGION_2G },
117     { 0x100000000, REGION_4G },
118 };
119 
120 XMpu_Config Mpu_Config;
121 
122 /************************** Function Prototypes ******************************/
123 void Xil_InitializeExistingMPURegConfig(void);
124 /*****************************************************************************/
125 /**
126 * @brief    This function sets the memory attributes for a section covering
127 *           1MB, of memory in the translation table.
128 *
129 * @param    Addr: 32-bit address for which memory attributes need to be set.
130 * @param    attrib: Attribute for the given memory region.
131 * @return    None.
132 *
133 *
134 ******************************************************************************/
Xil_SetTlbAttributes(INTPTR addr,u32 attrib)135 void Xil_SetTlbAttributes(INTPTR addr, u32 attrib)
136 {
137     INTPTR Localaddr = addr;
138     Localaddr &= (~(0xFFFFFU));
139     /* Setting the MPU region with given attribute with 1MB size */
140     Xil_SetMPURegion(Localaddr, 0x100000, attrib);
141 }
142 
143 /*****************************************************************************/
144 /**
145 * @brief    Set the memory attributes for a section of memory in the
146 *           translation table.
147 *
148 * @param    Addr: 32-bit address for which memory attributes need to be set..
149 * @param    size: size is the size of the region.
150 * @param    attrib: Attribute for the given memory region.
151 * @return    None.
152 *
153 *
154 ******************************************************************************/
Xil_SetMPURegion(INTPTR addr,u64 size,u32 attrib)155 u32 Xil_SetMPURegion(INTPTR addr, u64 size, u32 attrib)
156 {
157     u32 Regionsize = 0;
158     INTPTR Localaddr = addr;
159     u32 NextAvailableMemRegion;
160     unsigned int i;
161 
162     NextAvailableMemRegion = Xil_GetNextMPURegion();
163     if (NextAvailableMemRegion == 0xFF) {
164         LOG_E("No regions available\r\n");
165         return XST_FAILURE;
166     }
167 
168     Xil_DCacheFlush();
169     Xil_ICacheInvalidate();
170 
171     mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,NextAvailableMemRegion);
172     isb();
173 
174     /* Lookup the size.  */
175     for (i = 0; i < sizeof region_size / sizeof region_size[0]; i++) {
176         if (size <= region_size[i].size) {
177             Regionsize = region_size[i].encoding;
178             break;
179         }
180     }
181 
182     Localaddr &= ~(region_size[i].size - 1);
183 
184     Regionsize <<= 1;
185     Regionsize |= REGION_EN;
186     dsb();
187     mtcp(XREG_CP15_MPU_REG_BASEADDR, Localaddr);    /* Set base address of a region */
188     mtcp(XREG_CP15_MPU_REG_ACCESS_CTRL, attrib);    /* Set the control attribute */
189     mtcp(XREG_CP15_MPU_REG_SIZE_EN, Regionsize);    /* set the region size and enable it*/
190     dsb();
191     isb();
192     Xil_UpdateMPUConfig(NextAvailableMemRegion, Localaddr, Regionsize, attrib);
193     return XST_SUCCESS;
194 }
195 /*****************************************************************************/
196 /**
197 * @brief    Enable MPU for Cortex R5 processor. This function invalidates I
198 *           cache and flush the D Caches, and then enables the MPU.
199 *
200 *
201 * @param    None.
202 * @return    None.
203 *
204 ******************************************************************************/
Xil_EnableMPU(void)205 void Xil_EnableMPU(void)
206 {
207     u32 CtrlReg, Reg;
208     s32 DCacheStatus=0, ICacheStatus=0;
209     /* enable caches only if they are disabled */
210 #if defined (__GNUC__)
211     CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
212 #elif defined (__ICCARM__)
213     mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
214 #endif
215     if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) != 0x00000000U) {
216         DCacheStatus=1;
217     }
218     if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) != 0x00000000U) {
219         ICacheStatus=1;
220     }
221 
222     if(DCacheStatus != 0) {
223         Xil_DCacheDisable();
224     }
225     if(ICacheStatus != 0){
226         Xil_ICacheDisable();
227     }
228 #if defined (__GNUC__)
229     Reg = mfcp(XREG_CP15_SYS_CONTROL);
230 #elif defined (__ICCARM__)
231      mfcp(XREG_CP15_SYS_CONTROL,Reg);
232 #endif
233     Reg |= 0x00000001U;
234     dsb();
235     mtcp(XREG_CP15_SYS_CONTROL, Reg);
236     isb();
237     /* enable caches only if they are disabled in routine*/
238     if(DCacheStatus != 0) {
239         Xil_DCacheEnable();
240     }
241     if(ICacheStatus != 0) {
242         Xil_ICacheEnable();
243     }
244 }
245 
246 /*****************************************************************************/
247 /**
248 * @brief    Disable MPU for Cortex R5 processors. This function invalidates I
249 *           cache and flush the D Caches, and then disabes the MPU.
250 *
251 * @param    None.
252 *
253 * @return    None.
254 *
255 ******************************************************************************/
Xil_DisableMPU(void)256 void Xil_DisableMPU(void)
257 {
258     u32 CtrlReg, Reg;
259     s32 DCacheStatus=0, ICacheStatus=0;
260     /* enable caches only if they are disabled */
261 
262 #if defined (__GNUC__)
263     CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
264 #elif defined (__ICCARM__)
265     mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
266 #endif
267     if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) != 0x00000000U) {
268         DCacheStatus=1;
269     }
270     if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) != 0x00000000U) {
271         ICacheStatus=1;
272     }
273 
274     if(DCacheStatus != 0) {
275         Xil_DCacheDisable();
276     }
277     if(ICacheStatus != 0){
278         Xil_ICacheDisable();
279     }
280 
281     mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0);
282 #if defined (__GNUC__)
283     Reg = mfcp(XREG_CP15_SYS_CONTROL);
284 #elif defined (__ICCARM__)
285     mfcp(XREG_CP15_SYS_CONTROL,Reg);
286 #endif
287     Reg &= ~(0x00000001U);
288     dsb();
289     mtcp(XREG_CP15_SYS_CONTROL, Reg);
290     isb();
291     /* enable caches only if they are disabled in routine*/
292     if(DCacheStatus != 0) {
293         Xil_DCacheEnable();
294     }
295     if(ICacheStatus != 0) {
296         Xil_ICacheEnable();
297     }
298 }
299 
300 /*****************************************************************************/
301 /**
302 * @brief    Update the MPU configuration for the requested region number in
303 *             the global MPU configuration table.
304 *
305 * @param    reg_num: The requested region number to be updated information for.
306 * @param    address: 32 bit address for start of the region.
307 * @param    size: Requested size of the region.
308 * @param    attrib: Attribute for the corresponding region.
309 * @return    XST_FAILURE: When the requested region number if 16 or more.
310 *             XST_SUCCESS: When the MPU configuration table is updated.
311 *
312 *
313 ******************************************************************************/
Xil_UpdateMPUConfig(u32 reg_num,INTPTR address,u32 size,u32 attrib)314 u32 Xil_UpdateMPUConfig(u32 reg_num, INTPTR address, u32 size, u32 attrib)
315 {
316     u32 ReturnVal = XST_SUCCESS;
317     u32 Tempsize = size;
318     u32 Index;
319 
320     if (reg_num >=  MAX_POSSIBLE_MPU_REGS) {
321         LOG_E("Invalid region number\r\n");
322         ReturnVal = XST_FAILURE;
323         goto exit;
324     }
325 
326     if (size & REGION_EN) {
327         Mpu_Config[reg_num].RegionStatus = MPU_REG_ENABLED;
328         Mpu_Config[reg_num].BaseAddress = address;
329         Tempsize &= (~REGION_EN);
330         Tempsize >>= 1;
331         /* Lookup the size.  */
332         for (Index = 0; Index <
333                 sizeof region_size / sizeof region_size[0]; Index++) {
334             if (Tempsize <= region_size[Index].encoding) {
335                 Mpu_Config[reg_num].Size = region_size[Index].size;
336                 break;
337             }
338         }
339         Mpu_Config[reg_num].Attribute = attrib;
340     } else {
341         Mpu_Config[reg_num].RegionStatus = 0U;
342         Mpu_Config[reg_num].BaseAddress = 0U;
343         Mpu_Config[reg_num].Size = 0U;
344         Mpu_Config[reg_num].Attribute = 0U;
345     }
346 
347 exit:
348     return ReturnVal;
349 }
350 
351 /*****************************************************************************/
352 /**
353 * @brief    The MPU configuration table is passed to the caller.
354 *
355 * @param    mpuconfig: This is of type XMpu_Config which is an array of
356 *             16 entries of type structure representing the MPU config table
357 * @return    none
358 *
359 *
360 ******************************************************************************/
Xil_GetMPUConfig(XMpu_Config mpuconfig)361 void Xil_GetMPUConfig (XMpu_Config mpuconfig) {
362     u32 Index = 0U;
363 
364     while (Index < MAX_POSSIBLE_MPU_REGS) {
365         mpuconfig[Index].RegionStatus = Mpu_Config[Index].RegionStatus;
366         mpuconfig[Index].BaseAddress = Mpu_Config[Index].BaseAddress;
367         mpuconfig[Index].Attribute = Mpu_Config[Index].Attribute;
368         mpuconfig[Index].Size = Mpu_Config[Index].Size;
369         Index++;
370     }
371 }
372 
373 /*****************************************************************************/
374 /**
375 * @brief    Returns the total number of free MPU regions available.
376 *
377 * @param    none
378 * @return    Number of free regions available to users
379 *
380 *
381 ******************************************************************************/
Xil_GetNumOfFreeRegions(void)382 u32 Xil_GetNumOfFreeRegions (void) {
383     u32 Index = 0U;
384     int NumofFreeRegs = 0U;
385 
386     while (Index < MAX_POSSIBLE_MPU_REGS) {
387         if (MPU_REG_DISABLED == Mpu_Config[Index].RegionStatus) {
388             NumofFreeRegs++;
389         }
390         Index++;
391     }
392     return NumofFreeRegs;
393 }
394 
395 /*****************************************************************************/
396 /**
397 * @brief    Returns the total number of free MPU regions available in the form
398 *           of a mask. A bit of 1 in the returned 16 bit value represents the
399 *           corresponding region number to be available.
400 *           For example, if this function returns 0xC0000, this would mean, the
401 *           regions 14 and 15 are available to users.
402 *
403 * @param    none
404 * @return    The free region mask as a 16 bit value
405 *
406 *
407 ******************************************************************************/
Xil_GetMPUFreeRegMask(void)408 u16 Xil_GetMPUFreeRegMask (void) {
409     u32 Index = 0U;
410     u16 FreeRegMask = 0U;
411 
412     while (Index < MAX_POSSIBLE_MPU_REGS) {
413         if (MPU_REG_DISABLED == Mpu_Config[Index].RegionStatus) {
414             FreeRegMask |= (1U << Index);
415         }
416         Index++;
417     }
418     return FreeRegMask;
419 }
420 
421 /*****************************************************************************/
422 /**
423 * @brief    Disables the corresponding region number as passed by the user.
424 *
425 * @param    reg_num: The region number to be disabled
426 * @return    XST_SUCCESS: If the region could be disabled successfully
427 *             XST_FAILURE: If the requested region number is 16 or more.
428 *
429 *
430 ******************************************************************************/
Xil_DisableMPURegionByRegNum(u32 reg_num)431 u32 Xil_DisableMPURegionByRegNum (u32 reg_num) {
432     u32 Temp = 0U;
433     u32 ReturnVal = XST_FAILURE;
434 
435     if (reg_num >= 16U) {
436         LOG_E("Invalid region number\r\n");
437         goto exit1;
438     }
439     Xil_DCacheFlush();
440     Xil_ICacheInvalidate();
441 
442     mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,reg_num);
443 #if defined (__GNUC__)
444     Temp = mfcp(XREG_CP15_MPU_REG_SIZE_EN);
445 #elif defined (__ICCARM__)
446     mfcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
447 #endif
448     Temp &= (~REGION_EN);
449     dsb();
450     mtcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
451     dsb();
452     isb();
453     Xil_UpdateMPUConfig(reg_num, 0U, 0U, 0U);
454     ReturnVal = XST_SUCCESS;
455 
456 exit1:
457     return ReturnVal;
458 }
459 
460 /*****************************************************************************/
461 /**
462 * @brief    Enables the corresponding region number as passed by the user.
463 *
464 * @param    reg_num: The region number to be enabled
465 * @param    address: 32 bit address for start of the region.
466 * @param    size: Requested size of the region.
467 * @param    attrib: Attribute for the corresponding region.
468 * @return    XST_SUCCESS: If the region could be created successfully
469 *             XST_FAILURE: If the requested region number is 16 or more.
470 *
471 *
472 ******************************************************************************/
Xil_SetMPURegionByRegNum(u32 reg_num,INTPTR addr,u64 size,u32 attrib)473 u32 Xil_SetMPURegionByRegNum (u32 reg_num, INTPTR addr, u64 size, u32 attrib)
474 {
475     u32 ReturnVal = XST_SUCCESS;
476     INTPTR Localaddr = addr;
477     u32 Regionsize = 0;
478     u32 Index;
479 
480     if (reg_num >= 16U) {
481         LOG_E("Invalid region number\r\n");
482         ReturnVal = XST_FAILURE;
483         goto exit2;
484     }
485 
486     if (Mpu_Config[reg_num].RegionStatus == MPU_REG_ENABLED) {
487         LOG_E("Region already enabled\r\n");
488         ReturnVal = XST_FAILURE;
489         goto exit2;
490     }
491 
492     Xil_DCacheFlush();
493     Xil_ICacheInvalidate();
494     mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,reg_num);
495     isb();
496 
497     /* Lookup the size.  */
498     for (Index = 0; Index <
499             sizeof region_size / sizeof region_size[0]; Index++) {
500         if (size <= region_size[Index].size) {
501             Regionsize = region_size[Index].encoding;
502             break;
503         }
504     }
505 
506     Localaddr &= ~(region_size[Index].size - 1);
507     Regionsize <<= 1;
508     Regionsize |= REGION_EN;
509     dsb();
510     mtcp(XREG_CP15_MPU_REG_BASEADDR, Localaddr);
511     mtcp(XREG_CP15_MPU_REG_ACCESS_CTRL, attrib);
512     mtcp(XREG_CP15_MPU_REG_SIZE_EN, Regionsize);
513     dsb();
514     isb();
515     Xil_UpdateMPUConfig(reg_num, Localaddr, Regionsize, attrib);
516 exit2:
517     return ReturnVal;
518 
519 }
520 
521 /*****************************************************************************/
522 /**
523 * @brief    Initializes the MPU configuration table that are setup in the
524 *             R5 boot code in the Init_Mpu function called before C main.
525 *
526 * @param    none
527 * @return    none
528 *
529 *
530 ******************************************************************************/
Xil_InitializeExistingMPURegConfig(void)531 void Xil_InitializeExistingMPURegConfig(void)
532 {
533     u32 Index = 0U;
534     u32 Index1 = 0U;
535     u32 MPURegSize;
536     INTPTR MPURegBA;
537     u32 MPURegAttrib;
538     u32 Tempsize;
539 
540     while (Index < MAX_POSSIBLE_MPU_REGS) {
541         mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,Index);
542 #if defined (__GNUC__)
543         MPURegSize = mfcp(XREG_CP15_MPU_REG_SIZE_EN);
544         MPURegBA = mfcp(XREG_CP15_MPU_REG_BASEADDR);
545         MPURegAttrib = mfcp(XREG_CP15_MPU_REG_ACCESS_CTRL);
546 #elif defined (__ICCARM__)
547         mfcp(XREG_CP15_MPU_REG_SIZE_EN,MPURegSize);
548         mfcp(XREG_CP15_MPU_REG_BASEADDR, MPURegBA);
549         mfcp(XREG_CP15_MPU_REG_ACCESS_CTRL, MPURegAttrib);
550 #endif
551         if (MPURegSize & REGION_EN) {
552             Mpu_Config[Index].RegionStatus = MPU_REG_ENABLED;
553             Mpu_Config[Index].BaseAddress = MPURegBA;
554             Mpu_Config[Index].Attribute = MPURegAttrib;
555             Tempsize = MPURegSize & (~REGION_EN);
556             Tempsize >>= 1;
557             for (Index1 = 0; Index1 <
558                 (sizeof (region_size) / sizeof (region_size[0])); Index1++) {
559                 if (Tempsize <= region_size[Index1].encoding) {
560                     Mpu_Config[Index].Size = region_size[Index1].size;
561                     break;
562                 }
563             }
564         }
565         Index++;
566     }
567 }
568 
569 /*****************************************************************************/
570 /**
571 * @brief    Returns the next available free MPU region
572 *
573 * @param    none
574 * @return    The free MPU region available
575 *
576 *
577 ******************************************************************************/
Xil_GetNextMPURegion(void)578 u32 Xil_GetNextMPURegion(void)
579 {
580     u32 Index = 0U;
581     u32 NextAvailableReg = 0xFF;
582     while (Index < MAX_POSSIBLE_MPU_REGS) {
583         if (Mpu_Config[Index].RegionStatus != MPU_REG_ENABLED) {
584             NextAvailableReg = Index;
585             break;
586         }
587         Index++;
588     }
589     return NextAvailableReg;
590 }
591 
592 /*****************************************************************************/
593 /**
594 * @brief       Memory mapping for Cortex r5.
595 *
596 * @param       Physaddr is base physical address at which to start mapping.
597 *                   NULL in Physaddr masks possible mapping errors.
598 * @param       size of region to be mapped.
599 * @param       flags used to set translation table.
600 *
601 * @return      Physaddr on success, NULL on error. Ambiguous if Physaddr==NULL
602 *
603 * @note:    u32overflow() is defined for readability and (for __GNUC__) to
604 *           - force the type of the check to be the same as the first argument
605 *           - hide the otherwise unused third argument of the builtin
606 *           - improve safety by choosing the explicit _uadd_ version.
607 *           Consider __builtin_add_overflow_p() when available.
608 *           Use an alternative (less optimal?) for compilers w/o the builtin.
609 *
610 ******************************************************************************/
611 #ifdef __GNUC__
612 #define u32overflow(a, b) ({typeof(a) s; __builtin_uadd_overflow(a, b, &s); })
613 #else
614 #define u32overflow(a, b) ((a) > ((a) + (b)))
615 #endif /* __GNUC__ */
Xil_MemMap(UINTPTR Physaddr,size_t size,u32 flags)616 void *Xil_MemMap(UINTPTR Physaddr, size_t size, u32 flags)
617 {
618     size_t Regionsize = MPU_REGION_SIZE_MIN;
619     UINTPTR Basephysaddr = 0, end = Physaddr + size;
620 
621     if (!flags)
622         return (void *)Physaddr;
623     if (u32overflow(Physaddr, size))
624         return NULL;
625     for ( ; Regionsize != 0; Regionsize <<= 1) {
626         if (Regionsize >= size) {
627             Basephysaddr = Physaddr & ~(Regionsize - 1);
628             if (u32overflow(Basephysaddr, Regionsize))
629                 break;
630             if ((Basephysaddr + Regionsize) >= end)
631                 return Xil_SetMPURegion(Basephysaddr,
632                     Regionsize, flags) == XST_SUCCESS ?
633                     (void *)Physaddr : NULL;
634         }
635     }
636     return NULL;
637 }
638