00001 /*This file has been prepared for Doxygen automatic documentation generation.*/ 00015 /* Copyright (c) 2009 Atmel Corporation. All rights reserved. 00016 * 00017 * Redistribution and use in source and binary forms, with or without 00018 * modification, are permitted provided that the following conditions are met: 00019 * 00020 * 1. Redistributions of source code must retain the above copyright notice, this 00021 * list of conditions and the following disclaimer. 00022 * 00023 * 2. Redistributions in binary form must reproduce the above copyright notice, 00024 * this list of conditions and the following disclaimer in the documentation 00025 * and/or other materials provided with the distribution. 00026 * 00027 * 3. The name of Atmel may not be used to endorse or promote products derived 00028 * from this software without specific prior written permission. 00029 * 00030 * 4. This software may only be redistributed and used in connection with an Atmel 00031 * AVR product. 00032 * 00033 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 00034 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00035 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 00036 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR 00037 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00038 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00039 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00040 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00041 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00042 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 00043 * 00044 */ 00142 #include <avr32/io.h> 00143 #include "compiler.h" 00144 #include "print_funcs.h" 00145 #include "gpio.h" 00146 #include "mpu.h" 00147 #include "power_clocks_lib.h" 00148 #include "cycle_counter.h" 00149 00150 00151 // Number of regions considered in this example. 00152 #define NB_CONFIG_MPU_ENTRIES 4 00153 00154 #define REGION_0_FLASH_INDEX 0 00155 #define REGION_1_RAM_INDEX 1 00156 #define REGION_2_STACK_INDEX 2 00157 #define REGION_3_PERIPHERALS_INDEX 3 00158 00159 // Allocation for NB_CONFIG_MPU_ENTRIES DMPU entries 00160 mpu_entry_t dmpu_entries[NB_CONFIG_MPU_ENTRIES]; 00161 00162 extern void ForbiddenFunc(); 00163 00164 00165 #if defined (__GNUC__) 00166 00172 __attribute__ ((__naked__, __section__(".ForbiddenText"))) 00173 #elif __ICCAVR32__ 00174 #pragma shadow_registers = full 00175 #pragma location="FORBIDDENTEXT" 00176 #endif 00177 void ForbiddenFunc(void) /*@"FORBIDDENTEXT"*/ 00178 { 00179 #if defined (__GNUC__) 00180 __asm__ __volatile__ ( 00181 ".balign 0x4\n\t" 00182 00183 "nop\n\t" /* We'll get an MPU exception here. */ 00184 "mov pc,lr" /* This is setting the PC to the instruction following the call of ForbiddenFunc. */ 00185 :: 00186 ); 00187 #elif defined (__ICCAVR32__) 00188 __asm__ __volatile__ ( 00189 "nop\n\t" /* We'll get an MPU exception here. */ 00190 "mov pc,lr" /* This is setting the PC to the instruction following the call of ForbiddenFunc. */ 00191 ); 00192 #endif 00193 } 00194 00195 00204 void handle_exception(unsigned int *sp, unsigned long exception_address, unsigned int exception_cause) 00205 { 00206 /* Test exception cause register AVR32_ECR. AVR32_ECR is updated with a value 00207 * equal to the 9 lowest bits of the EVBA offset of the exception shifted 2 00208 * bits to the right. */ 00209 00210 switch(exception_cause) 00211 { 00212 case AVR32_EVBA_OFFSET_TLB_MULTIPLE/4: 00213 // The TLB Multiple Hit Exception is generated when an access hits in 00214 // multiple MPU regions. This is usually caused by programming error. 00215 // Turn LED0 on. 00216 ((avr32_gpio_port_t *)&AVR32_GPIO.port[LED0_GPIO >> 5])->ovrc = 1 << (LED0_GPIO & 0x1F); 00217 disable_mpu(); // Disable the MPU to avoid to trigger the exception again! 00218 break; 00219 00220 case AVR32_EVBA_OFFSET_ITLB_MISS/4: 00221 // The ITLB Miss exception is generated when the MPU is enabled and the 00222 // instruction memory access does not hit in any regions. 00223 // Turn LED1 on. 00224 ((avr32_gpio_port_t *)&AVR32_GPIO.port[LED1_GPIO >> 5])->ovrc = 1 << (LED1_GPIO & 0x1F); 00225 disable_mpu(); // Disable the MPU to avoid to trigger the exception again! 00226 break; 00227 00228 case AVR32_EVBA_OFFSET_ITLB_PROT/4: 00229 // The ITLB Protection exception is generated when the instruction memory 00230 // access violates the access rights specified by the protection region in 00231 // which the address lies. 00232 // Turn LED2 on. 00233 ((avr32_gpio_port_t *)&AVR32_GPIO.port[LED2_GPIO >> 5])->ovrc = 1 << (LED2_GPIO & 0x1F); 00234 disable_mpu(); // Disable the MPU to avoid to trigger the exception again! 00235 break; 00236 00237 case AVR32_EVBA_OFFSET_DTLB_MISS_R/4: 00238 // The DTLB Read Miss exception is generated when the MPU is enabled and 00239 // the data memory read access does not hit in any regions. 00240 #if BOARD == EVK1100 || BOARD == STK600_RCUC3L0 00241 // Turn LED6 on. 00242 ((avr32_gpio_port_t *)&AVR32_GPIO.port[LED6_GPIO >> 5])->ovrc = 1 << (LED6_GPIO & 0x1F); 00243 #endif 00244 disable_mpu(); // Disable the MPU to avoid to trigger the exception again! 00245 break; 00246 00247 case AVR32_EVBA_OFFSET_DTLB_MISS_W/4: 00248 // The DTLB Write Miss exception is generated when the MPU is enabled and 00249 // the data memory write access does not hit in any regions. 00250 #if BOARD == EVK1100 || BOARD == STK600_RCUC3L0 00251 // Turn LED4 on. 00252 ((avr32_gpio_port_t *)&AVR32_GPIO.port[LED4_GPIO >> 5])->ovrc = 1 << (LED4_GPIO & 0x1F); 00253 #endif 00254 disable_mpu(); // Disable the MPU to avoid to trigger the exception again! 00255 break; 00256 00257 case AVR32_EVBA_OFFSET_DTLB_PROT_R/4: 00258 // The DTLB Protection exception is generated when the data memory read 00259 // violates the access rights specified by the protection region in which 00260 // the address lies. 00261 #if BOARD == EVK1100 || BOARD == STK600_RCUC3L0 00262 // Turn LED5 on. 00263 ((avr32_gpio_port_t *)&AVR32_GPIO.port[LED5_GPIO >> 5])->ovrc = 1 << (LED5_GPIO & 0x1F); 00264 #endif 00265 disable_mpu(); // Disable the MPU to avoid to trigger the exception again! 00266 break; 00267 00268 case AVR32_EVBA_OFFSET_DTLB_PROT_W/4: 00269 // The DTLB Protection exception is generated when the data memory write 00270 // violates the access rights specified by the protection region in which 00271 // the address lies. 00272 // Turn LED3 on. 00273 ((avr32_gpio_port_t *)&AVR32_GPIO.port[LED3_GPIO >> 5])->ovrc = 1 << (LED3_GPIO & 0x1F); 00274 // Update the return from exception PC address to the next instruction, 00275 // to avoid triggering the exception again. 00276 // Check if the instruction that generated the exception is extended 00277 // (4 bytes) or compact (2 bytes) to find out the address of the next 00278 // instruction which we should return to. All extended intructions have the 00279 // 3 MSb always set, while this pattern is forbidden for compact instructions. 00280 if ( (*((unsigned char *)exception_address) & 0xE0 ) == 0xE0 ) 00281 // Extended instruction. 00282 sp[1] = exception_address + 4; 00283 else 00284 // Compact instruction 00285 sp[1] = exception_address + 2; 00286 break; 00287 00288 default: // Unexpected 00289 #if BOARD == EVK1100 || BOARD == STK600_RCUC3L0 00290 // Toggle LED7. 00291 ((avr32_gpio_port_t *)&AVR32_GPIO.port[LED7_GPIO >> 5])->ovrt = 1 << (LED7_GPIO & 0x1F); 00292 #endif 00293 break; 00294 } 00295 } 00296 00297 00298 static void ToggleLedsInfinitly(void) 00299 { 00300 volatile unsigned long i; 00301 00302 00303 LED_On( LED0 | LED1 | LED2 | LED3 ); 00304 while(1) 00305 { 00306 i=100000; 00307 while(i--); 00308 LED_Toggle( LED0 | LED1 | LED2 | LED3 ); 00309 } 00310 } 00311 00312 00313 static void DisplayLedChaserInfinitly(void) 00314 { 00315 volatile unsigned long i; 00316 U8 u8LedMap = 0x01; 00317 00318 00319 while(1) 00320 { 00321 // Turn the current LED on only and move to next LED. 00322 LED_Display_Field(LED0 | LED1, u8LedMap); 00323 i=100000; 00324 while(i--); 00325 u8LedMap = max((U8)(u8LedMap << 1) & 0x0F, 0x01); 00326 } 00327 } 00328 00329 00335 void test_memory_area(void) 00336 { 00337 avr32_config1_t config1; // configuration register 00338 U8 u8NbMpuEntries; // Number of MPU entries. 00339 #if defined (__GNUC__) 00340 extern void _stack; // Start address of the stack. 00341 extern void __stack_size__; // Size of the stack. 00342 #elif defined (__ICCAVR32__) 00343 #pragma segment = "SSTACK" 00344 #endif 00345 eRegionSize RegionSize; // Region size 00346 U32 u32kBSizeValue; // A region size expressed in kB 00347 00348 00349 // Read the CONFIG1 register to check the MPU configuration. 00350 *(U32 *)&config1 = (U32)Get_system_register(AVR32_CONFIG1); 00351 u8NbMpuEntries = config1.dmmusz; 00352 print_dbg("\r\nNumber of MPU entries: 0x"); 00353 print_dbg_hex(u8NbMpuEntries); // Should be 8 on UC3. 00354 00355 print_dbg("\r\nSetting up all MPU entries:"); 00356 00357 00358 //### 00359 // Configuring Region 0: the Flash memory area occupied by this application. 00360 // Since this program is linked into flash, we want to define the Flash memory 00361 // protection scheme as being Readable and Executable (RX). 00362 // The flash memory starts at address 0x80000000 (this info is found in the part 00363 // specific header file found in the compiler installation tree; e.g. in uc3a0512.h 00364 // for an AT32UC3A0512 part). 00365 dmpu_entries[REGION_0_FLASH_INDEX].addr = AVR32_FLASH_ADDRESS; 00366 // We estimate the size of this application to be less than 64kB. So we define 00367 // region 0 size as being 64kB. 00368 dmpu_entries[REGION_0_FLASH_INDEX].size = MPU_REGION_SIZE_64KB; 00369 // Deem this protection scheme as valid. 00370 dmpu_entries[REGION_0_FLASH_INDEX].valid = 1; 00371 if( set_mpu_entry(&dmpu_entries[REGION_0_FLASH_INDEX], REGION_0_FLASH_INDEX) ) 00372 ToggleLedsInfinitly(); // Error 00373 00374 // Set Access Permission A to Read/Execute access in both privileged 00375 // and unprivileged mode. 00376 set_access_permissions(REGION_0_FLASH_INDEX, MPU_APRA_ID, MPU_PRIVRX_UNPRIVRX); 00377 // Set Access Permission B to Read access in privileged mode and to 00378 // None in unprivileged mode. 00379 set_access_permissions(REGION_0_FLASH_INDEX, MPU_APRB_ID, MPU_PRIVR_UNPRIVNONE); 00380 // Each region is divided into 16 sub-regions. So in the case of this region 00381 // (region 0) we are currently setting up, each sub-region is 4kB in size. 00382 // All subregions that hold our application should be in EXECUTE access; except 00383 // for the ForbiddenFunc function which we implicitly put towards the end of 00384 // the .text section, for test purpose. 00385 // We estimated that our application should fit in much less that 64kB. So we 00386 // configure the subregions 0 to 11 to use the permission access Read/eXecute 00387 // as defined in the MPUAPRA register and the remaining subregions (12 to 15) 00388 // to use the permission access Read. Each subregion is mapped to a bit: when 00389 // the bit is set to 0, the subregion permission access is taken from the MPUAPRA 00390 // register (previously defined as MPU_PRIVRX_UNPRIVRX for region 0); if the 00391 // bit is set to 1; the subregion permission access is taken from the MPUAPRB 00392 // register (previously set to MPU_PRIVR_UNPRIVNONE for region 0). 00393 // We purposedly placed the ForbiddenFunc function in one of the subregion 12 00394 // to 15; so that when the code jumps to this location, we should get an ITLB 00395 // exception. 00396 select_subregion(REGION_0_FLASH_INDEX, 0xF000); 00397 00398 00399 //### 00400 // Configuring Region 1: the internal RAM memory used by this application. 00401 // The RAM memory starts at address 0x00000000 (this info is found in the part 00402 // specific header file found in the compiler installation tree; e.g. in uc3a0512.h 00403 // for an AT32UC3A0512 part). 00404 dmpu_entries[REGION_1_RAM_INDEX].addr = AVR32_SRAM_ADDRESS; 00405 // We estimate the RAM footprint of this application to be less than 4kB. So 00406 // we define region 1 size as being 4kB in size. 00407 dmpu_entries[REGION_1_RAM_INDEX].size = MPU_REGION_SIZE_4KB; 00408 // Deem this protection scheme as valid. 00409 dmpu_entries[REGION_1_RAM_INDEX].valid = 1; 00410 if( set_mpu_entry(&dmpu_entries[REGION_1_RAM_INDEX], REGION_1_RAM_INDEX) ) 00411 ToggleLedsInfinitly(); // Error 00412 00413 // Set Access Permission A to Read/Write access in privileged mode and to None 00414 // in unprivileged mode. 00415 set_access_permissions(REGION_1_RAM_INDEX, MPU_APRA_ID, MPU_PRIVRW_UNPRIVNONE); 00416 // Set Access Permission B to Read access in privileged mode and to None in 00417 // unprivileged mode. 00418 set_access_permissions(REGION_1_RAM_INDEX, MPU_APRB_ID, MPU_PRIVR_UNPRIVNONE); 00419 // Each region is divided into 16 sub-regions. So in the case of region 1 we 00420 // are currently setting up, each sub-region is 256B in size. 00421 // All subregions that our application uses should be in Read/Write access; 00422 // except for the last subregion (in [0x00000F00, 0x00001000[) (for test purpose). 00423 // We estimated that our application should use much less than 4kB. So we 00424 // configure the subregions 0 to 14 to use the permission access Read/Write 00425 // as defined in the MPUAPRA register and the remaining subregion (15) to use 00426 // the permission access Read. 00427 // Each subregion is mapped to a bit: when the bit is set to 0, the subregion 00428 // permission access is taken from the MPUAPRA register (previously defined as 00429 // MPU_PRIVRW_UNPRIVNONE for region 1); if the bit is set to 1; the subregion 00430 // permission access is taken from the MPUAPRB register (previously set to 00431 // MPU_PRIVR_UNPRIVNONE for region 1). 00432 // For the sake of this example, the application will try to do a write access 00433 // at an address in the range [0x00000F00, 0x00001000[: we should then get a 00434 // DTLB exception. 00435 select_subregion(REGION_1_RAM_INDEX, 0x8000); 00436 00437 00438 //### 00439 // Configuring Region 2: the memory used by the stack. 00440 // According to the linker script and to the linker step, the stack is placed 00441 // in INTRAM (internal RAM memory) after the RAM area explicitly used by the 00442 // application. 00443 // The stack is used upon exceptions (some registers are saved on the stack; cf 00444 // doc32000 "AVR32 Architecture Manual Complete" section 7.1 Event Handling in 00445 // AVR32A); the stack may be used when doing function calls also. Since this 00446 // application intends to generate exceptions, we must make sure that the memory 00447 // area used by the stack is Read/Write! 00448 #if defined (__GNUC__) 00449 dmpu_entries[REGION_2_STACK_INDEX].addr = (unsigned int)&_stack; 00450 #elif defined (__ICCAVR32__) 00451 dmpu_entries[REGION_2_STACK_INDEX].addr = (unsigned int)__segment_begin( "SSTACK" ); 00452 #endif 00453 // WARNING NOTE: there are limitations concerning the region size; see doc32002 00454 // "AVR32UC Technical Reference Manual Complete" Table 6-1. "Protection region 00455 // sizes implied by the Size field". The mpu_convert_kbsize_to_eregionsize() 00456 // makes sure this part of the spec is respected. 00457 #if defined (__GNUC__) 00458 u32kBSizeValue = (U32)&__stack_size__ >> 10; 00459 #elif defined (__ICCAVR32__) 00460 u32kBSizeValue = ((U32)__segment_end( "SSTACK" ) - (U32)__segment_begin( "SSTACK" )) >> 10; 00461 #endif 00462 00463 if(KO == mpu_convert_kbsize_to_eregionsize(&RegionSize, u32kBSizeValue)) 00464 ToggleLedsInfinitly(); // Error 00465 dmpu_entries[REGION_2_STACK_INDEX].size = RegionSize; 00466 // Deem this protection scheme as valid. 00467 dmpu_entries[REGION_2_STACK_INDEX].valid = 1; 00468 if( set_mpu_entry(&dmpu_entries[REGION_2_STACK_INDEX], REGION_2_STACK_INDEX) ) 00469 ToggleLedsInfinitly(); // Error 00470 00471 // Set Access Permission A to Read access in privileged mode and to None in 00472 // unprivileged mode. 00473 set_access_permissions(REGION_2_STACK_INDEX, MPU_APRA_ID, MPU_PRIVR_UNPRIVNONE); 00474 // Set Access Permission B to Read/Write access in privileged mode and to None 00475 // in unprivileged mode. 00476 set_access_permissions(REGION_2_STACK_INDEX, MPU_APRB_ID, MPU_PRIVRW_UNPRIVNONE); 00477 // Set all subregions of the stack to Read/Write access (i.e. use the Access Permissions B). 00478 select_subregion(REGION_2_STACK_INDEX,0xFFFF); 00479 00480 00481 //### 00482 // Configuring Region 3: the peripherals memory mapping. 00483 // We're using the DEBUG module to output traces to USART1, we're using the GPIO 00484 // module => we have to define access permissions to the region where the USART1 00485 // & GPIO peripherals registers are mapped. We'll set this region as Read/Write 00486 // because we don't want to generate MPU exceptions when using a peripheral. 00487 // The USART1 & GPIO peripherals are on the same Peripheral Bus (PBA). We'll 00488 // configure all peripherals on PBA with the same access rights. 00489 // The PBA physical memory map starts at address 0xFFFF0000 (this info is found 00490 // in the datasheet in the table "AT32UC3x Physical Memory Map". 00491 // The PDCA module happens to be the module that is mapped at the start of the 00492 // PBA memory map. 00493 dmpu_entries[REGION_3_PERIPHERALS_INDEX].addr = AVR32_PDCA_ADDRESS; 00494 // The size of the PBA memory map is 64kB. 00495 dmpu_entries[REGION_3_PERIPHERALS_INDEX].size = MPU_REGION_SIZE_64KB; 00496 // Deem this protection scheme as valid. 00497 dmpu_entries[REGION_3_PERIPHERALS_INDEX].valid = 1; 00498 if( set_mpu_entry(&dmpu_entries[REGION_3_PERIPHERALS_INDEX], REGION_3_PERIPHERALS_INDEX) ) 00499 ToggleLedsInfinitly(); // Error 00500 00501 // Set Access Permission A to Read/Write access in privileged mode and to None 00502 // in unprivileged mode. 00503 set_access_permissions(REGION_3_PERIPHERALS_INDEX, MPU_APRA_ID, MPU_PRIVRW_UNPRIVNONE); 00504 // We don't set the Access Permission B because we won't use it. 00505 // Set all 16 subregions of the PBA memory map to Read/Write access. 00506 select_subregion(REGION_3_PERIPHERALS_INDEX,0x0000); 00507 00508 00509 enable_mpu(); // Enable the MPU address checking. 00510 } 00511 00512 00513 /* \brief Main entry point 00514 * This is an example of how to setup the AVR32 UC3 MPU with protected regions. 00515 */ 00516 00517 int main(void) 00518 { 00519 Enable_global_exception(); 00520 Enable_global_interrupt(); 00521 00522 // Clear the LEDs. 00523 #if BOARD == EVK1100 || BOARD == EVK1101 || BOARD == EVK1104 || BOARD == EVK1105 || BOARD == STK600_RCUC3L0 00524 gpio_set_gpio_pin(LED0_GPIO); gpio_set_gpio_pin(LED1_GPIO); 00525 gpio_set_gpio_pin(LED2_GPIO); gpio_set_gpio_pin(LED3_GPIO); 00526 #endif 00527 #if BOARD == EVK1100 || BOARD == STK600_RCUC3L0 00528 gpio_set_gpio_pin(LED4_GPIO); gpio_set_gpio_pin(LED5_GPIO); 00529 gpio_set_gpio_pin(LED6_GPIO); gpio_set_gpio_pin(LED7_GPIO); 00530 #endif 00531 00532 // Configure Osc0 in crystal mode (i.e. use of an external crystal source, with 00533 // frequency FOSC0) with an appropriate startup time then switch the main clock 00534 // source to Osc0. 00535 pcl_switch_to_osc(PCL_OSC0, FOSC0, OSC0_STARTUP); 00536 00537 // Init the trace-on-usart1 module (under UTILS/DEBUG/). 00538 init_dbg_rs232(FOSC0); 00539 print_dbg("\n\n## This is the AT32UC3 MPU example ##"); 00540 00541 // Set up and enable the MPU to protect the following memory areas: 00542 // -------------------- 00543 // | Access permissions | 00544 // ------------------------------------------|--------------------| 00545 // | Flash [0x80000000 - 0x8000C000[ | Read / eXecute | 00546 // | Region 0, subregions 0 to 11 | | 00547 // |------------------------------------------|--------------------| 00548 // | Flash [0x8000C000 - 0x80010000[ | Read | 00549 // | Region 0, subregions 12 to 15 | | 00550 // |------------------------------------------|--------------------| 00551 // | RAM [0x00000000 - 0x00000F00[ | Read / Write | 00552 // | Region 1, subregions 0 to 14 | | 00553 // |------------------------------------------|--------------------| 00554 // | RAM [0x00000F00 - 0x00001000[ | Read | 00555 // | Region 1, subregion 15 | | 00556 // |------------------------------------------|--------------------| 00557 // | Stack [&stack - &stack + stack size[ | Read / Write | 00558 // | Region 2, all subregions | | 00559 // ---------------------------------------------------------------| 00560 // | PBA memory map [0xFFFF0000 - 0xFFFFFFFF] | Read / Write | 00561 // | Region 3, all subregions | | 00562 // --------------------------------------------------------------- 00563 test_memory_area(); 00564 00565 print_dbg("\nTesting the Write protection of the area [0x00000F00 - 0x00001000["); 00566 // The address 0x00000F00 is mpu-configured as Read only. We perform a Write 00567 // access there, so that should trigger a DTLB write protection exception 00568 // => LED3 lights up. 00569 *( (volatile int*) (0x00000F00)) = 0x55AA55AA; 00570 00571 // Wait two seconds before doing the next test, to clearly see that LED3 lights 00572 // up first then LED2 does. 00573 cpu_delay_ms(2000, FOSC0); 00574 00575 00576 print_dbg("\nTesting the eXecute protection of the area [0x8000C000 - 0x80010000["); 00577 // The memory area [0x8000C000 - 0x80010000[ is mpu-configured as Read only. 00578 // We forced the ForbiddenFunc() function to be mapped in this area. Calling 00579 // this function should thus trigger an ITLB protection exception => LED2 lights up. 00580 ForbiddenFunc(); 00581 00582 // LED0 & LED1 blink alternatively forever. 00583 DisplayLedChaserInfinitly(); 00584 00585 return(0); 00586 }