Ambos lados, revisión anterior
Revisión previa
Próxima revisión
|
Revisión previa
|
inicializacion_de_procesador_cortex-a8 [2023/04/21 00:46] cnigri features_get |
inicializacion_de_procesador_cortex-a8 [2024/05/17 11:16] (actual) cnigri Correccion de descripcion |
|[[https://developer.arm.com/documentation/dui0417/d/hardware-description/northbridge?lang=en | Northbridge]]| 0x70000000-0x8FFFFFFF| [[https://developer.arm.com/documentation/dui0417/d/programmer-s-reference/dynamic-memory-controller--dmc?lang=en | Dinamic Memory Controller]]| 512MB | | |[[https://developer.arm.com/documentation/dui0417/d/hardware-description/northbridge?lang=en | Northbridge]]| 0x70000000-0x8FFFFFFF| [[https://developer.arm.com/documentation/dui0417/d/programmer-s-reference/dynamic-memory-controller--dmc?lang=en | Dinamic Memory Controller]]| 512MB | |
| |
De la tabla se desprende que la memoria RAM se direcciona en el rango 0x70000000-0x8FFFFFFF, y que la parte superior del mismo (256MB) se encuentra espejado en 0x00000000-0x0FFFFFFF. Sin embargo se debe recordar que al estar en la etapa //Inicialización del SoC//, el DMC no se encuentra configurado por lo que no es posible emplear dicha memoria y por ende cualquier rango asociado a la misma. | De la tabla se desprende que la memoria RAM se direcciona en el rango 0x70000000-0x8FFFFFFF, y que el rango de direcciones numéricamente inferiores del mismo (256MB) se encuentra espejado en 0x00000000-0x0FFFFFFF. Sin embargo se debe recordar que al estar en la etapa //Inicialización del SoC//, el DMC no se encuentra configurado por lo que no es posible emplear dicha memoria y por ende cualquier rango asociado a la misma. |
| |
Por su parte la ROM se direcciona en el rango 0x40000000- 0x5FFFFFFF y el controlador de este tipo de memorias no requiere inicialización, justamente para poder leer el código que permita satisfacer los requerimientos de la etapa //Inicialización del SoC//. Al parecer ya se encuentra resuelto el dilema sobre donde leer el código, pero al lector astuto seguramente le surgirá interrogante ¿Cómo puede ser esto posible, si la [[https://developer.arm.com/documentation/ddi0406/b/System-Level-Architecture/The-System-Level-Programmers--Model/Exceptions/Reset | Reset Vector Address]] es 0x00000000 o 0xFFFF0000?\\ | Por su parte la ROM se direcciona en el rango 0x40000000- 0x5FFFFFFF y el controlador de este tipo de memorias no requiere inicialización, justamente para poder leer el código que permita satisfacer los requerimientos de la etapa //Inicialización del SoC//. Al parecer ya se encuentra resuelto el dilema sobre donde leer el código, pero al lector astuto seguramente le surgirá interrogante ¿Cómo puede ser esto posible, si la [[https://developer.arm.com/documentation/ddi0406/b/System-Level-Architecture/The-System-Level-Programmers--Model/Exceptions/Reset | Reset Vector Address]] es 0x00000000 o 0xFFFF0000?\\ |
Para resolver esta duda perfectamente válida apelamos a la //"magia"// del [[https://developer.arm.com/documentation/dui0417/d/hardware-description/northbridge?lang=en | Northbridge]], este ASIC específico de esta placa se encarga de [[https://developer.arm.com/documentation/dui0417/d/programmer-s-reference/configuration-and-initialization/remapping-of-boot-memory?lang=en | remapear]] la NOR de 0x40000000- 0x40FFFFFF a 0x00000000-0x00FFFFFF. Si bien esto ya brinda cierta claridad sobre donde debe situarse el código, es importante observar que el rango remapeado es tan solo de 16MB, frente a los 512MB disponibles en el mapa de memoria, esto significa que si bien la placa puede disponer de una NOR de hasta 512MB el código de arranque en la misma solo puede estar alojado en los primeros 16MB, quedando el restante espacio para disponible para el código complementario. Esto es importante tenerlo presente al momento de generar el mapa de memoria del código por lo general mediante el [[guiasupervivenciald|linker script]] | Para resolver esta duda perfectamente válida apelamos a la //"magia"// del [[https://developer.arm.com/documentation/dui0417/d/hardware-description/northbridge?lang=en | Northbridge]], este ASIC específico de esta placa se encarga de [[https://developer.arm.com/documentation/dui0417/d/programmer-s-reference/configuration-and-initialization/remapping-of-boot-memory?lang=en | remapear]] la NOR de 0x40000000- 0x40FFFFFF a 0x00000000-0x00FFFFFF. Si bien esto ya brinda cierta claridad sobre donde debe situarse el código, es importante observar que el rango remapeado es tan solo de 16MB, frente a los 512MB disponibles en el mapa de memoria, esto significa que si bien la placa puede disponer de una NOR de hasta 512MB el código de arranque en la misma solo puede estar alojado en los primeros 16MB, quedando el restante espacio para disponible para el código complementario. Esto es importante tenerlo presente al momento de generar el mapa de memoria del código por lo general mediante el [[guiasupervivenciald_arm|linker script]] |
| |
| |
A continuación se brinda un extracto del mapa de memoria obtenido del [[https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjD34qtzrf-AhXBrpUCHVucDAIQFnoECAwQAQ&url=https%3A%2F%2Fwww.ti.com%2Flit%2Fug%2Fspruh73q%2Fspruh73q.pdf&usg=AOvVaw3QziFF4b-THpx1J5kOVJNQ | AM335x and AMIC110 Sitara™ Processors Technical Reference Manual]] | A continuación se brinda un extracto del mapa de memoria obtenido del [[https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjD34qtzrf-AhXBrpUCHVucDAIQFnoECAwQAQ&url=https%3A%2F%2Fwww.ti.com%2Flit%2Fug%2Fspruh73q%2Fspruh73q.pdf&usg=AOvVaw3QziFF4b-THpx1J5kOVJNQ | AM335x and AMIC110 Sitara™ Processors Technical Reference Manual]] |
^ Block Name ^ Address range ^ Description ^ Memory region size^ | ^ Block Name ^ Address range ^ Description ^ Memory region size^ |
|Feneral Purpose Memory Controller | 0x00000000-0x1FFFFFFF | 8-/16-bit External Memory (Ex/R/W | 512MB | | |General Purpose Memory Controller | 0x00000000-0x1FFFFFFF | 8-/16-bit External Memory (Ex/R/W | 512MB | |
|Boot ROM | 0x40000000-0x4001FFFF | | 128kB | | |Boot ROM | 0x40000000-0x4001FFFF | | 128kB | |
|Boot ROM | 0x40020000-0x4002BFFF | 32-bit Ex/R (2) – Public | 48kB | | |Boot ROM | 0x40020000-0x4002BFFF | 32-bit Ex/R (2) – Public | 48kB | |
|SRAM internal | 0x402F0400-0x402FFFFF | 32-bit Ex/R/W | 48kB | | |SRAM internal | 0x402F0400-0x402FFFFF | 32-bit Ex/R/W | 63kB | |
|EMIF0 SDRAM | 0x80000000-0xBFFFFFFF | 8-/16-bit External Memory (Ex/R/W) | 1GB | | |EMIF0 SDRAM | 0x80000000-0xBFFFFFFF | 8-/16-bit External Memory (Ex/R/W) | 1GB | |
{{ :td3:under_construction.jpg?200 | En construccion}} | {{ :td3:under_construction.jpg?200 | En construccion}} |
En el modelo propuesto se identifican en <span style="color:red;font-size:100%;">rojo</span> las <span style="color:red;font-size:100%;">configuraciones obligatorias</span>, en <span style="color:orange;font-size:100%;">amarillo</span> las <span style="color:orange;font-size:100%;">optativas segun el caso de uso</span>, mientras que en <span style="color:green;font-size:100%;">verde</span> las <span style="color:green;font-size:100%;">sugeridas</span> | En el modelo propuesto se identifican en <span style="color:red;font-size:100%;">rojo</span> las <span style="color:red;font-size:100%;">configuraciones obligatorias</span>, en <span style="color:orange;font-size:100%;">amarillo</span> las <span style="color:orange;font-size:100%;">optativas segun el caso de uso</span>, mientras que en <span style="color:green;font-size:100%;">verde</span> las <span style="color:green;font-size:100%;">sugeridas</span> |
</html> | </html> |
| {{ :initialization_soc.png?400 | Inicializacion del SoC}} |
En los apartados subsiguientes se detallan las configuraciones específicas de cada subetapa | En los apartados subsiguientes se detallan las configuraciones específicas de cada subetapa |
| |
==== mode set & interrupt disable==== | |
La primer acción que se debe realizar es garantizar que el procesador se encuentra en el modo y privilegio de operación que permita el acceso a los recursos del mismo.\ | <html><b><u><span style="color:red;font-size:150%;">mode set & interrupt disable</span></u></b></html> |
En ARMv7 este modo se denomina //Supervisor// normalmente se referencia como //svc//. Si bien por manual se especifica que este es el modo que el procesador arranca luego de un reinicio, se debe asegurarlo, para lo cual se emplean los 5 bits menos significativos del Current Program Status Register, denominados campo de modo (CPSR.M -> CPSR[4:0]). | |
| La primer acción que se debe realizar es garantizar que el procesador se encuentra en el modo y privilegio de operación que permita el acceso a los recursos del mismo.\\ |
| En ARMv7 este modo se denomina //Supervisor// normalmente se referencia como //svc//. Si bien por [[https://developer.arm.com/documentation/ddi0406/c/System-Level-Architecture/The-System-Level-Programmers--Model/Exception-descriptions/Reset | manual se especifica]] que este es el modo en el que el procesador arranca luego de un reinicio, se debe asegurarlo, para lo cual se emplean los 5 bits menos significativos del [[https://developer.arm.com/documentation/ddi0601/2022-12/AArch32-Registers/CPSR--Current-Program-Status-Register?lang=en | Current Program Status Register]], denominados campo de modo (CPSR.M -> CPSR[4:0]). |
Dado que el estado del SoC y sobre todo de los periféricos de la placa no es conocido, se debe evitar que algún estimulo externo perturbe la secuencia de inicialización, es decir se deben deshabilitar las interrupciones, que en el caso de ARMv7 son IRQ y FIQ.\ | Dado que el estado del SoC y sobre todo de los periféricos de la placa no es conocido, se debe evitar que algún estimulo externo perturbe la secuencia de inicialización, es decir se deben deshabilitar las interrupciones, que en el caso de ARMv7 son IRQ y FIQ.\ |
En el caso de ARMv7 la deshabilitación de las interrupciones se realiza con el mismo registro (CPSR.I -> CPSR[7], CPSR.F -> CPSR[6]) que se emplea para configurar el modo de operación por lo cual en un paso se realizan dos subetapas | En el caso de ARMv7 la deshabilitación de las interrupciones se realiza con el mismo registro (CPSR.I -> CPSR[7], CPSR.F -> CPSR[6]) que se emplea para configurar el modo de operación por lo cual en un paso se realizan dos subetapas |
<code asm> | <code asm> |
mrs r0, cpsr /* Move to general purpose Register a System register*/ | reset: @ En la explicación de exception set se comprenderá el motivo de este nombre |
bic r0, r0, #0x1f /* BItwise bit Clear*/ | mrs r0, cpsr @ Move to general purpose Register a System register |
orr r0, r0, #0xd3 /* OR bitwise 0xd3 -> 11010011 -> CPSR[76x43210]*/ | bic r0, r0, #0x1f @ BItwise bit Clear |
msr cpsr,r0 /* Move to System register a general purpose Register*/ | orr r0, r0, #0xd3 @ OR bitwise 0xd3 -> 11010011 -> CPSR[76x43210] |
| msr cpsr,r0 @ Move to System register a general purpose Register |
</code> | </code> |
| |
==== features get ==== | |
| <html><b><u><span style="color:green;font-size:150%;">features get</span></u></b></html> |
En implementaciones reales es una buena y muy recomendable práctica identificar las funcionalidades disponibles en el SoC. A tal fin se dispone del conjunto de [[https://developer.arm.com/documentation/ddi0403/d/System-Level-Architecture/The-CPUID-Scheme/About-the-CPUID-scheme/Summary-of-the-CPUID-registers | Registros CPUID]], los cuales deben ser accedidos mediante los registros del CoProcessor15 (CP15). Si bien no es necesario para los fines de la Cátedra, se brinda un ejemplo de lectura del mismo por ser una instrucción relativamente "criptica", para el caso del [[https://developer.arm.com/documentation/ddi0601/2023-03/AArch32-Registers/MIDR--Main-ID-Register?lang=en | Main Identifier Register]] | En implementaciones reales es una buena y muy recomendable práctica identificar las funcionalidades disponibles en el SoC. A tal fin se dispone del conjunto de [[https://developer.arm.com/documentation/ddi0403/d/System-Level-Architecture/The-CPUID-Scheme/About-the-CPUID-scheme/Summary-of-the-CPUID-registers | Registros CPUID]], los cuales deben ser accedidos mediante los registros del CoProcessor15 (CP15). Si bien no es necesario para los fines de la Cátedra, se brinda un ejemplo de lectura del mismo por ser una instrucción relativamente "criptica", para el caso del [[https://developer.arm.com/documentation/ddi0601/2023-03/AArch32-Registers/MIDR--Main-ID-Register?lang=en | Main Identifier Register]] |
<code asm> | <code asm> |
| |
| |
==== exception set ==== | <html><b><u><span style="color:orange;font-size:150%;">core configure</span></u></b></html> |
| |
| Si bien la mayoría de los registros se inicializan con valores coherentes y adecuados luego del reinicio del SoC, de forma tal que el programador se encuentre en un ambiente seguro para realizar la primer etapa de inicialización, existen ciertos casos donde se muy recomendable establecer configuraciones conocidas. El caso más emblemático son los indicadores de condición/estado del [[https://developer.arm.com/documentation/ddi0601/2022-12/AArch32-Registers/CPSR--Current-Program-Status-Register?lang=en | Current Program Status Register]] (CPSR.C -> CPSR[31:28]). |
| <code asm> |
| mrs r0, cpsr |
| bic r0, r0, #0xf0000000 /* BItwise bit Clear N, Z, C, V bits */ |
| msr cpsr,r0 |
| </code> |
| |
| |
| <html><u><b><span style="color:orange;font-size:150%;">rom copy</span></u></b></html> |
| |
| Antes comenzar con descripción de esta subetapa vale la pena responder algunas dudas razonables |
| === ¿Donde se debe copiar la ROM? === |
| La respuesta simple es a RAM, pero ¿como puede ser esto posible si aun no se ha inicializado el DCM?.\\ |
| Por lo general todo SoC dispone de una SRAM interna o la placa presenta una externa que no requiere configuración como es el caso del SMC, esto permite disponer de un espacio de memoria RAM pequeño pero suficiente para los fines de esta subetapa.\ |
| Para los casos de uso planteados disponemos del siguiente rango |
| ^ Board ^ Address range ^ Memory type ^ Memory type ^ |
| | PB-A8 |0x48000000-0x4BFFFFFF | 2MB | [[https://www.issi.com/us/product-cellular-ram.shtml | Cellular RAM ]] | |
| | Beagle |0x402F0400-0x402FFFFF | 63k | SRAM internal | |
| |
| === ¿Porqué se debe copiar de ROM a RAM? === |
| ¿Entre las razones más relevantes se pueden mencionar |
| * Velocidad de ejecución |
| * Requerimientos de alineación para el direccionamiento. Se debe recordar que para optimizar el uso de la ROM el código se consolida en forma consecutiva, eliminando en la medida de lo posible todo espacio entre secciones. |
| * Requerimientos de posicionar el código y datos en páginas y/o segmentos diferenciados |
| |
| === ¿Porqué no se puede copiar de ROM a la RAM del sistema? === |
| Como se mencionó anteriormente, principalmente porque el DMC no se encuentra inicializado, pero no solo se trata del DMC sino que todos los subsistemas asociados a la memoria deben estar correctamente configurados, como ser el AXI, el reloj, el PowerModuleController. Esto implica una mayor cantidad de operaciones en las cuales se puede dar una excepción, que recordemos que aun no se encuentran configuradas porque no se dispone de RAM, es decir nos encontraríamos en un bucle, se requiere RAM para disponer de pila para excepciones y llamada a funciones, pero el código para su configuración no se puede ejecutar porque la misma no esta inicializada. |
| \\ |
| |
| ---- |
| |
| Habiendo esbozado una explicación sobre las razones por las cuales es necesario realizar la copia de ROM (NOR, E2PROM) a RAM (SRAM, CELLRAM), se procede a brindar un ejemplo simple de función de copia que no requiere pila. El código brindado dista mucho de ser óptimo, para lo cual existe un sin numero de [[https://github.com/ARM-software/optimized-routines/tree/master/string/arm | referencias]], pero cumple su cometido. |
| <code asm> |
| ldr r0, _direccion_origen |
| ldr r1, _direccion_destino |
| ldr r2, _cuenta_doublewords |
| bl mem_cpy |
| |
| @ Opcion A con incremento de a double word |
| mem_cpy: |
| add r2, r2, r0 |
| slow_copy: |
| ldr r3, [r0], #4 @ r3=*( i n t * ) ( r0+0 ); r0 = r0+4 |
| str r3, [r1], #4 @ * ( i n t * ) ( r1+0 ) = r3 ; r1 = r1+4 |
| cmp r0, r2 |
| ble slow_copy |
| mov pc, lr |
| </code> |
| Empleando [[https://keleshev.com/ldm-my-favorite-arm-instruction/ | loadmultiple]] y [[https://azeria-labs.com/load-and-store-multiple-part-5/ | storemultiple]] |
| <code asm> |
| ldr r0, _direccion_origen |
| ldr r1, _direccion_destino |
| ldr r2, _cuenta_doublewords |
| bl mem_cpy |
| |
| @ Opcion B con incremento de a 8 double word veces (r3 a r10 |
| mem_cpy: |
| add r2, r2, r0 |
| fast_copy: |
| ldmia r0!, {r3 - r10} @ r3=*(int *) (r0); r0 = r0+4; r4=*(int *) (r0); r0 = r0+4; r5=*(int *) (r0); r0 = r0+4;...;r10=*(int * ) (r0); r0 = r0+4; |
| stmia r1!, {r3 - r10} @ *(int *) (r1) = r3; r1 = r1+4;*(int *) (r1) = r4; r1 = r1+4;*(int *) (r1) = r5; r1 = r1+4;...;*(int *) (r1) = r10; r1 = r1+4; |
| cmp r0, r2 |
| ble fast_copy |
| mov pc, lr |
| </code> |
| |
| <HTML> |
| <p style="border:4px dashed red;"><b><u><span style="color:black;font-size:120%;">Aclaracion </span></u></b> |
| <br> |
| La copia de ROM a RAM internas (SRAM, CellRAM) es un paso intermedio, necesario y casi obligatorio para inicializar la RAM del sistema en la mayoría de las placas.<br> |
| Si bien a los fines de la Cátedra para el caso de uso PB-A8, el tamaño de la CellRAM sería suficiente para implementar la guía de trabajos prácticos debe considerarse como un caso muy particular, observar que incluso en la caso de uso Beagle esto no sería posible.<br> |
| Lo expresado pone en evidencia la necesidad de inicializar el DCM, pero debido a la complejidad del mismo y por razones pedagógicas (la carga de aprendizaje es suficiente estableciendo el Short-descriptor translation table for small page es más que suficiente), se opta por aprovechar el recurso que provee el QEMU, presentando el espacio de memoria asociado a la DRAM ya disponible para su uso.</p> |
| </HTML> |
| |
| <html><b><u><span style="color:red;font-size:150%;">stack configure</span></u></b></html> |
| |
| Esta subetapa es una de las más sencillas, pero no por eso menos importante, ya que permite disponer de un entorno de memoria capaz de soportar la [[https://github.com/ARM-software/abi-aa/releases | ARM Architecture Procedure Call Standard]], que en forma simplificada implica que es posible ejecutar al menos código escrito en C. Esto no es un dato menor, ya que una buena parte (~ 70%) de las rutinas de configuración que implementa cada etapa puede ser reutilizable entre diferentes arquitecturas (ARMv7, ARMv8 e incluso Intel X86).\\ |
| La configuración de la pila no solo se trata de establecer adecuadamente el valor de [[https://developer.arm.com/documentation/dui0473/m/overview-of-the-arm-architecture/general-purpose-registers | R13 (SP)]], sino también de proveer una zona de memoria limpia para operar con él, entendiéndose por limpia con valores prohibidos de forma que un acceso erróneo pueda ser identificado. Esto último resulta útil en la mayoría de las arquitecturas previas a la ARMv8, ya que en las mismas no se encuentra implementada la protección por hardware de la pila, es decir que ni siquiera se tiene un control del tamaño de esta memoria para identificar si el SP excedió los límites, como si se hace en algunos [[https://developer.arm.com/documentation/100235/0004/the-cortex-m33-processor/programmer-s-model/core-registers?lang=en | SoC ARMv8 mediante MSPLIM]]. Esta técnica denominada [[https://en.wikipedia.org/wiki/Buffer_overflow_protection | El buchón de la pila]] [[https://ctf101.org/binary-exploitation/stack-canaries/#stack-canaries | o en inglés Stack Canaries]], presenta un sin número de variantes y su implementación excede al contenido requerido por esta Cátedra.\\ |
| Es importante mencionar que en un sistema real este procedimiento se debe repetir una vez inicializada la RAM del sistema.\\ |
| A los fines de la Cátedra, lo mínimo a realizar seria establecer el SP y garantizar que el rango asignado a la pila pueda ser escrito y leído correctamente. |
| <code asm> |
| stack_setup: |
| ldr r0, #CONFIG_PILA_LIMITE_DIRECCION |
| sub r0, r0, #(CONFIG_PILA_SVC_LARGO + CONFIG_PILA_IRQ_LARGO + CONFIG_PILA_FIQ_LARGO) |
| sub sp, r0, #12 @ 3 words para abort-stack |
| bic sp, sp, #7 @ 8-byte ajuste para satisfacer alineacion requerida por ABI |
| mov pc, lr |
| </code> |
| |
| <code asm> |
| ldr r0, #(CONFIG_PILA_LIMITE_DIRECCION - CONFIG_PILA_SVC_LARGO - CONFIG_PILA_IRQ_LARGO - CONFIG_PILA_FIQ_LARGO - 12) |
| bl stack_validate |
| |
| stack_validate: |
| ldr r2, =0xA5A5A5A5 |
| ldr r3, =0xA5A5A5A5 |
| ldr r4, =0xA5A5A5A5 |
| ldr r5, =0xA5A5A5A5 |
| ldr r6, =0xA5A5A5A5 |
| ldr r7, =0xA5A5A5A5 |
| ldr r8, =0xA5A5A5A5 |
| ldr r9, =0xA5A5A5A5 |
| ldr r10, =0xA5A5A5A5 |
| stack_write_fast: |
| sub r1, sp, #(CONFIG_PILA_LIMITE_DIRECCION - 36) |
| cmp r1, 0 |
| ble stack_write_slow |
| push {r3 - r10} |
| stack_write_slow: |
| push {r2} |
| cmp sp, r0 |
| bpl stack_write_fast |
| |
| stack_verify_fast: |
| sub r1, sp, #(CONFIG_PILA_LIMITE_DIRECCION - CONFIG_PILA_IRQ_LARGO - CONFIG_PILA_FIQ_LARGO - 36) |
| cmp r1, 0 |
| ble stack_verify_slow |
| pop {r3 - r10} |
| sub r1, r3, r4 |
| cmp r1, #0 |
| bne core_reset |
| sub r1, r5, r6 |
| cmp r1, #0 |
| bne core_reset |
| sub r1, r7, r8 |
| cmp r1, #0 |
| bne core_reset |
| sub r1, r9, r10 |
| cmp r1, #0 |
| bne core_reset |
| stack_verify_slow: |
| pop {r2} |
| cmp r2, #0xA5A5A5A5 |
| bne core_reset |
| cmp sp, r0 |
| ble stack_write_fast |
| mov pc, lr |
| </code> |
| |
| <html><b><u><span style="color:red;font-size:150%;">exception set</span></u></b></html> |
| |
| A fin de una correcta intepretación de lo que se indique y el código provisto en este apartado, es importante que el lector tenga un conocimento acabado de los [[https://developer.arm.com/documentation/den0013/d/ARM-Processor-Modes-and-Registers | modos de operación del procesador]], como así también los [[https://developer.arm.com/documentation/den0013/d/Exception-Handling/Types-of-exception?lang=en | tipos de excepción]]. |
| Como es bien sabido la [[https://developer.arm.com/documentation/den0013/d/Exception-Handling/Exception-priorities?lang=en#CEGHDCAE | tabla de vectores]] puede situarse a partir de la dirección base 0x0000000 (Normal) o 0xFFFF0000 (Superior). En los casos de uso que contemplados en este artículo se emplea la Normal. Nuevamente se debe recordar que tanto la tabla como las rutinas de atención a las excepciones se encuentran inicialmente en ROM y que deben ser copiadas a RAM, por este motivo es importante repasar el mapa de memoria de cada SoC |
| |
| |
| ==== Cortex A8 test chip ==== |
| La RAM dispone del rango 0x70000000-0x8FFFFFFF y la parte superior del mismo (256MB) se encuentra espejado en 0x00000000-0x0FFFFFFF. |
| Por su parte el [[https://developer.arm.com/documentation/dui0417/d/hardware-description/northbridge?lang=en | Northbridge]] también se encarga de [[https://developer.arm.com/documentation/dui0417/d/programmer-s-reference/configuration-and-initialization/remapping-of-boot-memory?lang=en | remapear]] la NOR de 0x40000000- 0x40FFFFFF a 0x00000000-0x00FFFFFF. |
| De los párrafos precedentes se desprende que este SoC permite el acceso a la [[https://developer.arm.com/documentation/den0013/d/Exception-Handling/Exception-priorities?lang=en#CEGHDCAE | tabla de vectores Normal]], pero es responsabilidad del ingeniero de software implementar la misma en esos dispositivos de memoria. |
| |
| ==== AM 335x ==== |
{{ :td3:under_construction.jpg?200 | En construccion}} | {{ :td3:under_construction.jpg?200 | En construccion}} |
| |
--- //[[cnigri@frba.utn.edu.ar|ChristiaN]] 2023/04/20 14:44// | Habiendo comprendido las restricciones de acceso a memoria específicas de cada uno de los casos de uso, se brinda a continuación el código básico de implementación de la [[https://developer.arm.com/documentation/den0013/d/Exception-Handling/Exception-priorities?lang=en#CEGHDCAE | tabla de vectores]], así como también el preámbulo y el epílogo de las excepciones estandar. |
| |
| El siguiente fragmento muestra las [[https://developer.arm.com/documentation/den0013/d/Exception-Handling/Exception-priorities/The-Vector-table | dos variantes para direccionar]],en la [[https://developer.arm.com/documentation/den0013/d/Exception-Handling/Exception-priorities?lang=en#CEGHDCAE | tabla de vectores]], el controlador de excepción: |
| * **b**: para bifurfaciones/saltos de hasta 32MB |
| * **ldr pc**: bifurfaciones sin restricciones de rango por fuera de la propia arquitectura |
| <code asm> |
| .global _start_generic |
| _start_generic: @ Etiqueta para referencia punto de entrada y tabla |
| b reset @ Configuracion de modo y deshabilitacion de interrupciones |
| ldr pc, _undefined_instruction |
| ldr pc, _software_interrupt |
| ldr pc, _prefetch_abort |
| ldr pc, _data_abort |
| nop @ No usado |
| ;En forma mas profesional se podria implementar ldr pc, _not_used donde se trata con preambulo y epilogo; |
| ldr pc, _irq |
| ldr pc, _fiq |
| </code> |
| |
| Una vez que la excepción es [[https://developer.arm.com/documentation/den0013/d/Exception-Handling/Exception-handling | manejada/vectorizada]] por el procesador, es decir se alcanza a la bifucarción correspondiente de la tabla precedente, es responsabilidad del desarrollador establecer la pila del modo de operación, resguardar la información que generó la excepción y establecer al procesador en modo Supervisor, esto se conoce como preambulo y a continuación se propone un ejemplo |
| |
| <code asm> |
| .align 5 |
| _undefined_instruction |
| ldr r13, #CONFIG_POR_MODE_PILA_LIMITE_DIRECCION |
| str lr, [r13] @ resguarda direccion de instruccion genero exepcion |
| mrs lr, spsr @ Move to Register lr from Special register spsr |
| str lr, [r13, #4] @ resguardo del State Program Status Register |
| mov r13, 0xd3 @ Prepara la conmutacion a modo Supervisor (xIQ deshabilitadas) |
| msr spsr, r13 |
| mov lr, pc |
| movs pc, lr @ Conmuta de modo |
| </code> |
| |
| En la excepciones _prefetch_abort y _data_abort el preambulo es equivalente, solo el valor de //**lr**//, referencia en el primer caso [[https://developer.arm.com/documentation/ddi0406/c/System-Level-Architecture/The-System-Level-Programmers--Model/Exception-descriptions/Prefetch-Abort-exception | sub lr, lr, #4 ]], mientras que en el segundo [[ https://developer.arm.com/documentation/ddi0406/c/System-Level-Architecture/The-System-Level-Programmers--Model/Exception-descriptions/Data-Abort-exception | sub lr, lr, #8]] |
| |
| El siguiente paso es preservar los registros //"no banqueados"// a fin de disponer de la información (foto de estado) completa que pudo producir la excepción, y recuperar de la pila del modo previo (Abort o Undef) los valores del **//lr//** y **//spsr//**. En pocas palabras se dispone de dos modos de operación que requieren acceder a la misma información, sin que se pierda en el acceso o la conmutación, siendo el recurso común/compartido la memoria. En SoC donde existe un procesador principal (proposito general) y otro dedicado (RealTime, Grafico, etc), la técnica de compartir memoria se suele llamar //carveaout// y emplearemos una variante para satisfacer el requerimiento planteado. |
| El concepto es simple, establecer un marco (no importa la posición absoluta de inicio) de referencia con desplazamientos bien definidos (relativos) |
| |
| <code asm> |
| #define REGISTER_SIZE 4 |
| #define FRAME_R0 0 |
| #define FRAME_R1 FRAME_R0 + REGISTER_SIZE @4 |
| #define FRAME_R2 FRAME_R1 + REGISTER_SIZE @8 |
| #define FRAME_R3 FRAME_R2 + REGISTER_SIZE @12 |
| #define FRAME_R4 FRAME_R3 + REGISTER_SIZE @16 |
| #define FRAME_R5 FRAME_R4 + REGISTER_SIZE @20 |
| #define FRAME_R6 FRAME_R5 + REGISTER_SIZE @24 |
| #define FRAME_R7 FRAME_R6 + REGISTER_SIZE @28 |
| #define FRAME_R8 FRAME_R7 + REGISTER_SIZE @32 |
| #define FRAME_R9 FRAME_R8 + REGISTER_SIZE @36 |
| #define FRAME_R10 FRAME_R9 + REGISTER_SIZE @40 |
| #define FRAME_FP FRAME_R10 + REGISTER_SIZE @44 |
| #define FRAME_IP FRAME_FP + REGISTER_SIZE @48 |
| #define FRAME_SP FRAME_IP + REGISTER_SIZE @52 |
| #define FRAME_LR FRAME_SP + REGISTER_SIZE @56 |
| #define FRAME_PC FRAME_LR + REGISTER_SIZE @60 |
| #define FRAME_PSR FRAME_PC + REGISTER_SIZE @64 |
| #define FRAME_R0_BCKP FRAME_PSR + REGISTER_SIZE @68 |
| #define FRAME_SIZE FRAME_R0_BCKP + FRAME_R0_BCKP @72 |
| </code> |
| |
| En código se puede emplear una macro equivalente a la siguiente propuesta |
| <code asm> |
| .macro pseudo_context_get |
| sub sp, sp, #FRAME_SIZE @ Posiciono el marco |
| stmia sp, {r0 - r12} @ resguarda r0-r12 en pila de SVC |
| ldr r2, #CONFIG_POR_MODE_PILA_LIMITE_DIRECCION |
| ldmia r2, {r2 - r3} @ recupera de pila de modo anterior lr y spsr |
| add r0, sp, #FRAME_SIZE @ reseguarda la pila original |
| add r5, sp, #FRAME_SP |
| mov r1, lr |
| stmia r5, {r0 - r3} @ resguarda sp y lr de SVC, y lr, spsr de modo anterior |
| mov r0, sp |
| .endm |
| </code> |
| |
| Esto permite implementar los controladores de excepción en C |
| |
| <code asm> |
| .align 5 |
| _prefetch_abort |
| ldr r13, #CONFIG_POR_MODE_PILA_LIMITE_DIRECCION |
| str lr, [r13] @ resguarda direccion de instruccion genero exepcion |
| mrs lr, spsr @ Move to Register lr from Special register spsr |
| str lr, [r13, #4] @ resguardo del State Program Status Register |
| mov r13, 0xd3 @ Prepara la conmutacion a modo Supervisor (xIQ deshabilitadas) |
| msr spsr, r13 |
| mov lr, pc |
| movs pc, lr @ Conmuta de modo |
| pseudo_context_get |
| bl prefetch_abort_handler |
| </code> |
| |
| Siendo el prototipo de la funcion en C acorde a [[https://github.com/ARM-software/abi-aa/releases | ARM Architecture Procedure Call Standard]] |
| <code c> |
| void prefetch_abort_handler(unsigned long *frame_ptr); |
| </code> |
| <html><b><u><span style="color:orange;font-size:150%;">core reset</span></u></b></html> |
| |
| En esta subetapa lo que se busca es reiniciar el SoC tras alguna configuración o estado irrecuperable por parte del software. |
| <code asm> |
| ;Caso de uso Beagle |
| core_reset: |
| ldr r1, #0x48180F00 |
| ldr r3, #0x1 |
| str r3, [r1] |
| mov r0, r0 |
| _reset_loop: |
| b _reset_loop |
| </code> |
| |
| --- //[[cnigri@frba.utn.edu.ar|ChristiaN]] 2024/05/17 11:17// |
| |