From 87a681736fdbfa8c9deb517bdcea019f856d6a33 Mon Sep 17 00:00:00 2001 From: Philippe Thierry Date: Tue, 18 Sep 2018 15:09:09 +0200 Subject: [PATCH] Initial commit --- .gitignore | 13 + Ada/c-kernel.ads | 42 + Ada/c-socinfo.ads | 74 ++ Ada/c.ads | 35 + Ada/config.def | 1 + Ada/debug.adb | 73 ++ Ada/debug.ads | 39 + Ada/ewok-devices-interfaces.adb | 33 + Ada/ewok-devices-interfaces.ads | 34 + Ada/ewok-devices.adb | 621 ++++++++++++++ Ada/ewok-devices.ads | 111 +++ Ada/ewok-devices_shared.ads | 47 ++ Ada/ewok-dma-interfaces.adb | 57 ++ Ada/ewok-dma-interfaces.ads | 37 + Ada/ewok-dma.adb | 639 +++++++++++++++ Ada/ewok-dma.ads | 112 +++ Ada/ewok-dma_shared.ads | 32 + Ada/ewok-exti-handler.adb | 195 +++++ Ada/ewok-exti-handler.ads | 33 + Ada/ewok-exti-interfaces.adb | 34 + Ada/ewok-exti-interfaces.ads | 34 + Ada/ewok-exti.adb | 144 ++++ Ada/ewok-exti.ads | 63 ++ Ada/ewok-gpio.adb | 218 +++++ Ada/ewok-gpio.ads | 84 ++ Ada/ewok-interrupts-handler.adb | 185 +++++ Ada/ewok-interrupts-handler.ads | 41 + Ada/ewok-interrupts-interfaces.adb | 34 + Ada/ewok-interrupts-interfaces.ads | 34 + Ada/ewok-interrupts.adb | 136 ++++ Ada/ewok-interrupts.ads | 89 ++ Ada/ewok-ipc.adb | 115 +++ Ada/ewok-ipc.ads | 111 +++ Ada/ewok-isr.adb | 90 ++ Ada/ewok-isr.ads | 37 + Ada/ewok-layout.ads | 187 +++++ Ada/ewok-mpu-handler.adb | 111 +++ Ada/ewok-mpu-handler.ads | 36 + Ada/ewok-mpu-interfaces.adb | 41 + Ada/ewok-mpu-interfaces.ads | 35 + Ada/ewok-mpu.adb | 335 ++++++++ Ada/ewok-mpu.ads | 92 +++ Ada/ewok-perm.adb | 156 ++++ Ada/ewok-perm.ads | 138 ++++ Ada/ewok-posthook.adb | 217 +++++ Ada/ewok-posthook.ads | 38 + Ada/ewok-sanitize.adb | 215 +++++ Ada/ewok-sanitize.ads | 107 +++ Ada/ewok-sched-interfaces.adb | 34 + Ada/ewok-sched-interfaces.ads | 33 + Ada/ewok-sched.adb | 606 ++++++++++++++ Ada/ewok-sched.ads | 56 ++ Ada/ewok-sleep.adb | 95 +++ Ada/ewok-sleep.ads | 106 +++ Ada/ewok-softirq.adb | 394 +++++++++ Ada/ewok-softirq.ads | 89 ++ Ada/ewok-syscalls-handler.adb | 300 +++++++ Ada/ewok-syscalls-handler.ads | 30 + Ada/ewok-syscalls.ads | 95 +++ Ada/ewok-tasks.adb | 552 +++++++++++++ Ada/ewok-tasks.ads | 253 ++++++ Ada/ewok-tasks_shared.ads | 61 ++ Ada/ewok.ads | 61 ++ Ada/exported/config.def | 1 + Ada/exported/ewok-exported-devices.ads | 62 ++ Ada/exported/ewok-exported-dma.ads | 86 ++ Ada/exported/ewok-exported-gpios.ads | 96 +++ Ada/exported/ewok-exported-interrupts.ads | 111 +++ Ada/exported/ewok-exported-sleep.ads | 32 + Ada/exported/ewok-exported-ticks.ads | 33 + Ada/exported/ewok-exported.ads | 25 + Ada/generated/.placeholder | 0 Ada/libgnat/Makefile | 33 + Ada/libgnat/gnat.gpr | 35 + Ada/libgnat/gnat/ada.ads | 1 + Ada/libgnat/gnat/gnat.ads | 1 + Ada/libgnat/gnat/last_chance_handler.c | 12 + Ada/libgnat/gnat/link_list.txt | 10 + Ada/libgnat/gnat/s-imguns.adb | 43 + Ada/processor.adb | 35 + Ada/processor.ads | 37 + Ada/rings.adb | 144 ++++ Ada/rings.ads | 77 ++ Ada/syscalls/config.def | 1 + Ada/syscalls/ewok-syscalls-cfg-gpio.adb | 134 +++ Ada/syscalls/ewok-syscalls-cfg-gpio.ads | 38 + Ada/syscalls/ewok-syscalls-cfg-mem.adb | 263 ++++++ Ada/syscalls/ewok-syscalls-cfg-mem.ads | 38 + Ada/syscalls/ewok-syscalls-cfg.adb | 73 ++ Ada/syscalls/ewok-syscalls-cfg.ads | 34 + Ada/syscalls/ewok-syscalls-dma.adb | 408 ++++++++++ Ada/syscalls/ewok-syscalls-dma.ads | 55 ++ Ada/syscalls/ewok-syscalls-gettick.adb | 110 +++ Ada/syscalls/ewok-syscalls-gettick.ads | 34 + Ada/syscalls/ewok-syscalls-init.adb | 280 +++++++ Ada/syscalls/ewok-syscalls-init.ads | 52 ++ Ada/syscalls/ewok-syscalls-ipc.adb | 768 ++++++++++++++++++ Ada/syscalls/ewok-syscalls-ipc.ads | 53 ++ Ada/syscalls/ewok-syscalls-lock.adb | 61 ++ Ada/syscalls/ewok-syscalls-lock.ads | 37 + Ada/syscalls/ewok-syscalls-reset.adb | 52 ++ Ada/syscalls/ewok-syscalls-reset.ads | 33 + Ada/syscalls/ewok-syscalls-sleep.adb | 73 ++ Ada/syscalls/ewok-syscalls-sleep.ads | 34 + Ada/syscalls/ewok-syscalls-yield.adb | 49 ++ Ada/syscalls/ewok-syscalls-yield.ads | 34 + Kconfig | 265 ++++++ LICENSE | 201 +++++ Makefile | 205 +++++ Makefile.objs | 16 + NOTICE | 13 + arch/Ada/config.def | 1 + arch/Ada/types-c.adb | 44 + arch/Ada/types-c.ads | 39 + arch/Ada/types.adb | 35 + arch/Ada/types.ads | 105 +++ arch/Ada/unsafe_types.ads | 13 + arch/Kconfig | 181 +++++ arch/Makefile | 190 +++++ arch/README.md | 34 + arch/auto.cgpr | 17 + arch/boards/32f407discovery/Kconfig | 3 + arch/boards/32f407discovery/Makefile.objs | 0 arch/boards/32f407discovery/buttons.h | 29 + arch/boards/32f407discovery/disco.h | 33 + arch/boards/32f407discovery/leds.h | 39 + arch/boards/32f407discovery/params.h | 72 ++ arch/boards/32f407discovery/product.h | 55 ++ arch/boards/32f429discovery/Kconfig | 3 + arch/boards/32f429discovery/Makefile.objs | 0 arch/boards/32f429discovery/buttons.h | 29 + arch/boards/32f429discovery/disco.h | 33 + arch/boards/32f429discovery/leds.h | 39 + arch/boards/32f429discovery/params.h | 72 ++ arch/boards/32f429discovery/product.h | 55 ++ arch/boards/Makefile.objs | 14 + arch/boards/boards.h | 34 + arch/boards/shared.c | 54 ++ arch/boards/shared.h | 57 ++ arch/boards/wookey/Kconfig | 3 + arch/boards/wookey/Makefile.objs | 0 arch/boards/wookey/buttons.h | 28 + arch/boards/wookey/leds.h | 34 + arch/boards/wookey/params.h | 72 ++ arch/boards/wookey/product.h | 54 ++ arch/cores/armv7-m/Ada/config.def | 1 + .../cores/armv7-m/Ada/m4-cpu-instructions.adb | 96 +++ .../cores/armv7-m/Ada/m4-cpu-instructions.ads | 64 ++ arch/cores/armv7-m/Ada/m4-cpu.adb | 185 +++++ arch/cores/armv7-m/Ada/m4-cpu.ads | 217 +++++ arch/cores/armv7-m/Ada/m4-layout.ads | 41 + arch/cores/armv7-m/Ada/m4-mpu.adb | 126 +++ arch/cores/armv7-m/Ada/m4-mpu.ads | 313 +++++++ arch/cores/armv7-m/Ada/m4-scb.adb | 44 + arch/cores/armv7-m/Ada/m4-scb.ads | 347 ++++++++ arch/cores/armv7-m/Ada/m4-systick.adb | 95 +++ arch/cores/armv7-m/Ada/m4-systick.ads | 170 ++++ arch/cores/armv7-m/Ada/m4.ads | 37 + arch/cores/armv7-m/Makefile.objs | 25 + arch/cores/armv7-m/m4-core.h | 48 ++ arch/cores/armv7-m/m4-cpu.h | 203 +++++ arch/cores/armv7-m/m4-fpu.c | 125 +++ arch/cores/armv7-m/m4-fpu.h | 83 ++ arch/cores/armv7-m/m4-mpu-regions.h | 80 ++ arch/cores/armv7-m/m4-mpu.c | 206 +++++ arch/cores/armv7-m/m4-mpu.h | 180 ++++ arch/cores/armv7-m/m4-svc.h | 52 ++ arch/cores/armv7-m/m4-systick-regs.h | 111 +++ arch/cores/armv7-m/m4-systick.c | 59 ++ arch/cores/armv7-m/m4-systick.h | 54 ++ arch/cores/armv7-m/types.h | 66 ++ arch/debug.c | 226 ++++++ arch/debug.h | 108 +++ arch/get_random.c | 59 ++ arch/get_random.h | 8 + arch/libabsp.adc | 4 + arch/libabsp.gpr | 50 ++ arch/libc.c | 127 +++ arch/libc.h | 24 + arch/socs/stm32f407/Ada/config.def | 1 + arch/socs/stm32f407/Ada/default_handlers.adb | 1 + arch/socs/stm32f407/Ada/default_handlers.ads | 1 + arch/socs/stm32f407/Ada/soc-devmap.ads.DRAFT | 1 + .../socs/stm32f407/Ada/soc-dma-interfaces.adb | 1 + .../socs/stm32f407/Ada/soc-dma-interfaces.ads | 1 + arch/socs/stm32f407/Ada/soc-dma.adb | 1 + arch/socs/stm32f407/Ada/soc-dma.ads | 1 + .../socs/stm32f407/Ada/soc-dwt-interfaces.adb | 1 + .../socs/stm32f407/Ada/soc-dwt-interfaces.ads | 1 + arch/socs/stm32f407/Ada/soc-dwt.adb | 1 + arch/socs/stm32f407/Ada/soc-dwt.ads | 1 + arch/socs/stm32f407/Ada/soc-exti.adb | 1 + arch/socs/stm32f407/Ada/soc-exti.ads | 1 + .../stm32f407/Ada/soc-gpio-interfaces.adb | 1 + .../stm32f407/Ada/soc-gpio-interfaces.ads | 1 + arch/socs/stm32f407/Ada/soc-gpio.adb | 1 + arch/socs/stm32f407/Ada/soc-gpio.ads | 1 + arch/socs/stm32f407/Ada/soc-interrupts.adb | 1 + arch/socs/stm32f407/Ada/soc-interrupts.ads | 1 + .../socs/stm32f407/Ada/soc-layout-stm32f4.ads | 1 + .../stm32f407/Ada/soc-layout-stm32f42x.ads | 1 + arch/socs/stm32f407/Ada/soc-layout.ads | 106 +++ arch/socs/stm32f407/Ada/soc-nvic.adb | 1 + arch/socs/stm32f407/Ada/soc-nvic.ads | 1 + arch/socs/stm32f407/Ada/soc-rcc.adb.DRAFT | 1 + arch/socs/stm32f407/Ada/soc-rcc.ads | 1 + arch/socs/stm32f407/Ada/soc-syscfg.adb | 1 + arch/socs/stm32f407/Ada/soc-syscfg.ads | 1 + arch/socs/stm32f407/Ada/soc.ads | 1 + arch/socs/stm32f407/Kconfig | 1 + arch/socs/stm32f407/Makefile.objs | 45 + arch/socs/stm32f407/default_handlers.c | 1 + arch/socs/stm32f407/default_handlers.h | 1 + arch/socs/stm32f407/fw1.ld.in | 1 + arch/socs/stm32f407/fw2.ld.in | 1 + arch/socs/stm32f407/postpone.c | 1 + arch/socs/stm32f407/soc-core.h | 1 + arch/socs/stm32f407/soc-devmap.c | 1 + arch/socs/stm32f407/soc-devmap.h | 1 + arch/socs/stm32f407/soc-dma.c | 1 + arch/socs/stm32f407/soc-dma.h | 1 + arch/socs/stm32f407/soc-dma_regs.h | 1 + arch/socs/stm32f407/soc-dwt.c | 1 + arch/socs/stm32f407/soc-dwt.h | 1 + arch/socs/stm32f407/soc-exti.c | 1 + arch/socs/stm32f407/soc-exti.h | 1 + arch/socs/stm32f407/soc-flash.h | 1 + arch/socs/stm32f407/soc-gpio.c | 1 + arch/socs/stm32f407/soc-gpio.h | 1 + arch/socs/stm32f407/soc-init.c | 1 + arch/socs/stm32f407/soc-init.h | 1 + arch/socs/stm32f407/soc-interrupts.c | 1 + arch/socs/stm32f407/soc-interrupts.h | 1 + arch/socs/stm32f407/soc-iwdg.c | 1 + arch/socs/stm32f407/soc-iwdg.h | 1 + arch/socs/stm32f407/soc-layout.h | 173 ++++ arch/socs/stm32f407/soc-nvic.h | 1 + arch/socs/stm32f407/soc-pwr.h | 1 + arch/socs/stm32f407/soc-rcc.c | 1 + arch/socs/stm32f407/soc-rcc.h | 1 + arch/socs/stm32f407/soc-rng.c | 1 + arch/socs/stm32f407/soc-rng.h | 1 + arch/socs/stm32f407/soc-scb.h | 1 + arch/socs/stm32f407/soc-syscfg.h | 1 + arch/socs/stm32f407/soc-usart-regs.h | 1 + arch/socs/stm32f407/soc-usart.c | 1 + arch/socs/stm32f407/soc-usart.h | 1 + arch/socs/stm32f407/startup_stm32f407.s | 330 ++++++++ arch/socs/stm32f429/Ada/config.def | 1 + arch/socs/stm32f429/Ada/default_handlers.adb | 1 + arch/socs/stm32f429/Ada/default_handlers.ads | 1 + arch/socs/stm32f429/Ada/soc-devmap.ads.DRAFT | 1 + .../socs/stm32f429/Ada/soc-dma-interfaces.adb | 1 + .../socs/stm32f429/Ada/soc-dma-interfaces.ads | 1 + arch/socs/stm32f429/Ada/soc-dma.adb | 1 + arch/socs/stm32f429/Ada/soc-dma.ads | 1 + .../socs/stm32f429/Ada/soc-dwt-interfaces.adb | 1 + .../socs/stm32f429/Ada/soc-dwt-interfaces.ads | 1 + arch/socs/stm32f429/Ada/soc-dwt.adb | 1 + arch/socs/stm32f429/Ada/soc-dwt.ads | 1 + arch/socs/stm32f429/Ada/soc-exti.adb | 1 + arch/socs/stm32f429/Ada/soc-exti.ads | 1 + .../stm32f429/Ada/soc-gpio-interfaces.adb | 1 + .../stm32f429/Ada/soc-gpio-interfaces.ads | 1 + arch/socs/stm32f429/Ada/soc-gpio.adb | 1 + arch/socs/stm32f429/Ada/soc-gpio.ads | 1 + arch/socs/stm32f429/Ada/soc-interrupts.adb | 1 + arch/socs/stm32f429/Ada/soc-interrupts.ads | 1 + .../socs/stm32f429/Ada/soc-layout-stm32f4.ads | 1 + .../stm32f429/Ada/soc-layout-stm32f42x.ads | 1 + arch/socs/stm32f429/Ada/soc-layout.ads | 83 ++ arch/socs/stm32f429/Ada/soc-nvic.adb | 1 + arch/socs/stm32f429/Ada/soc-nvic.ads | 1 + arch/socs/stm32f429/Ada/soc-rcc.adb.DRAFT | 1 + arch/socs/stm32f429/Ada/soc-rcc.ads | 1 + arch/socs/stm32f429/Ada/soc-syscfg.adb | 1 + arch/socs/stm32f429/Ada/soc-syscfg.ads | 1 + arch/socs/stm32f429/Ada/soc.ads | 1 + arch/socs/stm32f429/Kconfig | 1 + arch/socs/stm32f429/Makefile.objs | 45 + arch/socs/stm32f429/default_handlers.c | 1 + arch/socs/stm32f429/default_handlers.h | 1 + arch/socs/stm32f429/fw1.ld.in | 1 + arch/socs/stm32f429/fw2.ld.in | 1 + arch/socs/stm32f429/postpone.c | 1 + arch/socs/stm32f429/soc-core.h | 1 + arch/socs/stm32f429/soc-devmap.c | 1 + arch/socs/stm32f429/soc-devmap.h | 1 + arch/socs/stm32f429/soc-dma.c | 1 + arch/socs/stm32f429/soc-dma.h | 1 + arch/socs/stm32f429/soc-dma_regs.h | 1 + arch/socs/stm32f429/soc-dwt.c | 1 + arch/socs/stm32f429/soc-dwt.h | 1 + arch/socs/stm32f429/soc-exti.c | 1 + arch/socs/stm32f429/soc-exti.h | 1 + arch/socs/stm32f429/soc-flash.h | 1 + arch/socs/stm32f429/soc-gpio.c | 1 + arch/socs/stm32f429/soc-gpio.h | 1 + arch/socs/stm32f429/soc-init.c | 1 + arch/socs/stm32f429/soc-init.h | 1 + arch/socs/stm32f429/soc-interrupts.c | 1 + arch/socs/stm32f429/soc-interrupts.h | 1 + arch/socs/stm32f429/soc-iwdg.c | 1 + arch/socs/stm32f429/soc-iwdg.h | 1 + arch/socs/stm32f429/soc-layout.h | 178 ++++ arch/socs/stm32f429/soc-nvic.h | 1 + arch/socs/stm32f429/soc-pwr.h | 1 + arch/socs/stm32f429/soc-rcc.c | 1 + arch/socs/stm32f429/soc-rcc.h | 1 + arch/socs/stm32f429/soc-rng.c | 1 + arch/socs/stm32f429/soc-rng.h | 1 + arch/socs/stm32f429/soc-scb.h | 1 + arch/socs/stm32f429/soc-syscfg.h | 1 + arch/socs/stm32f429/soc-usart-regs.h | 1 + arch/socs/stm32f429/soc-usart.c | 1 + arch/socs/stm32f429/soc-usart.h | 1 + arch/socs/stm32f429/startup_stm32f429.s | 321 ++++++++ arch/socs/stm32f439/Ada/.placeholder | 0 arch/socs/stm32f439/Ada/config.def | 1 + arch/socs/stm32f439/Ada/default_handlers.adb | 31 + arch/socs/stm32f439/Ada/default_handlers.ads | 29 + arch/socs/stm32f439/Ada/soc-devmap.ads.DRAFT | 70 ++ .../socs/stm32f439/Ada/soc-dma-interfaces.adb | 353 ++++++++ .../socs/stm32f439/Ada/soc-dma-interfaces.ads | 124 +++ arch/socs/stm32f439/Ada/soc-dma.adb | 189 +++++ arch/socs/stm32f439/Ada/soc-dma.ads | 414 ++++++++++ .../socs/stm32f439/Ada/soc-dwt-interfaces.adb | 53 ++ .../socs/stm32f439/Ada/soc-dwt-interfaces.ads | 44 + arch/socs/stm32f439/Ada/soc-dwt.adb | 177 ++++ arch/socs/stm32f439/Ada/soc-dwt.ads | 356 ++++++++ arch/socs/stm32f439/Ada/soc-exti.adb | 78 ++ arch/socs/stm32f439/Ada/soc-exti.ads | 184 +++++ .../stm32f439/Ada/soc-gpio-interfaces.adb | 60 ++ .../stm32f439/Ada/soc-gpio-interfaces.ads | 44 + arch/socs/stm32f439/Ada/soc-gpio.adb | 88 ++ arch/socs/stm32f439/Ada/soc-gpio.ads | 318 ++++++++ arch/socs/stm32f439/Ada/soc-interrupts.adb | 37 + arch/socs/stm32f439/Ada/soc-interrupts.ads | 158 ++++ .../socs/stm32f439/Ada/soc-layout-stm32f4.ads | 30 + .../stm32f439/Ada/soc-layout-stm32f42x.ads | 34 + arch/socs/stm32f439/Ada/soc-layout.ads | 105 +++ arch/socs/stm32f439/Ada/soc-nvic.adb | 60 ++ arch/socs/stm32f439/Ada/soc-nvic.ads | 235 ++++++ arch/socs/stm32f439/Ada/soc-rcc.adb.DRAFT | 154 ++++ arch/socs/stm32f439/Ada/soc-rcc.ads | 225 +++++ arch/socs/stm32f439/Ada/soc-syscfg.adb | 66 ++ arch/socs/stm32f439/Ada/soc-syscfg.ads | 173 ++++ arch/socs/stm32f439/Ada/soc.ads | 38 + arch/socs/stm32f439/Kconfig | 0 arch/socs/stm32f439/Makefile.objs | 43 + arch/socs/stm32f439/default_handlers.c | 184 +++++ arch/socs/stm32f439/default_handlers.h | 33 + arch/socs/stm32f439/fw1.ld.in | 134 +++ arch/socs/stm32f439/fw2.ld.in | 126 +++ arch/socs/stm32f439/postpone.c | 34 + arch/socs/stm32f439/soc-core.h | 143 ++++ arch/socs/stm32f439/soc-devmap.c | 55 ++ arch/socs/stm32f439/soc-devmap.h | 158 ++++ arch/socs/stm32f439/soc-dma.c | 443 ++++++++++ arch/socs/stm32f439/soc-dma.h | 89 ++ arch/socs/stm32f439/soc-dma_regs.h | 208 +++++ arch/socs/stm32f439/soc-dwt.c | 83 ++ arch/socs/stm32f439/soc-dwt.h | 45 + arch/socs/stm32f439/soc-exti.c | 369 +++++++++ arch/socs/stm32f439/soc-exti.h | 89 ++ arch/socs/stm32f439/soc-flash.h | 282 +++++++ arch/socs/stm32f439/soc-gpio.c | 231 ++++++ arch/socs/stm32f439/soc-gpio.h | 370 +++++++++ arch/socs/stm32f439/soc-init.c | 71 ++ arch/socs/stm32f439/soc-init.h | 45 + arch/socs/stm32f439/soc-interrupts.c | 196 +++++ arch/socs/stm32f439/soc-interrupts.h | 175 ++++ arch/socs/stm32f439/soc-iwdg.c | 64 ++ arch/socs/stm32f439/soc-iwdg.h | 59 ++ arch/socs/stm32f439/soc-layout.h | 226 ++++++ arch/socs/stm32f439/soc-nvic.h | 247 ++++++ arch/socs/stm32f439/soc-pwr.h | 80 ++ arch/socs/stm32f439/soc-rcc.c | 132 +++ arch/socs/stm32f439/soc-rcc.h | 751 +++++++++++++++++ arch/socs/stm32f439/soc-rng.c | 177 ++++ arch/socs/stm32f439/soc-rng.h | 60 ++ arch/socs/stm32f439/soc-scb.h | 426 ++++++++++ arch/socs/stm32f439/soc-syscfg.h | 39 + arch/socs/stm32f439/soc-usart-regs.h | 433 ++++++++++ arch/socs/stm32f439/soc-usart.c | 436 ++++++++++ arch/socs/stm32f439/soc-usart.h | 240 ++++++ arch/socs/stm32f439/startup_stm32f439.s | 321 ++++++++ arch/stack_check.c | 54 ++ arch/stack_check.h | 28 + arch/usb_device.h | 46 ++ devices-shared.h | 48 ++ devices.c | 556 +++++++++++++ devices.h | 164 ++++ dma-shared.h | 50 ++ dma.c | 553 +++++++++++++ dma.h | 200 +++++ exported/devices.h | 111 +++ exported/dmas.h | 171 ++++ exported/gpio.h | 230 ++++++ exported/irq.h | 165 ++++ exported/sleep.h | 32 + exported/syscalls.h | 146 ++++ exti-handler.c | 168 ++++ exti-handler.h | 49 ++ exti.c | 82 ++ exti.h | 38 + generated/.placehorder | 0 gnatprep.def | 1 + gpio.c | 281 +++++++ gpio.h | 86 ++ init.c | 231 ++++++ ipc.c | 63 ++ ipc.h | 67 ++ isr.c | 88 ++ isr.h | 16 + kernel.dfu1.ld.in | 107 +++ kernel.dfu2.ld.in | 107 +++ kernel.fw1.ld.in | 107 +++ kernel.fw2.ld.in | 107 +++ kernel.h | 54 ++ kernel.ld.in | 1 + layout.h | 46 ++ libabsp.adc | 4 + libabsp.gpr | 52 ++ libkernel.adc | 3 + libkernel.gpr | 123 +++ mpu-handler.c | 83 ++ mpu.c | 244 ++++++ mpu.h | 68 ++ perm.c | 289 +++++++ perm.h | 116 +++ posthook.c | 186 +++++ posthook.h | 34 + processor.h | 35 + prove/Makefile | 25 + prove/README.md | 46 ++ prove/gnatprep.def | 1 + prove/prove.gpr | 32 + prove/target.atp | 28 + regutils.h | 250 ++++++ sanitize.c | 181 +++++ sanitize.h | 115 +++ sched.c | 615 ++++++++++++++ sched.h | 25 + shared/ipc.h | 2 + sleep.c | 113 +++ sleep.h | 100 +++ softirq.c | 405 +++++++++ softirq.h | 31 + syscalls-handler.c | 259 ++++++ syscalls/syscalls-cfg-gpio.c | 102 +++ syscalls/syscalls-cfg-gpio.h | 32 + syscalls/syscalls-cfg-mem.c | 182 +++++ syscalls/syscalls-cfg-mem.h | 39 + syscalls/syscalls-cfg.c | 113 +++ syscalls/syscalls-cfg.h | 57 ++ syscalls/syscalls-dma.c | 327 ++++++++ syscalls/syscalls-dma.h | 46 ++ syscalls/syscalls-gettick.c | 84 ++ syscalls/syscalls-gettick.h | 36 + syscalls/syscalls-init.c | 289 +++++++ syscalls/syscalls-init.h | 49 ++ syscalls/syscalls-ipc.c | 553 +++++++++++++ syscalls/syscalls-ipc.h | 30 + syscalls/syscalls-lock.c | 74 ++ syscalls/syscalls-lock.h | 33 + syscalls/syscalls-reset.c | 41 + syscalls/syscalls-reset.h | 40 + syscalls/syscalls-sleep.c | 57 ++ syscalls/syscalls-sleep.h | 31 + syscalls/syscalls-utils.h | 77 ++ syscalls/syscalls-yield.c | 55 ++ syscalls/syscalls-yield.h | 39 + syscalls/syscalls.h | 50 ++ tasks-shared.h | 31 + tasks.c | 406 +++++++++ tasks.h | 270 ++++++ types.h | 34 + usart.c | 92 +++ usart.h | 29 + 480 files changed, 41195 insertions(+) create mode 100644 .gitignore create mode 100644 Ada/c-kernel.ads create mode 100644 Ada/c-socinfo.ads create mode 100644 Ada/c.ads create mode 120000 Ada/config.def create mode 100644 Ada/debug.adb create mode 100644 Ada/debug.ads create mode 100644 Ada/ewok-devices-interfaces.adb create mode 100644 Ada/ewok-devices-interfaces.ads create mode 100644 Ada/ewok-devices.adb create mode 100644 Ada/ewok-devices.ads create mode 100644 Ada/ewok-devices_shared.ads create mode 100644 Ada/ewok-dma-interfaces.adb create mode 100644 Ada/ewok-dma-interfaces.ads create mode 100644 Ada/ewok-dma.adb create mode 100644 Ada/ewok-dma.ads create mode 100644 Ada/ewok-dma_shared.ads create mode 100644 Ada/ewok-exti-handler.adb create mode 100644 Ada/ewok-exti-handler.ads create mode 100644 Ada/ewok-exti-interfaces.adb create mode 100644 Ada/ewok-exti-interfaces.ads create mode 100644 Ada/ewok-exti.adb create mode 100644 Ada/ewok-exti.ads create mode 100644 Ada/ewok-gpio.adb create mode 100644 Ada/ewok-gpio.ads create mode 100644 Ada/ewok-interrupts-handler.adb create mode 100644 Ada/ewok-interrupts-handler.ads create mode 100644 Ada/ewok-interrupts-interfaces.adb create mode 100644 Ada/ewok-interrupts-interfaces.ads create mode 100644 Ada/ewok-interrupts.adb create mode 100644 Ada/ewok-interrupts.ads create mode 100644 Ada/ewok-ipc.adb create mode 100644 Ada/ewok-ipc.ads create mode 100644 Ada/ewok-isr.adb create mode 100644 Ada/ewok-isr.ads create mode 100644 Ada/ewok-layout.ads create mode 100644 Ada/ewok-mpu-handler.adb create mode 100644 Ada/ewok-mpu-handler.ads create mode 100644 Ada/ewok-mpu-interfaces.adb create mode 100644 Ada/ewok-mpu-interfaces.ads create mode 100644 Ada/ewok-mpu.adb create mode 100644 Ada/ewok-mpu.ads create mode 100644 Ada/ewok-perm.adb create mode 100644 Ada/ewok-perm.ads create mode 100644 Ada/ewok-posthook.adb create mode 100644 Ada/ewok-posthook.ads create mode 100644 Ada/ewok-sanitize.adb create mode 100644 Ada/ewok-sanitize.ads create mode 100644 Ada/ewok-sched-interfaces.adb create mode 100644 Ada/ewok-sched-interfaces.ads create mode 100644 Ada/ewok-sched.adb create mode 100644 Ada/ewok-sched.ads create mode 100644 Ada/ewok-sleep.adb create mode 100644 Ada/ewok-sleep.ads create mode 100644 Ada/ewok-softirq.adb create mode 100644 Ada/ewok-softirq.ads create mode 100644 Ada/ewok-syscalls-handler.adb create mode 100644 Ada/ewok-syscalls-handler.ads create mode 100644 Ada/ewok-syscalls.ads create mode 100644 Ada/ewok-tasks.adb create mode 100644 Ada/ewok-tasks.ads create mode 100644 Ada/ewok-tasks_shared.ads create mode 100644 Ada/ewok.ads create mode 120000 Ada/exported/config.def create mode 100644 Ada/exported/ewok-exported-devices.ads create mode 100644 Ada/exported/ewok-exported-dma.ads create mode 100644 Ada/exported/ewok-exported-gpios.ads create mode 100644 Ada/exported/ewok-exported-interrupts.ads create mode 100644 Ada/exported/ewok-exported-sleep.ads create mode 100644 Ada/exported/ewok-exported-ticks.ads create mode 100644 Ada/exported/ewok-exported.ads create mode 100644 Ada/generated/.placeholder create mode 100644 Ada/libgnat/Makefile create mode 100644 Ada/libgnat/gnat.gpr create mode 120000 Ada/libgnat/gnat/ada.ads create mode 120000 Ada/libgnat/gnat/gnat.ads create mode 100644 Ada/libgnat/gnat/last_chance_handler.c create mode 100644 Ada/libgnat/gnat/link_list.txt create mode 100644 Ada/libgnat/gnat/s-imguns.adb create mode 100644 Ada/processor.adb create mode 100644 Ada/processor.ads create mode 100644 Ada/rings.adb create mode 100644 Ada/rings.ads create mode 120000 Ada/syscalls/config.def create mode 100644 Ada/syscalls/ewok-syscalls-cfg-gpio.adb create mode 100644 Ada/syscalls/ewok-syscalls-cfg-gpio.ads create mode 100644 Ada/syscalls/ewok-syscalls-cfg-mem.adb create mode 100644 Ada/syscalls/ewok-syscalls-cfg-mem.ads create mode 100644 Ada/syscalls/ewok-syscalls-cfg.adb create mode 100644 Ada/syscalls/ewok-syscalls-cfg.ads create mode 100644 Ada/syscalls/ewok-syscalls-dma.adb create mode 100644 Ada/syscalls/ewok-syscalls-dma.ads create mode 100644 Ada/syscalls/ewok-syscalls-gettick.adb create mode 100644 Ada/syscalls/ewok-syscalls-gettick.ads create mode 100644 Ada/syscalls/ewok-syscalls-init.adb create mode 100644 Ada/syscalls/ewok-syscalls-init.ads create mode 100644 Ada/syscalls/ewok-syscalls-ipc.adb create mode 100644 Ada/syscalls/ewok-syscalls-ipc.ads create mode 100644 Ada/syscalls/ewok-syscalls-lock.adb create mode 100644 Ada/syscalls/ewok-syscalls-lock.ads create mode 100644 Ada/syscalls/ewok-syscalls-reset.adb create mode 100644 Ada/syscalls/ewok-syscalls-reset.ads create mode 100644 Ada/syscalls/ewok-syscalls-sleep.adb create mode 100644 Ada/syscalls/ewok-syscalls-sleep.ads create mode 100644 Ada/syscalls/ewok-syscalls-yield.adb create mode 100644 Ada/syscalls/ewok-syscalls-yield.ads create mode 100644 Kconfig create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Makefile.objs create mode 100644 NOTICE create mode 120000 arch/Ada/config.def create mode 100644 arch/Ada/types-c.adb create mode 100644 arch/Ada/types-c.ads create mode 100644 arch/Ada/types.adb create mode 100644 arch/Ada/types.ads create mode 100644 arch/Ada/unsafe_types.ads create mode 100644 arch/Kconfig create mode 100644 arch/Makefile create mode 100644 arch/README.md create mode 100644 arch/auto.cgpr create mode 100644 arch/boards/32f407discovery/Kconfig create mode 100644 arch/boards/32f407discovery/Makefile.objs create mode 100644 arch/boards/32f407discovery/buttons.h create mode 100644 arch/boards/32f407discovery/disco.h create mode 100644 arch/boards/32f407discovery/leds.h create mode 100644 arch/boards/32f407discovery/params.h create mode 100644 arch/boards/32f407discovery/product.h create mode 100644 arch/boards/32f429discovery/Kconfig create mode 100644 arch/boards/32f429discovery/Makefile.objs create mode 100644 arch/boards/32f429discovery/buttons.h create mode 100644 arch/boards/32f429discovery/disco.h create mode 100644 arch/boards/32f429discovery/leds.h create mode 100644 arch/boards/32f429discovery/params.h create mode 100644 arch/boards/32f429discovery/product.h create mode 100644 arch/boards/Makefile.objs create mode 100644 arch/boards/boards.h create mode 100644 arch/boards/shared.c create mode 100644 arch/boards/shared.h create mode 100644 arch/boards/wookey/Kconfig create mode 100644 arch/boards/wookey/Makefile.objs create mode 100644 arch/boards/wookey/buttons.h create mode 100644 arch/boards/wookey/leds.h create mode 100644 arch/boards/wookey/params.h create mode 100644 arch/boards/wookey/product.h create mode 120000 arch/cores/armv7-m/Ada/config.def create mode 100644 arch/cores/armv7-m/Ada/m4-cpu-instructions.adb create mode 100644 arch/cores/armv7-m/Ada/m4-cpu-instructions.ads create mode 100644 arch/cores/armv7-m/Ada/m4-cpu.adb create mode 100644 arch/cores/armv7-m/Ada/m4-cpu.ads create mode 100644 arch/cores/armv7-m/Ada/m4-layout.ads create mode 100644 arch/cores/armv7-m/Ada/m4-mpu.adb create mode 100644 arch/cores/armv7-m/Ada/m4-mpu.ads create mode 100644 arch/cores/armv7-m/Ada/m4-scb.adb create mode 100644 arch/cores/armv7-m/Ada/m4-scb.ads create mode 100644 arch/cores/armv7-m/Ada/m4-systick.adb create mode 100644 arch/cores/armv7-m/Ada/m4-systick.ads create mode 100644 arch/cores/armv7-m/Ada/m4.ads create mode 100644 arch/cores/armv7-m/Makefile.objs create mode 100644 arch/cores/armv7-m/m4-core.h create mode 100644 arch/cores/armv7-m/m4-cpu.h create mode 100644 arch/cores/armv7-m/m4-fpu.c create mode 100644 arch/cores/armv7-m/m4-fpu.h create mode 100644 arch/cores/armv7-m/m4-mpu-regions.h create mode 100644 arch/cores/armv7-m/m4-mpu.c create mode 100644 arch/cores/armv7-m/m4-mpu.h create mode 100644 arch/cores/armv7-m/m4-svc.h create mode 100644 arch/cores/armv7-m/m4-systick-regs.h create mode 100644 arch/cores/armv7-m/m4-systick.c create mode 100644 arch/cores/armv7-m/m4-systick.h create mode 100644 arch/cores/armv7-m/types.h create mode 100644 arch/debug.c create mode 100644 arch/debug.h create mode 100644 arch/get_random.c create mode 100644 arch/get_random.h create mode 100644 arch/libabsp.adc create mode 100644 arch/libabsp.gpr create mode 100644 arch/libc.c create mode 100644 arch/libc.h create mode 120000 arch/socs/stm32f407/Ada/config.def create mode 120000 arch/socs/stm32f407/Ada/default_handlers.adb create mode 120000 arch/socs/stm32f407/Ada/default_handlers.ads create mode 120000 arch/socs/stm32f407/Ada/soc-devmap.ads.DRAFT create mode 120000 arch/socs/stm32f407/Ada/soc-dma-interfaces.adb create mode 120000 arch/socs/stm32f407/Ada/soc-dma-interfaces.ads create mode 120000 arch/socs/stm32f407/Ada/soc-dma.adb create mode 120000 arch/socs/stm32f407/Ada/soc-dma.ads create mode 120000 arch/socs/stm32f407/Ada/soc-dwt-interfaces.adb create mode 120000 arch/socs/stm32f407/Ada/soc-dwt-interfaces.ads create mode 120000 arch/socs/stm32f407/Ada/soc-dwt.adb create mode 120000 arch/socs/stm32f407/Ada/soc-dwt.ads create mode 120000 arch/socs/stm32f407/Ada/soc-exti.adb create mode 120000 arch/socs/stm32f407/Ada/soc-exti.ads create mode 120000 arch/socs/stm32f407/Ada/soc-gpio-interfaces.adb create mode 120000 arch/socs/stm32f407/Ada/soc-gpio-interfaces.ads create mode 120000 arch/socs/stm32f407/Ada/soc-gpio.adb create mode 120000 arch/socs/stm32f407/Ada/soc-gpio.ads create mode 120000 arch/socs/stm32f407/Ada/soc-interrupts.adb create mode 120000 arch/socs/stm32f407/Ada/soc-interrupts.ads create mode 120000 arch/socs/stm32f407/Ada/soc-layout-stm32f4.ads create mode 120000 arch/socs/stm32f407/Ada/soc-layout-stm32f42x.ads create mode 100644 arch/socs/stm32f407/Ada/soc-layout.ads create mode 120000 arch/socs/stm32f407/Ada/soc-nvic.adb create mode 120000 arch/socs/stm32f407/Ada/soc-nvic.ads create mode 120000 arch/socs/stm32f407/Ada/soc-rcc.adb.DRAFT create mode 120000 arch/socs/stm32f407/Ada/soc-rcc.ads create mode 120000 arch/socs/stm32f407/Ada/soc-syscfg.adb create mode 120000 arch/socs/stm32f407/Ada/soc-syscfg.ads create mode 120000 arch/socs/stm32f407/Ada/soc.ads create mode 120000 arch/socs/stm32f407/Kconfig create mode 100644 arch/socs/stm32f407/Makefile.objs create mode 120000 arch/socs/stm32f407/default_handlers.c create mode 120000 arch/socs/stm32f407/default_handlers.h create mode 120000 arch/socs/stm32f407/fw1.ld.in create mode 120000 arch/socs/stm32f407/fw2.ld.in create mode 120000 arch/socs/stm32f407/postpone.c create mode 120000 arch/socs/stm32f407/soc-core.h create mode 120000 arch/socs/stm32f407/soc-devmap.c create mode 120000 arch/socs/stm32f407/soc-devmap.h create mode 120000 arch/socs/stm32f407/soc-dma.c create mode 120000 arch/socs/stm32f407/soc-dma.h create mode 120000 arch/socs/stm32f407/soc-dma_regs.h create mode 120000 arch/socs/stm32f407/soc-dwt.c create mode 120000 arch/socs/stm32f407/soc-dwt.h create mode 120000 arch/socs/stm32f407/soc-exti.c create mode 120000 arch/socs/stm32f407/soc-exti.h create mode 120000 arch/socs/stm32f407/soc-flash.h create mode 120000 arch/socs/stm32f407/soc-gpio.c create mode 120000 arch/socs/stm32f407/soc-gpio.h create mode 120000 arch/socs/stm32f407/soc-init.c create mode 120000 arch/socs/stm32f407/soc-init.h create mode 120000 arch/socs/stm32f407/soc-interrupts.c create mode 120000 arch/socs/stm32f407/soc-interrupts.h create mode 120000 arch/socs/stm32f407/soc-iwdg.c create mode 120000 arch/socs/stm32f407/soc-iwdg.h create mode 100644 arch/socs/stm32f407/soc-layout.h create mode 120000 arch/socs/stm32f407/soc-nvic.h create mode 120000 arch/socs/stm32f407/soc-pwr.h create mode 120000 arch/socs/stm32f407/soc-rcc.c create mode 120000 arch/socs/stm32f407/soc-rcc.h create mode 120000 arch/socs/stm32f407/soc-rng.c create mode 120000 arch/socs/stm32f407/soc-rng.h create mode 120000 arch/socs/stm32f407/soc-scb.h create mode 120000 arch/socs/stm32f407/soc-syscfg.h create mode 120000 arch/socs/stm32f407/soc-usart-regs.h create mode 120000 arch/socs/stm32f407/soc-usart.c create mode 120000 arch/socs/stm32f407/soc-usart.h create mode 100644 arch/socs/stm32f407/startup_stm32f407.s create mode 120000 arch/socs/stm32f429/Ada/config.def create mode 120000 arch/socs/stm32f429/Ada/default_handlers.adb create mode 120000 arch/socs/stm32f429/Ada/default_handlers.ads create mode 120000 arch/socs/stm32f429/Ada/soc-devmap.ads.DRAFT create mode 120000 arch/socs/stm32f429/Ada/soc-dma-interfaces.adb create mode 120000 arch/socs/stm32f429/Ada/soc-dma-interfaces.ads create mode 120000 arch/socs/stm32f429/Ada/soc-dma.adb create mode 120000 arch/socs/stm32f429/Ada/soc-dma.ads create mode 120000 arch/socs/stm32f429/Ada/soc-dwt-interfaces.adb create mode 120000 arch/socs/stm32f429/Ada/soc-dwt-interfaces.ads create mode 120000 arch/socs/stm32f429/Ada/soc-dwt.adb create mode 120000 arch/socs/stm32f429/Ada/soc-dwt.ads create mode 120000 arch/socs/stm32f429/Ada/soc-exti.adb create mode 120000 arch/socs/stm32f429/Ada/soc-exti.ads create mode 120000 arch/socs/stm32f429/Ada/soc-gpio-interfaces.adb create mode 120000 arch/socs/stm32f429/Ada/soc-gpio-interfaces.ads create mode 120000 arch/socs/stm32f429/Ada/soc-gpio.adb create mode 120000 arch/socs/stm32f429/Ada/soc-gpio.ads create mode 120000 arch/socs/stm32f429/Ada/soc-interrupts.adb create mode 120000 arch/socs/stm32f429/Ada/soc-interrupts.ads create mode 120000 arch/socs/stm32f429/Ada/soc-layout-stm32f4.ads create mode 120000 arch/socs/stm32f429/Ada/soc-layout-stm32f42x.ads create mode 100644 arch/socs/stm32f429/Ada/soc-layout.ads create mode 120000 arch/socs/stm32f429/Ada/soc-nvic.adb create mode 120000 arch/socs/stm32f429/Ada/soc-nvic.ads create mode 120000 arch/socs/stm32f429/Ada/soc-rcc.adb.DRAFT create mode 120000 arch/socs/stm32f429/Ada/soc-rcc.ads create mode 120000 arch/socs/stm32f429/Ada/soc-syscfg.adb create mode 120000 arch/socs/stm32f429/Ada/soc-syscfg.ads create mode 120000 arch/socs/stm32f429/Ada/soc.ads create mode 120000 arch/socs/stm32f429/Kconfig create mode 100644 arch/socs/stm32f429/Makefile.objs create mode 120000 arch/socs/stm32f429/default_handlers.c create mode 120000 arch/socs/stm32f429/default_handlers.h create mode 120000 arch/socs/stm32f429/fw1.ld.in create mode 120000 arch/socs/stm32f429/fw2.ld.in create mode 120000 arch/socs/stm32f429/postpone.c create mode 120000 arch/socs/stm32f429/soc-core.h create mode 120000 arch/socs/stm32f429/soc-devmap.c create mode 120000 arch/socs/stm32f429/soc-devmap.h create mode 120000 arch/socs/stm32f429/soc-dma.c create mode 120000 arch/socs/stm32f429/soc-dma.h create mode 120000 arch/socs/stm32f429/soc-dma_regs.h create mode 120000 arch/socs/stm32f429/soc-dwt.c create mode 120000 arch/socs/stm32f429/soc-dwt.h create mode 120000 arch/socs/stm32f429/soc-exti.c create mode 120000 arch/socs/stm32f429/soc-exti.h create mode 120000 arch/socs/stm32f429/soc-flash.h create mode 120000 arch/socs/stm32f429/soc-gpio.c create mode 120000 arch/socs/stm32f429/soc-gpio.h create mode 120000 arch/socs/stm32f429/soc-init.c create mode 120000 arch/socs/stm32f429/soc-init.h create mode 120000 arch/socs/stm32f429/soc-interrupts.c create mode 120000 arch/socs/stm32f429/soc-interrupts.h create mode 120000 arch/socs/stm32f429/soc-iwdg.c create mode 120000 arch/socs/stm32f429/soc-iwdg.h create mode 100644 arch/socs/stm32f429/soc-layout.h create mode 120000 arch/socs/stm32f429/soc-nvic.h create mode 120000 arch/socs/stm32f429/soc-pwr.h create mode 120000 arch/socs/stm32f429/soc-rcc.c create mode 120000 arch/socs/stm32f429/soc-rcc.h create mode 120000 arch/socs/stm32f429/soc-rng.c create mode 120000 arch/socs/stm32f429/soc-rng.h create mode 120000 arch/socs/stm32f429/soc-scb.h create mode 120000 arch/socs/stm32f429/soc-syscfg.h create mode 120000 arch/socs/stm32f429/soc-usart-regs.h create mode 120000 arch/socs/stm32f429/soc-usart.c create mode 120000 arch/socs/stm32f429/soc-usart.h create mode 100644 arch/socs/stm32f429/startup_stm32f429.s create mode 100644 arch/socs/stm32f439/Ada/.placeholder create mode 120000 arch/socs/stm32f439/Ada/config.def create mode 100644 arch/socs/stm32f439/Ada/default_handlers.adb create mode 100644 arch/socs/stm32f439/Ada/default_handlers.ads create mode 100644 arch/socs/stm32f439/Ada/soc-devmap.ads.DRAFT create mode 100644 arch/socs/stm32f439/Ada/soc-dma-interfaces.adb create mode 100644 arch/socs/stm32f439/Ada/soc-dma-interfaces.ads create mode 100644 arch/socs/stm32f439/Ada/soc-dma.adb create mode 100644 arch/socs/stm32f439/Ada/soc-dma.ads create mode 100644 arch/socs/stm32f439/Ada/soc-dwt-interfaces.adb create mode 100644 arch/socs/stm32f439/Ada/soc-dwt-interfaces.ads create mode 100644 arch/socs/stm32f439/Ada/soc-dwt.adb create mode 100644 arch/socs/stm32f439/Ada/soc-dwt.ads create mode 100644 arch/socs/stm32f439/Ada/soc-exti.adb create mode 100644 arch/socs/stm32f439/Ada/soc-exti.ads create mode 100644 arch/socs/stm32f439/Ada/soc-gpio-interfaces.adb create mode 100644 arch/socs/stm32f439/Ada/soc-gpio-interfaces.ads create mode 100644 arch/socs/stm32f439/Ada/soc-gpio.adb create mode 100644 arch/socs/stm32f439/Ada/soc-gpio.ads create mode 100644 arch/socs/stm32f439/Ada/soc-interrupts.adb create mode 100644 arch/socs/stm32f439/Ada/soc-interrupts.ads create mode 100644 arch/socs/stm32f439/Ada/soc-layout-stm32f4.ads create mode 100644 arch/socs/stm32f439/Ada/soc-layout-stm32f42x.ads create mode 100644 arch/socs/stm32f439/Ada/soc-layout.ads create mode 100644 arch/socs/stm32f439/Ada/soc-nvic.adb create mode 100644 arch/socs/stm32f439/Ada/soc-nvic.ads create mode 100644 arch/socs/stm32f439/Ada/soc-rcc.adb.DRAFT create mode 100644 arch/socs/stm32f439/Ada/soc-rcc.ads create mode 100644 arch/socs/stm32f439/Ada/soc-syscfg.adb create mode 100644 arch/socs/stm32f439/Ada/soc-syscfg.ads create mode 100644 arch/socs/stm32f439/Ada/soc.ads create mode 100644 arch/socs/stm32f439/Kconfig create mode 100644 arch/socs/stm32f439/Makefile.objs create mode 100644 arch/socs/stm32f439/default_handlers.c create mode 100644 arch/socs/stm32f439/default_handlers.h create mode 100644 arch/socs/stm32f439/fw1.ld.in create mode 100644 arch/socs/stm32f439/fw2.ld.in create mode 100644 arch/socs/stm32f439/postpone.c create mode 100644 arch/socs/stm32f439/soc-core.h create mode 100644 arch/socs/stm32f439/soc-devmap.c create mode 100644 arch/socs/stm32f439/soc-devmap.h create mode 100644 arch/socs/stm32f439/soc-dma.c create mode 100644 arch/socs/stm32f439/soc-dma.h create mode 100644 arch/socs/stm32f439/soc-dma_regs.h create mode 100644 arch/socs/stm32f439/soc-dwt.c create mode 100644 arch/socs/stm32f439/soc-dwt.h create mode 100644 arch/socs/stm32f439/soc-exti.c create mode 100644 arch/socs/stm32f439/soc-exti.h create mode 100644 arch/socs/stm32f439/soc-flash.h create mode 100644 arch/socs/stm32f439/soc-gpio.c create mode 100644 arch/socs/stm32f439/soc-gpio.h create mode 100644 arch/socs/stm32f439/soc-init.c create mode 100644 arch/socs/stm32f439/soc-init.h create mode 100644 arch/socs/stm32f439/soc-interrupts.c create mode 100644 arch/socs/stm32f439/soc-interrupts.h create mode 100644 arch/socs/stm32f439/soc-iwdg.c create mode 100644 arch/socs/stm32f439/soc-iwdg.h create mode 100644 arch/socs/stm32f439/soc-layout.h create mode 100644 arch/socs/stm32f439/soc-nvic.h create mode 100644 arch/socs/stm32f439/soc-pwr.h create mode 100644 arch/socs/stm32f439/soc-rcc.c create mode 100644 arch/socs/stm32f439/soc-rcc.h create mode 100644 arch/socs/stm32f439/soc-rng.c create mode 100644 arch/socs/stm32f439/soc-rng.h create mode 100644 arch/socs/stm32f439/soc-scb.h create mode 100644 arch/socs/stm32f439/soc-syscfg.h create mode 100644 arch/socs/stm32f439/soc-usart-regs.h create mode 100644 arch/socs/stm32f439/soc-usart.c create mode 100644 arch/socs/stm32f439/soc-usart.h create mode 100644 arch/socs/stm32f439/startup_stm32f439.s create mode 100644 arch/stack_check.c create mode 100644 arch/stack_check.h create mode 100644 arch/usb_device.h create mode 100644 devices-shared.h create mode 100644 devices.c create mode 100644 devices.h create mode 100644 dma-shared.h create mode 100644 dma.c create mode 100644 dma.h create mode 100644 exported/devices.h create mode 100644 exported/dmas.h create mode 100644 exported/gpio.h create mode 100644 exported/irq.h create mode 100644 exported/sleep.h create mode 100644 exported/syscalls.h create mode 100644 exti-handler.c create mode 100644 exti-handler.h create mode 100644 exti.c create mode 100644 exti.h create mode 100644 generated/.placehorder create mode 100644 gnatprep.def create mode 100644 gpio.c create mode 100644 gpio.h create mode 100644 init.c create mode 100644 ipc.c create mode 100644 ipc.h create mode 100644 isr.c create mode 100644 isr.h create mode 100644 kernel.dfu1.ld.in create mode 100644 kernel.dfu2.ld.in create mode 100644 kernel.fw1.ld.in create mode 100644 kernel.fw2.ld.in create mode 100644 kernel.h create mode 120000 kernel.ld.in create mode 100644 layout.h create mode 100644 libabsp.adc create mode 100644 libabsp.gpr create mode 100644 libkernel.adc create mode 100644 libkernel.gpr create mode 100644 mpu-handler.c create mode 100644 mpu.c create mode 100644 mpu.h create mode 100644 perm.c create mode 100644 perm.h create mode 100644 posthook.c create mode 100644 posthook.h create mode 100644 processor.h create mode 100644 prove/Makefile create mode 100644 prove/README.md create mode 100644 prove/gnatprep.def create mode 100644 prove/prove.gpr create mode 100644 prove/target.atp create mode 100644 regutils.h create mode 100644 sanitize.c create mode 100644 sanitize.h create mode 100644 sched.c create mode 100644 sched.h create mode 100644 shared/ipc.h create mode 100644 sleep.c create mode 100644 sleep.h create mode 100644 softirq.c create mode 100644 softirq.h create mode 100644 syscalls-handler.c create mode 100644 syscalls/syscalls-cfg-gpio.c create mode 100644 syscalls/syscalls-cfg-gpio.h create mode 100644 syscalls/syscalls-cfg-mem.c create mode 100644 syscalls/syscalls-cfg-mem.h create mode 100644 syscalls/syscalls-cfg.c create mode 100644 syscalls/syscalls-cfg.h create mode 100644 syscalls/syscalls-dma.c create mode 100644 syscalls/syscalls-dma.h create mode 100644 syscalls/syscalls-gettick.c create mode 100644 syscalls/syscalls-gettick.h create mode 100644 syscalls/syscalls-init.c create mode 100644 syscalls/syscalls-init.h create mode 100644 syscalls/syscalls-ipc.c create mode 100644 syscalls/syscalls-ipc.h create mode 100644 syscalls/syscalls-lock.c create mode 100644 syscalls/syscalls-lock.h create mode 100644 syscalls/syscalls-reset.c create mode 100644 syscalls/syscalls-reset.h create mode 100644 syscalls/syscalls-sleep.c create mode 100644 syscalls/syscalls-sleep.h create mode 100644 syscalls/syscalls-utils.h create mode 100644 syscalls/syscalls-yield.c create mode 100644 syscalls/syscalls-yield.h create mode 100644 syscalls/syscalls.h create mode 100644 tasks-shared.h create mode 100644 tasks.c create mode 100644 tasks.h create mode 100644 types.h create mode 100644 usart.c create mode 100644 usart.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d1fa1d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.placeholder +Ada/generated/config.def +Ada/generated/*.ads +Ada/generated/*.adb +generated/*.h +Ada/libgnat/gnat/s-imgint.adb +Ada/libgnat/gnat/s-imgint.ads +Ada/libgnat/gnat/s-imglli.adb +Ada/libgnat/gnat/s-imglli.ads +Ada/libgnat/gnat/s-imguns.ads +Ada/libgnat/gnat/s-memmov.adb +Ada/libgnat/gnat/s-memmov.ads +Ada/libgnat/gnat/system.ads diff --git a/Ada/c-kernel.ads b/Ada/c-kernel.ads new file mode 100644 index 0000000..e4b0c80 --- /dev/null +++ b/Ada/c-kernel.ads @@ -0,0 +1,42 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with types.c; + +package c.kernel is + + procedure log (s : types.c.c_string) + with + convention => c, + import => true, + external_name => "dbg_log", + global => null; + + procedure flush + with + convention => c, + import => true, + external_name => "dbg_flush", + global => null; + +end c.kernel; + diff --git a/Ada/c-socinfo.ads b/Ada/c-socinfo.ads new file mode 100644 index 0000000..2b84aa3 --- /dev/null +++ b/Ada/c-socinfo.ads @@ -0,0 +1,74 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ada.unchecked_conversion; +with ewok.perm; +with ewok.exported.dma; +with types.c; + +package c.socinfo + with spark_mode => off +is + + type t_device_soc_infos is record + name_ptr : system_address; + base_addr : system_address; + rcc_enr : system_address; + rcc_enb : unsigned_32; + size : unsigned_16; + subregions : unsigned_8; + intr_num : unsigned_8; + ro : types.c.bool; + minperm : ewok.perm.t_perm_name; + end record; + + type t_device_soc_infos_access is access all t_device_soc_infos; + + function to_device_soc_infos is new ada.unchecked_conversion + (system_address, t_device_soc_infos_access); + + function soc_devmap_find_device + (addr : system_address; + size : unsigned_16) + return t_device_soc_infos_access + with + convention => c, + import => true, + external_name => "soc_devmap_find_device"; + + function soc_devmap_find_dma_device + (dma_controller : ewok.exported.dma.t_controller; + stream : ewok.exported.dma.t_stream) + return t_device_soc_infos_access + with + convention => c, + import => true, + external_name => "soc_devices_get_dma"; + + procedure soc_devmap_enable_clock + (socdev : t_device_soc_infos) + with + convention => c, + import => true, + external_name => "soc_devmap_enable_clock"; + +end c.socinfo; diff --git a/Ada/c.ads b/Ada/c.ads new file mode 100644 index 0000000..95e32dd --- /dev/null +++ b/Ada/c.ads @@ -0,0 +1,35 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +pragma warnings (Off, "use clause for package"); + +with interfaces; use interfaces; +pragma unreferenced (interfaces); + +with types; use types; +pragma unreferenced (types); + +pragma warnings (On, "use clause for package"); + +package c is +end c; diff --git a/Ada/config.def b/Ada/config.def new file mode 120000 index 0000000..891e825 --- /dev/null +++ b/Ada/config.def @@ -0,0 +1 @@ +generated/config.def \ No newline at end of file diff --git a/Ada/debug.adb b/Ada/debug.adb new file mode 100644 index 0000000..d367bd2 --- /dev/null +++ b/Ada/debug.adb @@ -0,0 +1,73 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with types.c; +with c.kernel; + +package body debug + with spark_mode => off +is + + procedure log (s : string; nl : boolean := true) + is + c_string : types.c.c_string (1 .. s'length + 3); + begin + + for i in s'range loop + c_string(1 + i - s'first) := s(i); + end loop; + + if nl then + c_string(c_string'last - 2) := ASCII.CR; + c_string(c_string'last - 1) := ASCII.LF; + c_string(c_string'last) := ASCII.NUL; + else + c_string(c_string'last - 2) := ASCII.NUL; + end if; + + c.kernel.log (c_string); + c.kernel.flush; + + end log; + + + procedure log (level : t_level; s : string) + is + begin + case level is + when DEBUG .. INFO => + log (COLOR_KERNEL & s & COLOR_NORMAL); + when WARNING .. ALERT => + log (COLOR_ALERT & s & COLOR_NORMAL); + end case; + end log; + + + procedure panic (s : string) + is + begin + log (COLOR_ALERT & "panic: " & s & COLOR_NORMAL); + loop null; end loop; + end panic; + +end debug; diff --git a/Ada/debug.ads b/Ada/debug.ads new file mode 100644 index 0000000..f9438a8 --- /dev/null +++ b/Ada/debug.ads @@ -0,0 +1,39 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + + +package debug + with spark_mode => off +is + + type t_level is (DEBUG, INFO, WARNING, ALERT); + + COLOR_NORMAL : constant string := ASCII.ESC & "[37;40m"; + COLOR_ALERT : constant string := ASCII.ESC & "[37;41m"; + COLOR_KERNEL : constant string := ASCII.ESC & "[37;44m"; + + procedure log (s : string; nl : boolean := true); + procedure log (level : t_level; s : string); + procedure panic (s : string); + +end debug; diff --git a/Ada/ewok-devices-interfaces.adb b/Ada/ewok-devices-interfaces.adb new file mode 100644 index 0000000..43ea8c3 --- /dev/null +++ b/Ada/ewok-devices-interfaces.adb @@ -0,0 +1,33 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package body ewok.devices.interfaces + with spark_mode => off +is + + procedure init + is begin + ewok.devices.init; + end init; + +end ewok.devices.interfaces; diff --git a/Ada/ewok-devices-interfaces.ads b/Ada/ewok-devices-interfaces.ads new file mode 100644 index 0000000..0a204ed --- /dev/null +++ b/Ada/ewok-devices-interfaces.ads @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.devices.interfaces + with spark_mode => off +is + + procedure init + with + convention => c, + export => true, + external_name => "dev_init"; + +end ewok.devices.interfaces; diff --git a/Ada/ewok-devices.adb b/Ada/ewok-devices.adb new file mode 100644 index 0000000..b5e6f6d --- /dev/null +++ b/Ada/ewok-devices.adb @@ -0,0 +1,621 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.perm; use ewok.perm; +with ewok.exported.devices; use ewok.exported.devices; +with ewok.exported.interrupts; use ewok.exported.interrupts; +with ewok.exported.gpios; use ewok.exported.gpios; +with ewok.interrupts; use ewok.interrupts; +with ewok.sanitize; +with ewok.gpio; +with ewok.mpu; +with ewok.exti; +with ewok.tasks; use ewok.tasks; +with soc.nvic; +with soc.gpio; +with soc.interrupts; use soc.interrupts; +with c.socinfo; use type c.socinfo.t_device_soc_infos_access; +with types.c; +with debug; + +package body ewok.devices + with spark_mode => off +is + + procedure init + is begin + for i in registered_device'range loop + registered_device(i).status := DEV_STATE_UNUSED; + registered_device(i).task_id := ID_UNUSED; + registered_device(i).devinfo := NULL; + -- FIXME initialize registered_device(i).udev with 0 values + end loop; + end init; + + + function get_task_from_id(dev_id : t_device_id) + return t_task_id + is + begin + return registered_device(dev_id).task_id; + end get_task_from_id; + + + function get_user_device (dev_id : t_device_id) + return ewok.exported.devices.t_user_device_access + is + begin + if dev_id = ID_DEV_UNUSED then + raise program_error; + end if; + return registered_device(dev_id).udev'access; + end get_user_device; + + + function get_user_device_size (dev_id : t_device_id) + return unsigned_16 + is + begin + if dev_id = ID_DEV_UNUSED then + raise program_error; + end if; + return registered_device(dev_id).udev.size; + end get_user_device_size; + + + function get_user_device_addr (dev_id : t_device_id) + return system_address + is + begin + if dev_id = ID_DEV_UNUSED then + raise program_error; + end if; + return registered_device(dev_id).udev.base_addr; + end get_user_device_addr; + + + function is_user_device_region_ro (dev_id : t_device_id) + return boolean + is + begin + if dev_id = ID_DEV_UNUSED then + raise program_error; + end if; + return boolean (registered_device(dev_id).devinfo.all.ro); + end is_user_device_region_ro; + + + function get_user_device_subregions_mask (dev_id : t_device_id) + return unsigned_8 + is + begin + if dev_id = ID_DEV_UNUSED then + raise program_error; + end if; + return registered_device(dev_id).devinfo.all.subregions; + end get_user_device_subregions_mask; + + + function get_interrupt_config_from_interrupt + (interrupt : soc.interrupts.t_interrupt) + return ewok.exported.interrupts.t_interrupt_config_access + is + dev_id : t_device_id; + begin + + -- Retrieving the dev_id from the interrupt + dev_id := ewok.interrupts.get_device_from_interrupt (interrupt); + if dev_id = ID_DEV_UNUSED then + return NULL; + end if; + + -- Looking at each interrupts configured for this device + -- to retrieve the proper interrupt configuration informations + for i in 1 .. registered_device(dev_id).udev.interrupt_num loop + if registered_device(dev_id).udev.interrupts(i).interrupt = interrupt + then + return registered_device(dev_id).udev.interrupts(i)'access; + end if; + end loop; + return NULL; + end get_interrupt_config_from_interrupt; + + ------------------------ + -- Device registering -- + ------------------------ + + procedure get_registered_device_entry + (dev_id : out t_device_id; + success : out boolean) + is + begin + for id in registered_device'range loop + if registered_device(id).status = DEV_STATE_UNUSED then + registered_device(id).status := DEV_STATE_RESERVED; + dev_id := id; + success := true; + return; + end if; + end loop; + dev_id := ID_DEV_UNUSED; + success := false; + end get_registered_device_entry; + + + procedure release_registered_device_entry (dev_id : t_device_id) + is begin + registered_device(dev_id).status := DEV_STATE_UNUSED; + registered_device(dev_id).task_id := ID_UNUSED; + registered_device(dev_id).devinfo := NULL; + -- FIXME initialize registered_device(dev_id).udev with 0 values + end release_registered_device_entry; + + + procedure register_device + (task_id : in t_task_id; + udev : in ewok.exported.devices.t_user_device_access; + dev_id : out t_device_id; + success : out boolean) + is + devinfo : c.socinfo.t_device_soc_infos_access; + len : constant natural := types.c.len (udev.all.name); + name : string (1 .. len); + begin + + -- Convert C name to Ada string type for further log messages + types.c.to_ada (name, udev.all.name); + + -- Is it an existing device ? + -- Note: GPIOs (size = 0) are not considered as devices despite a task + -- can register them. Thus, we don't look for them in c.socinfo + -- table. + if udev.all.size /= 0 then + devinfo := c.socinfo.soc_devmap_find_device + (udev.all.base_addr, udev.all.size); + if devinfo = NULL then + debug.log (debug.WARNING, "Can't find device " & name & "(addr:" & + system_address'image (udev.all.base_addr) & ", size:" & + unsigned_16'image (udev.all.size) & ")"); + success := false; + return; + end if; + end if; + + -- Is it already used ? + -- Note: GPIOs alone are not considered as devices. When the user + -- declares lone GPIOs, devinfo is NULL + for id in registered_device'range loop + if registered_device(id).status /= DEV_STATE_UNUSED and then + registered_device(id).devinfo /= NULL and then + registered_device(id).devinfo = devinfo + then + debug.log (debug.WARNING, "Device " & name & " is already used"); + success := false; + return; + end if; + end loop; + + -- Are the GPIOs already used ? + for i in 1 .. udev.gpio_num loop + if ewok.gpio.is_used (udev.gpios(i).kref) then + debug.log (debug.WARNING, + "Device " & name & ": some GPIOs are already used"); + success := false; + return; + end if; + end loop; + + -- Are the related EXTIs already used ? + for i in 1 .. udev.gpio_num loop + if boolean (udev.gpios(i).settings.set_exti) and then + ewok.exti.is_used (udev.gpios(i).kref) + then + debug.log (debug.WARNING, + "Device " & name & ": some EXTIs are already used"); + success := false; + return; + end if; + end loop; + + -- Is it possible to register interrupt handlers ? + for i in 1 .. udev.interrupt_num loop + if ewok.interrupts.is_interrupt_already_used + (udev.interrupts(i).interrupt) + then + debug.log (debug.WARNING, + "Device " & name & ": some interrupts are already used"); + success := false; + return; + end if; + end loop; + + -- Is it possible to register a device ? + get_registered_device_entry (dev_id, success); + + if not success then + debug.log (debug.WARNING, + "register_device(): no slot left to register the device"); + return; + end if; + + -- Registering the device + debug.log (debug.INFO, "Registered device " & name & " (0x" & + system_address'image (udev.all.base_addr) & ")"); + + registered_device(dev_id).udev := udev.all; + registered_device(dev_id).task_id := task_id; + registered_device(dev_id).is_mapped := false; + registered_device(dev_id).devinfo := devinfo; + registered_device(dev_id).status := DEV_STATE_REGISTERED; + + -- Registering GPIOs + for i in 1 .. udev.gpio_num loop + ewok.gpio.register (task_id, dev_id, udev.gpios(i)'access, success); + if not success then + raise program_error; + end if; + debug.log (debug.INFO, + "Registered GPIO port" & + soc.gpio.t_gpio_port_index'image (udev.gpios(i).kref.port) & + " pin " & + soc.gpio.t_gpio_pin_index'image (udev.gpios(i).kref.pin)); + end loop; + + -- Registering EXTIs + for i in 1 .. udev.gpio_num loop + ewok.exti.register (udev.gpios(i)'access, success); + if not success then + raise program_error; + end if; + end loop; + + -- Registering handlers + for i in 1 .. udev.interrupt_num loop + ewok.interrupts.set_interrupt_handler + (udev.interrupts(i).interrupt, + udev.interrupts(i).handler, + task_id, + dev_id, + success); + if not success then + raise program_error; + end if; + end loop; + + success := true; + + end register_device; + + + procedure enable_device + (dev_id : in t_device_id; + success : out boolean) + is + irq : soc.nvic.t_irq_index; + interrupt : t_interrupt; + begin + + -- Check if the device was already configured + if registered_device(dev_id).status /= DEV_STATE_REGISTERED then + raise program_error; + end if; + + -- Configure and enable GPIOs + for i in 1 .. registered_device(dev_id).udev.gpio_num loop + ewok.gpio.config (registered_device(dev_id).udev.gpios(i)'access); + if registered_device(dev_id).udev.gpios(i).exti_trigger /= + GPIO_EXTI_TRIGGER_NONE + then + ewok.exti.enable (registered_device(dev_id).udev.gpios(i).kref); + end if; + end loop; + + -- For each interrupt, enable its associated IRQ in the NVIC + for i in 1 .. registered_device(dev_id).udev.interrupt_num loop + interrupt := registered_device(dev_id).udev.interrupts(i).interrupt; + irq := soc.nvic.to_irq_number (interrupt); + soc.nvic.enable_irq (irq); + debug.log (debug.INFO, "IRQ enabled" & soc.nvic.t_irq_index'image (irq) & " (int:" + & t_interrupt'image (interrupt) & ")"); + end loop; + + -- Enable device's clock + if registered_device(dev_id).devinfo /= NULL then + c.socinfo.soc_devmap_enable_clock (registered_device(dev_id).devinfo.all); + declare + udev : constant t_user_device := registered_device(dev_id).udev; + name : string (1 .. types.c.len (udev.name)); + begin + types.c.to_ada (name, udev.name); + debug.log (debug.INFO, "Enabled device " & name); + end; + end if; + + registered_device(dev_id).status := DEV_STATE_ENABLED; + if registered_device(dev_id).udev.map_mode = DEV_MAP_AUTO then + registered_device(dev_id).is_mapped := true; + end if; + success := true; + end enable_device; + + + function sanitize_user_defined_interrupt + (udev : in ewok.exported.devices.t_user_device_access; + config : in ewok.exported.interrupts.t_interrupt_config; + task_id : in t_task_id) + return boolean + is + begin + + if not ewok.sanitize.is_word_in_txt_slot + (to_system_address (config.handler), task_id) + then + debug.log (debug.WARNING, "Device handler not in TXT slot"); + return false; + end if; + + if config.interrupt not in INT_WWDG .. INT_HASH_RNG + then + debug.log (debug.WARNING, "Device interrupt not in range"); + return false; + end if; + + if config.mode = ISR_FORCE_MAINTHREAD and then + not ewok.perm.ressource_is_granted (PERM_RES_TSK_FISR, task_id) + then + debug.log (debug.WARNING, "Device ISR_FORCE_MAINTHREAD not allowed"); + return false; + end if; + + -- + -- Verify posthooks + -- + + for i in 1 .. MAX_POSTHOOK_INSTR loop + + if not config.posthook.action(i).instr'valid then + debug.log (debug.WARNING, + "Device posthook: invalid action requested"); + return false; + end if; + + case config.posthook.action(i).instr is + when POSTHOOK_NIL => null; + + when POSTHOOK_READ => + if config.posthook.action(i).read.offset > udev.all.size - 4 or + (config.posthook.action(i).read.offset and 2#11#) > 0 + then + debug.log (debug.WARNING, + "Device posthook: wrong READ offset"); + return false; + end if; + + when POSTHOOK_WRITE => + if config.posthook.action(i).write.offset > udev.all.size - 4 or + (config.posthook.action(i).write.offset and 2#11#) > 0 + then + debug.log (debug.WARNING, + "Device posthook: wrong WRITE offset"); + return false; + end if; + + when POSTHOOK_WRITE_REG => + if config.posthook.action(i).write_reg.offset_dest > + udev.all.size - 4 + or (config.posthook.action(i).write_reg.offset_dest and 2#11#) + > 0 + or config.posthook.action(i).write_reg.offset_src > + udev.all.size - 4 + or (config.posthook.action(i).write_reg.offset_src and 2#11#) + > 0 + then + debug.log (debug.WARNING, + "Device posthook: wrong AND offset"); + return false; + end if; + + when POSTHOOK_WRITE_MASK => + + if config.posthook.action(i).write_mask.offset_dest > + udev.all.size - 4 + or (config.posthook.action(i).write_mask.offset_dest and 2#11#) + > 0 + or config.posthook.action(i).write_mask.offset_src > + udev.all.size - 4 + or (config.posthook.action(i).write_mask.offset_src and 2#11#) + > 0 + or config.posthook.action(i).write_mask.offset_mask > + udev.all.size - 4 + or (config.posthook.action(i).write_mask.offset_mask and 2#11#) + > 0 + then + debug.log (debug.WARNING, + "Device posthook: wrong MASK offset"); + return false; + end if; + end case; + + end loop; + + return true; + + end sanitize_user_defined_interrupt; + + + function sanitize_user_defined_gpio + (udev : in ewok.exported.devices.t_user_device_access; + config : in ewok.exported.gpios.t_gpio_config; + task_id : in t_task_id) + return boolean + is + pragma unreferenced (udev); + begin + + if config.exti_trigger /= GPIO_EXTI_TRIGGER_NONE and then + not ewok.perm.ressource_is_granted (PERM_RES_DEV_EXTI, task_id) + then + debug.log (debug.WARNING, "Device PERM_RES_DEV_EXTI not allowed"); + return false; + end if; + + if config.exti_handler /= 0 and then + not ewok.sanitize.is_word_in_txt_slot (config.exti_handler, task_id) + then + debug.log (debug.WARNING, "Device EXTI handler not in TXT slot"); + return false; + end if; + + return true; + + end sanitize_user_defined_gpio; + + + function sanitize_user_defined_device + (udev : in ewok.exported.devices.t_user_device_access; + task_id : in t_task_id) + return boolean + is + devinfo : c.socinfo.t_device_soc_infos_access; + ok : boolean; + + len : constant natural := types.c.len (udev.all.name); + name : string (1 .. natural'min (t_device_name'length, len)); + begin + + if udev.all.name(t_device_name'last) /= ASCII.NUL then + types.c.to_ada (name, udev.all.name(1 .. t_device_name'length)); + debug.log (debug.WARNING, "Out-of-bound device name: " & name); + return false; + else + types.c.to_ada (name, udev.all.name); + end if; + + if udev.all.size /= 0 then + devinfo := + c.socinfo.soc_devmap_find_device (udev.all.base_addr, udev.all.size); + + if devinfo = NULL then + debug.log (debug.WARNING, "Device at addr" & system_address'image + (udev.all.base_addr) & " with size" & unsigned_16'image (udev.all.size) & + ": not found"); + return false; + end if; + + if not ewok.perm.ressource_is_granted (devinfo.minperm, task_id) then + debug.log (debug.WARNING, "Task" & t_task_id'image (task_id) & + " has not access to device " & name); + return false; + end if; + end if; + + for i in 1 .. udev.all.interrupt_num loop + ok := sanitize_user_defined_interrupt + (udev, udev.all.interrupts(i), task_id); + if not ok then + debug.log (debug.WARNING, "Device " & name & ": invalid udev.interrupts parameter"); + return false; + end if; + end loop; + + for i in 1 .. udev.all.gpio_num loop + ok := sanitize_user_defined_gpio (udev, udev.all.gpios(i), task_id); + if not ok then + debug.log (debug.WARNING, "Device " & name & ": invalid udev.gpios parameter"); + return false; + end if; + end loop; + + if udev.all.map_mode = DEV_MAP_VOLUNTARY then + if not ewok.perm.ressource_is_granted (PERM_RES_MEM_DYNAMIC_MAP, task_id) then + debug.log (debug.WARNING, "Task" & t_task_id'image (task_id) & + " voluntary mapped device " & name & " not permited"); + return false; + end if; + end if; + + return true; + + end sanitize_user_defined_device; + + + ------------------------------------------------- + -- Marking devices to be mapped in user memory -- + ------------------------------------------------- + + procedure map_device + (dev_id : in t_device_id; + success : out boolean) + is + task_id : constant t_task_id := ewok.devices.get_task_from_id (dev_id); + task_a : constant t_task_access := ewok.tasks.get_task (task_id); + begin + + -- The device is already mapped + if registered_device(dev_id).is_mapped then + success := true; + return; + end if; + + -- We are physically limited by the number of regions + if task_a.all.num_devs_mmapped = ewok.mpu.MPU_MAX_EMPTY_REGIONS then + success := false; + return; + end if; + + registered_device(dev_id).is_mapped := true; + task_a.all.num_devs_mmapped := task_a.all.num_devs_mmapped + 1; + success := true; + end map_device; + + + procedure unmap_device + (dev_id : in t_device_id; + success : out boolean) + is + task_id : constant t_task_id := ewok.devices.get_task_from_id (dev_id); + task_a : constant t_task_access := ewok.tasks.get_task (task_id); + begin + -- The device is already unmapped + if not registered_device(dev_id).is_mapped then + success := true; + return; + end if; + + task_a.all.num_devs_mmapped := task_a.all.num_devs_mmapped - 1; + registered_device(dev_id).is_mapped := false; + success := true; + end unmap_device; + + + function is_mapped (dev_id : t_device_id) + return boolean + is + begin + if dev_id = ID_DEV_UNUSED then + raise program_error; + end if; + return registered_device(dev_id).is_mapped; + end is_mapped; + + +end ewok.devices; diff --git a/Ada/ewok-devices.ads b/Ada/ewok-devices.ads new file mode 100644 index 0000000..5f20b6a --- /dev/null +++ b/Ada/ewok-devices.ads @@ -0,0 +1,111 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.devices_shared; use ewok.devices_shared; +with ewok.exported.devices; +with ewok.exported.interrupts; +with soc.interrupts; +with c.socinfo; + +package ewok.devices + with spark_mode => off +is + + type t_device_type is (DEV_TYPE_USER, DEV_TYPE_KERNEL); + + type t_device_state is -- FIXME + (DEV_STATE_UNUSED, + DEV_STATE_RESERVED, + DEV_STATE_CREATED, + DEV_STATE_REGISTERED, + DEV_STATE_ENABLED, + DEV_STATE_REG_FAILED); + + type t_device is record + udev : aliased ewok.exported.devices.t_user_device; + task_id : t_task_id; + is_mapped : boolean; + devinfo : c.socinfo.t_device_soc_infos_access; -- FIXME + status : t_device_state; + end record; + + registered_device : array (t_device_id range ID_DEV1 .. ID_DEV16) of t_device; + + + procedure init; + + procedure get_registered_device_entry + (dev_id : out t_device_id; + success : out boolean); + + procedure release_registered_device_entry (dev_id : t_device_id); + + function get_task_from_id(dev_id : t_device_id) + return t_task_id; + + function get_user_device (dev_id : t_device_id) + return ewok.exported.devices.t_user_device_access; + + function get_user_device_size (dev_id : t_device_id) + return unsigned_16; + + function get_user_device_addr (dev_id : t_device_id) + return system_address; + + function is_user_device_region_ro (dev_id : t_device_id) + return boolean; + + function get_user_device_subregions_mask (dev_id : t_device_id) + return unsigned_8; + + function get_interrupt_config_from_interrupt + (interrupt : soc.interrupts.t_interrupt) + return ewok.exported.interrupts.t_interrupt_config_access; + + procedure register_device + (task_id : in t_task_id; + udev : in ewok.exported.devices.t_user_device_access; + dev_id : out t_device_id; + success : out boolean); + + procedure enable_device + (dev_id : in t_device_id; + success : out boolean); + + function sanitize_user_defined_device + (udev : in ewok.exported.devices.t_user_device_access; + task_id : in t_task_id) + return boolean; + + procedure map_device + (dev_id : in t_device_id; + success : out boolean); + + procedure unmap_device + (dev_id : in t_device_id; + success : out boolean); + + function is_mapped (dev_id : t_device_id) + return boolean; + +end ewok.devices; diff --git a/Ada/ewok-devices_shared.ads b/Ada/ewok-devices_shared.ads new file mode 100644 index 0000000..d81ed44 --- /dev/null +++ b/Ada/ewok-devices_shared.ads @@ -0,0 +1,47 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.devices_shared + with spark_mode => on +is + + type t_device_id is + (ID_DEV_UNUSED, + ID_DEV1, + ID_DEV2, + ID_DEV3, + ID_DEV4, + ID_DEV5, + ID_DEV6, + ID_DEV7, + ID_DEV8, + ID_DEV9, + ID_DEV10, + ID_DEV11, + ID_DEV12, + ID_DEV13, + ID_DEV14, + ID_DEV15, + ID_DEV16); + +end ewok.devices_shared; diff --git a/Ada/ewok-dma-interfaces.adb b/Ada/ewok-dma-interfaces.adb new file mode 100644 index 0000000..205f041 --- /dev/null +++ b/Ada/ewok-dma-interfaces.adb @@ -0,0 +1,57 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ada.unchecked_conversion; + +package body ewok.dma.interfaces + with spark_mode => off +is + + procedure dma_init + is begin + ewok.dma.init; + end dma_init; + + function dma_get_status + (caller_id : ewok.tasks_shared.t_task_id; + intr : soc.interrupts.t_interrupt) + return unsigned_32 + is + + pragma warnings (off); -- size may differ + function to_unsigned_32 is new ada.unchecked_conversion + (soc.dma.t_dma_stream_int_status, unsigned_32); + pragma warnings (on); + + status : soc.dma.t_dma_stream_int_status; + ok : boolean; + begin + ewok.dma.get_status_register (caller_id, intr, status, ok); + if ok then + return to_unsigned_32 (status) and 16#0000_003F#; + else + return 0; + end if; + end dma_get_status; + + +end ewok.dma.interfaces; diff --git a/Ada/ewok-dma-interfaces.ads b/Ada/ewok-dma-interfaces.ads new file mode 100644 index 0000000..6c01831 --- /dev/null +++ b/Ada/ewok-dma-interfaces.ads @@ -0,0 +1,37 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.dma.interfaces + with spark_mode => off +is + + procedure dma_init + with + convention => c, export, external_name => "dma_init"; + + function dma_get_status + (caller_id : ewok.tasks_shared.t_task_id; + intr : soc.interrupts.t_interrupt) + return unsigned_32; + +end ewok.dma.interfaces; diff --git a/Ada/ewok-dma.adb b/Ada/ewok-dma.adb new file mode 100644 index 0000000..2ca92ce --- /dev/null +++ b/Ada/ewok-dma.adb @@ -0,0 +1,639 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.exported.dma; use ewok.exported.dma; +with ewok.sanitize; +with ewok.tasks; +with ewok.interrupts; +with ewok.devices_shared; + +#if CONFIG_KERNEL_DOMAIN +with ewok.perm; +#end if; + +with soc.dma.interfaces; +with soc.nvic; +with c.socinfo; use type c.socinfo.t_device_soc_infos_access; +with debug; + +package body ewok.dma + with spark_mode => off +is + + + procedure get_registered_dma_entry + (index : out ewok.dma_shared.t_registered_dma_index; + success : out boolean) + is + begin + for id in registered_dma'range loop + if registered_dma(id).status = DMA_UNUSED then + registered_dma(id).status := DMA_USED; + index := id; + success := true; + return; + end if; + end loop; + success := false; + end get_registered_dma_entry; + + + function has_same_dma_channel + (index : ewok.dma_shared.t_registered_dma_index; + config : ewok.exported.dma.t_dma_user_config) + return boolean + is + begin + if registered_dma(index).user_config.controller = config.controller and + registered_dma(index).user_config.stream = config.stream and + registered_dma(index).user_config.channel = config.channel + then + return true; + else + return false; + end if; + end has_same_dma_channel; + + + function dma_is_already_used + (config : ewok.exported.dma.t_dma_user_config) + return boolean + is + begin + for index in registered_dma'range loop + if has_same_dma_channel (index, config) then + return true; + end if; + end loop; + return false; + end dma_is_already_used; + + + function task_owns_dma_stream + (caller_id : ewok.tasks_shared.t_task_id; + dma_id : ewok.exported.dma.t_controller; + stream_id : ewok.exported.dma.t_stream) + return boolean + is + begin + for index in registered_dma'range loop + if registered_dma(index).task_id = caller_id and then + registered_dma(index).user_config.controller = dma_id and then + registered_dma(index).user_config.stream = stream_id + then + return true; + end if; + end loop; + return false; + end task_owns_dma_stream; + + + procedure enable_dma_stream + (index : in ewok.dma_shared.t_registered_dma_index) + is + dma_id : constant soc.dma.t_dma_periph_index := + soc.dma.t_dma_periph_index + (registered_dma(index).user_config.controller); + + stream_id : constant soc.dma.t_stream_index := + soc.dma.t_stream_index + (registered_dma(index).user_config.stream); + begin + if registered_dma(index).status = DMA_CONFIGURED then + soc.dma.interfaces.enable_stream (dma_id, stream_id); + end if; + end enable_dma_stream; + + + procedure disable_dma_stream + (index : in ewok.dma_shared.t_registered_dma_index) + is + dma_id : constant soc.dma.t_dma_periph_index := + soc.dma.t_dma_periph_index + (registered_dma(index).user_config.controller); + + stream_id : constant soc.dma.t_stream_index := + soc.dma.t_stream_index + (registered_dma(index).user_config.stream); + begin + if registered_dma(index).status = DMA_CONFIGURED then + soc.dma.interfaces.disable_stream (dma_id, stream_id); + end if; + end disable_dma_stream; + + + procedure enable_dma_irq + (index : in ewok.dma_shared.t_registered_dma_index) + is + intr : constant soc.interrupts.t_interrupt := + soc.interrupts.t_interrupt'val + (registered_dma(index).devinfo.all.intr_num); + begin + soc.nvic.enable_irq (soc.nvic.to_irq_number (intr)); + end enable_dma_irq; + + + function is_config_complete + (user_config : ewok.exported.dma.t_dma_user_config) + return boolean + is + begin + if user_config.in_addr = 0 or + user_config.out_addr = 0 or + user_config.size = 0 or + user_config.transfer_dir = MEMORY_TO_MEMORY or + (user_config.transfer_dir = MEMORY_TO_PERIPHERAL + and user_config.in_handler = 0) or + (user_config.transfer_dir = PERIPHERAL_TO_MEMORY + and user_config.out_handler = 0) + then + return false; + else + return true; + end if; + end is_config_complete; + + + function sanitize_dma + (user_config : ewok.exported.dma.t_dma_user_config; + caller_id : ewok.tasks_shared.t_task_id; + to_configure : ewok.exported.dma.t_config_mask; + mode : ewok.tasks_shared.t_task_mode) + return boolean + is + begin + + case user_config.transfer_dir is + when PERIPHERAL_TO_MEMORY => + + if to_configure.buffer_in then + if not ewok.sanitize.is_word_in_allocated_device + (user_config.in_addr, caller_id) + then + return false; + end if; + end if; + + if to_configure.buffer_out then + if not ewok.sanitize.is_range_in_any_slot + (user_config.out_addr, unsigned_32 (user_config.size), + caller_id, mode) + and + not ewok.sanitize.is_range_in_dma_shm + (user_config.out_addr, unsigned_32 (user_config.size), + SHM_ACCESS_WRITE, caller_id) + then + return false; + end if; + end if; + + if to_configure.handlers then + if not ewok.sanitize.is_word_in_txt_slot + (user_config.out_handler, caller_id) + then + return false; + end if; + end if; + + when MEMORY_TO_PERIPHERAL => + + if to_configure.buffer_in then + if not ewok.sanitize.is_range_in_any_slot + (user_config.in_addr, unsigned_32 (user_config.size), + caller_id, mode) + and + not ewok.sanitize.is_range_in_dma_shm + (user_config.in_addr, unsigned_32 (user_config.size), + SHM_ACCESS_READ, caller_id) + then + return false; + end if; + end if; + + if to_configure.buffer_out then + if not ewok.sanitize.is_word_in_allocated_device + (user_config.out_addr, caller_id) + then + return false; + end if; + end if; + + if to_configure.handlers then + if not ewok.sanitize.is_word_in_txt_slot + (user_config.in_handler, caller_id) + then + return false; + end if; + end if; + + when MEMORY_TO_MEMORY => + return false; + end case; + + return true; + + end sanitize_dma; + + + function sanitize_dma_shm + (shm : ewok.exported.dma.t_dma_shm_info; + caller_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) + return boolean + is + begin + + if not ewok.tasks.is_user (shm.granted_id) then + debug.log ("ewok.dma.sanitize_dma_shm(): wrong target"); + return false; + end if; + + if shm.accessed_id /= caller_id then + debug.log ("ewok.dma.sanitize_dma_shm(): wrong caller"); + return false; + end if; + +#if CONFIG_KERNEL_DOMAIN + if not ewok.perm.is_same_domain (shm.granted_id, shm.accessed_id) then + debug.log ("ewok.dma.sanitize_dma_shm(): not same domain"); + return false; + end if; +#end if; + + if not ewok.sanitize.is_range_in_data_slot + (shm.base, unsigned_32 (shm.size), caller_id, mode) + then + debug.log ("ewok.dma.sanitize_dma_shm(): shm not in range"); + return false; + end if; + + return true; + + end sanitize_dma_shm; + + + procedure reconfigure_stream + (user_config : in out ewok.exported.dma.t_dma_user_config; + index : in ewok.dma_shared.t_registered_dma_index; + to_configure : in ewok.exported.dma.t_config_mask; + caller_id : in ewok.tasks_shared.t_task_id; + success : out boolean) + is + soc_dma_id : soc.dma.t_dma_periph_index; + soc_stream_id : soc.dma.t_stream_index; + soc_dma_config : soc.dma.interfaces.t_dma_config; + ok : boolean; + begin + + if not to_configure.buffer_size then + user_config.size := registered_dma(index).user_config.size; + else + registered_dma(index).user_config.size := user_config.size; + end if; + + if to_configure.buffer_in then + registered_dma(index).user_config.in_addr := user_config.in_addr; + end if; + + if to_configure.buffer_out then + registered_dma(index).user_config.out_addr := user_config.out_addr; + end if; + + if to_configure.mode then + registered_dma(index).user_config.mode := user_config.mode; + end if; + + if to_configure.priority then + case user_config.transfer_dir is + when PERIPHERAL_TO_MEMORY => + registered_dma(index).user_config.out_priority := + user_config.out_priority; + + when MEMORY_TO_PERIPHERAL => + registered_dma(index).user_config.in_priority := + user_config.in_priority; + + when MEMORY_TO_MEMORY => + debug.log ("ewok.dma.reconfigure_stream(): MEMORY_TO_MEMORY not implemented"); + success := false; + return; + end case; + end if; + + if to_configure.direction then + registered_dma(index).user_config.transfer_dir := + user_config.transfer_dir; + end if; + + if to_configure.handlers then + case user_config.transfer_dir is + when PERIPHERAL_TO_MEMORY => + registered_dma(index).user_config.out_handler := + user_config.out_handler; + + ewok.interrupts.set_interrupt_handler + (soc.interrupts.t_interrupt'val + (registered_dma(index).devinfo.all.intr_num), + ewok.interrupts.to_handler_access (user_config.out_handler), + caller_id, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then + raise program_error; + end if; + + when MEMORY_TO_PERIPHERAL => + registered_dma(index).user_config.in_handler := + user_config.in_handler; + + ewok.interrupts.set_interrupt_handler + (soc.interrupts.t_interrupt'val + (registered_dma(index).devinfo.all.intr_num), + ewok.interrupts.to_handler_access (user_config.in_handler), + caller_id, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then + raise program_error; + end if; + + when MEMORY_TO_MEMORY => + debug.log ("ewok.dma.reconfigure_stream(): MEMORY_TO_MEMORY not implemented"); + success := false; + return; + end case; + end if; + + -- + -- Check if we enough elements to enable the DMA + -- + + if not is_config_complete (registered_dma(index).user_config) then + debug.log ("ewok.dma.reconfigure_stream(): incomplete configuration"); + success := false; + return; + end if; + + -- + -- Configuring the DMA + -- + + soc_dma_id := soc.dma.t_dma_periph_index + (registered_dma(index).user_config.controller); + + soc_stream_id := soc.dma.t_stream_index + (registered_dma(index).user_config.stream); + + soc_dma_config := + (dma_id => soc_dma_id, + stream => soc_stream_id, + channel => soc.dma.t_channel_index'val + (registered_dma(index).user_config.channel), + bytes => registered_dma(index).user_config.size, + in_addr => registered_dma(index).user_config.in_addr, + in_priority => soc.dma.interfaces.t_priority_level + (registered_dma(index).user_config.in_priority), + in_handler => registered_dma(index).user_config.in_handler, + out_addr => registered_dma(index).user_config.out_addr, + out_priority => soc.dma.interfaces.t_priority_level + (registered_dma(index).user_config.out_priority), + out_handler => registered_dma(index).user_config.out_handler, + flow_controller => soc.dma.interfaces.t_flow_controller + (registered_dma(index).user_config.flow_controller), + transfer_dir => soc.dma.interfaces.t_transfer_dir + (registered_dma(index).user_config.transfer_dir), + mode => soc.dma.interfaces.t_mode + (registered_dma(index).user_config.mode), + data_size => soc.dma.interfaces.t_data_size + (registered_dma(index).user_config.data_size), + memory_inc => boolean + (registered_dma(index).user_config.memory_inc), + periph_inc => boolean + (registered_dma(index).user_config.periph_inc), + mem_burst_size => soc.dma.interfaces.t_burst_size + (registered_dma(index).user_config.mem_burst_size), + periph_burst_size => soc.dma.interfaces.t_burst_size + (registered_dma(index).user_config.periph_burst_size)); + + soc.dma.interfaces.reconfigure_stream + (soc_dma_id, soc_stream_id, soc_dma_config, + soc.dma.interfaces.t_config_mask (to_configure)); + + registered_dma(index).status := DMA_CONFIGURED; + + soc.dma.interfaces.enable_stream (soc_dma_id, soc_stream_id); + + success := true; + + end reconfigure_stream; + + + procedure init_stream + (user_config : in ewok.exported.dma.t_dma_user_config; + caller_id : in ewok.tasks_shared.t_task_id; + index : out ewok.dma_shared.t_registered_dma_index; + success : out boolean) + is + soc_dma_id : soc.dma.t_dma_periph_index; + soc_stream_id : soc.dma.t_stream_index; + soc_dma_config : soc.dma.interfaces.t_dma_config; + ok : boolean; + begin + + -- Find a free entry in the registered_dma array + get_registered_dma_entry (index, ok); + if not ok then + debug.log ("ewok.dma.init(): no DMA entry available"); + success := false; + return; + end if; + + -- Copy the user configuration + registered_dma(index).user_config := user_config; + registered_dma(index).task_id := caller_id; + registered_dma(index).status := DMA_INITIALIZED; + registered_dma(index).devinfo := + c.socinfo.soc_devmap_find_dma_device + (user_config.controller, user_config.stream); + + if registered_dma(index).devinfo = NULL then + debug.log ("ewok.dma.init(): unknown DMA device"); + success := false; + return; + end if; + + -- Set up the interrupt handler + case user_config.transfer_dir is + when PERIPHERAL_TO_MEMORY => + if user_config.out_handler /= 0 then + ewok.interrupts.set_interrupt_handler + (soc.interrupts.t_interrupt'val + (registered_dma(index).devinfo.all.intr_num), + ewok.interrupts.to_handler_access (user_config.out_handler), + caller_id, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then + raise program_error; + end if; + end if; + + when MEMORY_TO_PERIPHERAL => + if user_config.in_handler /= 0 then + ewok.interrupts.set_interrupt_handler + (soc.interrupts.t_interrupt'val + (registered_dma(index).devinfo.all.intr_num), + ewok.interrupts.to_handler_access (user_config.in_handler), + caller_id, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then + raise program_error; + end if; + end if; + + when MEMORY_TO_MEMORY => + debug.log ("ewok.dma.init(): MEMORY_TO_MEMORY not implemented"); + success := false; + return; + end case; + + soc_dma_id := soc.dma.t_dma_periph_index (user_config.controller); + soc_stream_id := soc.dma.t_stream_index (user_config.stream); + + soc_dma_config := + (dma_id => soc_dma_id, + stream => soc_stream_id, + channel => soc.dma.t_channel_index'val (user_config.channel), + bytes => user_config.size, + in_addr => user_config.in_addr, + in_priority => soc.dma.interfaces.t_priority_level + (user_config.in_priority), + in_handler => user_config.in_handler, + out_addr => user_config.out_addr, + out_priority => soc.dma.interfaces.t_priority_level + (user_config.out_priority), + out_handler => user_config.out_handler, + flow_controller => soc.dma.interfaces.t_flow_controller + (user_config.flow_controller), + transfer_dir => soc.dma.interfaces.t_transfer_dir + (user_config.transfer_dir), + mode => soc.dma.interfaces.t_mode (user_config.mode), + data_size => soc.dma.interfaces.t_data_size + (user_config.data_size), + memory_inc => boolean (user_config.memory_inc), + periph_inc => boolean (user_config.periph_inc), + mem_burst_size => soc.dma.interfaces.t_burst_size + (user_config.mem_burst_size), + periph_burst_size => soc.dma.interfaces.t_burst_size + (user_config.periph_burst_size)); + + -- Reset the DMA stream + soc.dma.interfaces.reset_stream + (soc_dma_id, soc_stream_id); + + -- Configure the DMA stream + soc.dma.interfaces.configure_stream + (soc_dma_id, soc_stream_id, soc_dma_config); + + success := true; + + end init_stream; + + + procedure init + is + begin + soc.dma.enable_clocks; + end init; + + + procedure clear_dma_interrupts + (caller_id : in ewok.tasks_shared.t_task_id; + interrupt : in soc.interrupts.t_interrupt) + is + soc_dma_id : soc.dma.t_dma_periph_index; + soc_stream_id : soc.dma.t_stream_index; + ok : boolean; + begin + + soc.dma.get_dma_stream_from_interrupt + (interrupt, soc_dma_id, soc_stream_id, ok); + + if not ok then + raise program_error; + end if; + + if not task_owns_dma_stream (caller_id, t_controller (soc_dma_id), + t_stream (soc_stream_id)) + then + raise program_error; + end if; + + soc.dma.interfaces.clear_all_interrupts + (soc_dma_id, soc_stream_id); + + end clear_dma_interrupts; + + + procedure get_status_register + (caller_id : in ewok.tasks_shared.t_task_id; + interrupt : in soc.interrupts.t_interrupt; + status : out soc.dma.t_dma_stream_int_status; + success : out boolean) + is + soc_dma_id : soc.dma.t_dma_periph_index; + soc_stream_id : soc.dma.t_stream_index; + ok : boolean; + begin + + soc.dma.get_dma_stream_from_interrupt + (interrupt, soc_dma_id, soc_stream_id, ok); + + if not ok then + success := false; + return; + end if; + + if not task_owns_dma_stream (caller_id, + t_controller (soc_dma_id), + t_stream (soc_stream_id)) + then + success := false; + return; + end if; + + status := soc.dma.interfaces.get_interrupt_status + (soc_dma_id, soc_stream_id); + + soc.dma.interfaces.clear_all_interrupts (soc_dma_id, soc_stream_id); + + success := true; + + end get_status_register; + + +end ewok.dma; diff --git a/Ada/ewok-dma.ads b/Ada/ewok-dma.ads new file mode 100644 index 0000000..66d45ad --- /dev/null +++ b/Ada/ewok-dma.ads @@ -0,0 +1,112 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.dma_shared; +with ewok.exported.dma; +with soc.dma; +with soc.interrupts; +with c.socinfo; + + +package ewok.dma + with spark_mode => off +is + + type t_status is (DMA_UNUSED, DMA_USED, DMA_INITIALIZED, DMA_CONFIGURED); + + type t_registered_dma is record + user_config : ewok.exported.dma.t_dma_user_config; + task_id : ewok.tasks_shared.t_task_id := ID_UNUSED; + status : t_status := DMA_UNUSED; + devinfo : c.socinfo.t_device_soc_infos_access := NULL; + end record; + + registered_dma : + array (ewok.dma_shared.t_registered_dma_index) of t_registered_dma; + + + procedure get_registered_dma_entry + (index : out ewok.dma_shared.t_registered_dma_index; + success : out boolean); + + function has_same_dma_channel + (index : ewok.dma_shared.t_registered_dma_index; + config : ewok.exported.dma.t_dma_user_config) + return boolean; + + function dma_is_already_used + (config : ewok.exported.dma.t_dma_user_config) + return boolean; + + procedure enable_dma_stream + (index : in ewok.dma_shared.t_registered_dma_index); + + procedure disable_dma_stream + (index : in ewok.dma_shared.t_registered_dma_index); + + procedure enable_dma_irq + (index : in ewok.dma_shared.t_registered_dma_index); + + function is_config_complete + (user_config : ewok.exported.dma.t_dma_user_config) + return boolean; + + function sanitize_dma + (user_config : ewok.exported.dma.t_dma_user_config; + caller_id : ewok.tasks_shared.t_task_id; + to_configure : ewok.exported.dma.t_config_mask; + mode : ewok.tasks_shared.t_task_mode) + return boolean; + + function sanitize_dma_shm + (shm : ewok.exported.dma.t_dma_shm_info; + caller_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) + return boolean; + + procedure reconfigure_stream + (user_config : in out ewok.exported.dma.t_dma_user_config; + index : in ewok.dma_shared.t_registered_dma_index; + to_configure : in ewok.exported.dma.t_config_mask; + caller_id : in ewok.tasks_shared.t_task_id; + success : out boolean); + + procedure init_stream + (user_config : in ewok.exported.dma.t_dma_user_config; + caller_id : in ewok.tasks_shared.t_task_id; + index : out ewok.dma_shared.t_registered_dma_index; + success : out boolean); + + procedure init; + + procedure clear_dma_interrupts + (caller_id : in ewok.tasks_shared.t_task_id; + interrupt : in soc.interrupts.t_interrupt); + + procedure get_status_register + (caller_id : in ewok.tasks_shared.t_task_id; + interrupt : in soc.interrupts.t_interrupt; + status : out soc.dma.t_dma_stream_int_status; + success : out boolean); + +end ewok.dma; diff --git a/Ada/ewok-dma_shared.ads b/Ada/ewok-dma_shared.ads new file mode 100644 index 0000000..0783e70 --- /dev/null +++ b/Ada/ewok-dma_shared.ads @@ -0,0 +1,32 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.dma_shared + with spark_mode => off +is + + ID_DMA_UNUSED : constant := 0; + type t_user_dma_index is range ID_DMA_UNUSED .. 8; + subtype t_registered_dma_index is t_user_dma_index range 1 .. 8; + +end ewok.dma_shared; diff --git a/Ada/ewok-exti-handler.adb b/Ada/ewok-exti-handler.adb new file mode 100644 index 0000000..0e27d95 --- /dev/null +++ b/Ada/ewok-exti-handler.adb @@ -0,0 +1,195 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.gpio; use soc.gpio; +with soc.exti; use soc.exti; +with soc.syscfg; +with soc.nvic; +with soc.interrupts; +with ewok.interrupts; +with ewok.exported.gpios; use type ewok.exported.gpios.t_gpio_config_access; +with ewok.gpio; +with ewok.tasks_shared; +with ewok.devices_shared; +with ewok.isr; +with debug; + +package body ewok.exti.handler + with spark_mode => off +is + + procedure init + is + ok : boolean; + begin + + ewok.interrupts.set_interrupt_handler + (soc.interrupts.INT_EXTI0, + exti_handler'access, + ewok.tasks_shared.ID_UNUSED, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + ewok.interrupts.set_interrupt_handler + (soc.interrupts.INT_EXTI1, + exti_handler'access, + ewok.tasks_shared.ID_UNUSED, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + ewok.interrupts.set_interrupt_handler + (soc.interrupts.INT_EXTI2, + exti_handler'access, + ewok.tasks_shared.ID_UNUSED, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + ewok.interrupts.set_interrupt_handler + (soc.interrupts.INT_EXTI3, + exti_handler'access, + ewok.tasks_shared.ID_UNUSED, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + ewok.interrupts.set_interrupt_handler + (soc.interrupts.INT_EXTI4, + exti_handler'access, + ewok.tasks_shared.ID_UNUSED, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + ewok.interrupts.set_interrupt_handler + (soc.interrupts.INT_EXTI9_5, + exti_handler'access, + ewok.tasks_shared.ID_UNUSED, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + ewok.interrupts.set_interrupt_handler + (soc.interrupts.INT_EXTI15_10, + exti_handler'access, + ewok.tasks_shared.ID_UNUSED, + ewok.devices_shared.ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + end init; + + + procedure handle_line + (line : in soc.exti.t_exti_line_index; + interrupt : in soc.interrupts.t_interrupt; + frame_a : in ewok.t_stack_frame_access) + is + ref : ewok.exported.gpios.t_gpio_ref; + conf : ewok.exported.gpios.t_gpio_config_access; + task_id : ewok.tasks_shared.t_task_id; + begin + + -- Clear the EXTI pending bit for this line + soc.exti.clear_pending (line); + + -- Retrieve the configured GPIO point associated to this line + ref.pin := t_gpio_pin_index'val (t_exti_line_index'pos (line)); + ref.port := soc.syscfg.get_exti_port (ref.pin); + + -- Retrieving the GPIO configuration associated to that GPIO point. + -- Permit to get the "real" user ISR. + conf := ewok.gpio.get_config (ref); + + if conf = NULL then + soc.nvic.clear_pending_irq (soc.nvic.to_irq_number (interrupt)); + debug.log (debug.WARNING, "unable to find GPIO informations for port" & + t_gpio_port_index'image (ref.port) & ", pin" & + t_gpio_pin_index'image (ref.pin)); + else + task_id := ewok.gpio.get_task_id (ref); + + ewok.isr.postpone_isr + (interrupt, + ewok.interrupts.to_handler_access (conf.all.exti_handler), + task_id, + frame_a); + end if; + + end handle_line; + + + procedure exti_handler + (frame_a : in ewok.t_stack_frame_access) + is + intr : soc.interrupts.t_interrupt; + begin + + intr := soc.interrupts.get_interrupt; + + case intr is + when soc.interrupts.INT_EXTI0 => + handle_line (0, intr, frame_a); + + when soc.interrupts.INT_EXTI1 => + handle_line (1, intr, frame_a); + + when soc.interrupts.INT_EXTI2 => + handle_line (2, intr, frame_a); + + when soc.interrupts.INT_EXTI3 => + handle_line (3, intr, frame_a); + + when soc.interrupts.INT_EXTI4 => + handle_line (4, intr, frame_a); + + when soc.interrupts.INT_EXTI9_5 => + + for line in t_exti_line_index range 5 .. 9 loop + if soc.exti.is_line_pending (line) then + handle_line (line, intr, frame_a); + end if; + end loop; + + when soc.interrupts.INT_EXTI15_10 => + + for line in t_exti_line_index range 10 .. 15 loop + if soc.exti.is_line_pending (line) then + handle_line (line, intr, frame_a); + end if; + end loop; + + when others => raise program_error; + end case; + + end exti_handler; + +end ewok.exti.handler; diff --git a/Ada/ewok-exti-handler.ads b/Ada/ewok-exti-handler.ads new file mode 100644 index 0000000..12120af --- /dev/null +++ b/Ada/ewok-exti-handler.ads @@ -0,0 +1,33 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.exti.handler + with spark_mode => off +is + + procedure exti_handler + (frame_a : in ewok.t_stack_frame_access); + + procedure init; + +end ewok.exti.handler; diff --git a/Ada/ewok-exti-interfaces.adb b/Ada/ewok-exti-interfaces.adb new file mode 100644 index 0000000..874d948 --- /dev/null +++ b/Ada/ewok-exti-interfaces.adb @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package body ewok.exti.interfaces + with spark_mode => off +is + + procedure interfaces_init + is + begin + ewok.exti.init; + end interfaces_init; + +end ewok.exti.interfaces; diff --git a/Ada/ewok-exti-interfaces.ads b/Ada/ewok-exti-interfaces.ads new file mode 100644 index 0000000..55118b6 --- /dev/null +++ b/Ada/ewok-exti-interfaces.ads @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.exti.interfaces + with spark_mode => off +is + + procedure interfaces_init + with + convention => c, + export => true, + external_name => "exti_init"; + +end ewok.exti.interfaces; diff --git a/Ada/ewok-exti.adb b/Ada/ewok-exti.adb new file mode 100644 index 0000000..25362a5 --- /dev/null +++ b/Ada/ewok-exti.adb @@ -0,0 +1,144 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.exti; use soc.exti; +with soc.nvic; +with soc.syscfg; +with soc.gpio; +with ewok.exported.gpios; use ewok.exported.gpios; +with ewok.exti.handler; + +package body ewok.exti + with spark_mode => off +is + + procedure init + is + begin + ewok.exti.handler.init; + soc.exti.init; + end init; + + + procedure enable + (ref : in ewok.exported.gpios.t_gpio_ref) + is + line : soc.exti.t_exti_line_index; + begin + + line := soc.exti.t_exti_line_index'val + (soc.gpio.t_gpio_pin_index'pos (ref.pin)); + + soc.exti.enable (line); + + case ref.pin is + when 0 => soc.nvic.enable_irq (soc.nvic.EXTI_Line_0); + when 1 => soc.nvic.enable_irq (soc.nvic.EXTI_Line_1); + when 2 => soc.nvic.enable_irq (soc.nvic.EXTI_Line_2); + when 3 => soc.nvic.enable_irq (soc.nvic.EXTI_Line_3); + when 4 => soc.nvic.enable_irq (soc.nvic.EXTI_Line_4); + when 5 .. 9 => soc.nvic.enable_irq (soc.nvic.EXTI_Line_5_9); + when 10 .. 15 => soc.nvic.enable_irq (soc.nvic.EXTI_Line_10_15); + end case; + + end enable; + + + procedure disable + (ref : in ewok.exported.gpios.t_gpio_ref) + is + line : soc.exti.t_exti_line_index; + begin + line := soc.exti.t_exti_line_index'val + (soc.gpio.t_gpio_pin_index'pos (ref.pin)); + soc.exti.disable (line); + end disable; + + + function is_used + (ref : ewok.exported.gpios.t_gpio_ref) + return boolean + is + line : constant soc.exti.t_exti_line_index := + soc.exti.t_exti_line_index'val + (soc.gpio.t_gpio_pin_index'pos (ref.pin)); + begin + return exti_line_registered (line) or + soc.exti.is_enabled (line); + end is_used; + + + procedure register + (conf : in ewok.exported.gpios.t_gpio_config_access; + success : out boolean) + is + line : constant soc.exti.t_exti_line_index := + soc.exti.t_exti_line_index'val + (soc.gpio.t_gpio_pin_index'pos (conf.all.kref.pin)); + begin + + -- Is EXTI setting required? + if not conf.all.settings.set_exti then + success := true; + return; + end if; + + -- Is EXTI line already registered? + if exti_line_registered (line) then + success := false; + return; + end if; + + -- If the line is already set, thus it's already used. + -- We return in error. + if soc.exti.is_enabled (line) then + success := false; + return; + end if; + + -- Configuring the triggers + case conf.all.exti_trigger is + when GPIO_EXTI_TRIGGER_NONE => + success := true; + return; + + when GPIO_EXTI_TRIGGER_RISE => + soc.exti.EXTI.RTSR.line(line) := TRIGGER_ENABLED; + + when GPIO_EXTI_TRIGGER_FALL => + soc.exti.EXTI.FTSR.line(line) := TRIGGER_ENABLED; + + when GPIO_EXTI_TRIGGER_BOTH => + soc.exti.EXTI.RTSR.line(line) := TRIGGER_ENABLED; + soc.exti.EXTI.FTSR.line(line) := TRIGGER_ENABLED; + end case; + + -- Configuring the SYSCFG register + soc.syscfg.set_exti_port (conf.all.kref.pin, conf.all.kref.port); + + exti_line_registered (line) := true; + success := true; + + end register; + + +end ewok.exti; diff --git a/Ada/ewok-exti.ads b/Ada/ewok-exti.ads new file mode 100644 index 0000000..e0be1ac --- /dev/null +++ b/Ada/ewok-exti.ads @@ -0,0 +1,63 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.exti; +with ewok.exported.gpios; + +package ewok.exti + with spark_mode => off +is + + exti_line_registered : array (soc.exti.t_exti_line_index) of boolean + := (others => false); + + --------------- + -- Functions -- + --------------- + + -- \brief initialize the EXTI module + procedure init; + + + -- \brief Disable a given line + -- \returns 0 of EXTI line has been properly disabled, or non-null value + procedure disable + (ref : in ewok.exported.gpios.t_gpio_ref); + + -- Enable (i.e. activate at EXTI and NVIC level) the EXTI line. + -- This is done by calling soc_exti_enable() only. No generic call here. + procedure enable + (ref : in ewok.exported.gpios.t_gpio_ref); + + -- Return true if EXTI line is already registered. + function is_used + (ref : ewok.exported.gpios.t_gpio_ref) + return boolean; + + -- \brief Register a new EXTI line. + -- Check that the EXTI line is not already registered. + procedure register + (conf : in ewok.exported.gpios.t_gpio_config_access; + success : out boolean); + +end ewok.exti; + diff --git a/Ada/ewok-gpio.adb b/Ada/ewok-gpio.adb new file mode 100644 index 0000000..bb26cd0 --- /dev/null +++ b/Ada/ewok-gpio.adb @@ -0,0 +1,218 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with debug; +with ewok.exported.gpios; use ewok.exported.gpios; +with soc.gpio; use type soc.gpio.t_GPIO_port_access; + use type soc.gpio.t_gpio_pin_index; +with soc.rcc; + +package body ewok.gpio + with spark_mode => off +is + + + function to_pin_alt_func + (u : unsigned_32) return soc.gpio.t_pin_alt_func + is + pragma warnings (off); + function conv is new ada.unchecked_conversion + (unsigned_32, soc.gpio.t_pin_alt_func); + pragma warnings (on); + begin + if u > 15 then + raise program_error; + end if; + return conv (u); + end to_pin_alt_func; + + + function is_used + (ref : ewok.exported.gpios.t_gpio_ref) + return boolean + is + begin + return gpio_points(ref.port, ref.pin).used; + end is_used; + + + procedure register + (task_id : in ewok.tasks_shared.t_task_id; + device_id : in ewok.devices_shared.t_device_id; + conf_a : in ewok.exported.gpios.t_gpio_config_access; + success : out boolean) + is + ref : constant ewok.exported.gpios.t_gpio_ref := conf_a.all.kref; + begin + if gpio_points(ref.port, ref.pin).used then + debug.log (debug.WARNING, "Registering GPIO: port" & + soc.gpio.t_gpio_port_index'image (ref.port) & ", pin" & + soc.gpio.t_gpio_pin_index'image (ref.pin) & " is already used."); + success := false; + else + gpio_points(ref.port, ref.pin).used := true; + gpio_points(ref.port, ref.pin).task_id := task_id; + gpio_points(ref.port, ref.pin).device_id := device_id; + gpio_points(ref.port, ref.pin).config := conf_a; + success := true; + end if; + end register; + + + procedure config + (conf : in ewok.exported.gpios.t_gpio_config_access) + is + gpio : soc.gpio.t_GPIO_port_access; + begin + + -- Enable RCC + case conf.all.kref.port is + when soc.gpio.GPIO_PA => soc.rcc.RCC.AHB1.GPIOAEN := true; + when soc.gpio.GPIO_PB => soc.rcc.RCC.AHB1.GPIOBEN := true; + when soc.gpio.GPIO_PC => soc.rcc.RCC.AHB1.GPIOCEN := true; + when soc.gpio.GPIO_PD => soc.rcc.RCC.AHB1.GPIODEN := true; + when soc.gpio.GPIO_PE => soc.rcc.RCC.AHB1.GPIOEEN := true; + when soc.gpio.GPIO_PF => soc.rcc.RCC.AHB1.GPIOFEN := true; + when soc.gpio.GPIO_PG => soc.rcc.RCC.AHB1.GPIOGEN := true; + when soc.gpio.GPIO_PH => soc.rcc.RCC.AHB1.GPIOHEN := true; + when soc.gpio.GPIO_PI => soc.rcc.RCC.AHB1.GPIOIEN := true; + end case; + + gpio := soc.gpio.get_port_access (conf.all.kref.port); + + if conf.all.settings.set_mode then + gpio.all.MODER.pin (conf.all.kref.pin) := + soc.gpio.t_pin_mode'val + (t_interface_gpio_mode'pos (conf.all.mode)); + end if; + + if conf.all.settings.set_type then + gpio.all.OTYPER.pin (conf.all.kref.pin) := + soc.gpio.t_pin_output_type'val + (t_interface_gpio_type'pos (conf.all.otype)); + end if; + + if conf.all.settings.set_speed then + gpio.all.OSPEEDR.pin (conf.all.kref.pin) := + soc.gpio.t_pin_output_speed'val + (t_interface_gpio_speed'pos (conf.all.ospeed)); + end if; + + if conf.all.settings.set_pupd then + gpio.all.PUPDR.pin (conf.all.kref.pin) := + soc.gpio.t_pin_pupd'val + (t_interface_gpio_pupd'pos (conf.all.pupd)); + end if; + + if conf.all.settings.set_bsr_r then + gpio.all.BSRR.BR (conf.all.kref.pin) := types.to_bit (conf.all.bsr_r); + end if; + + if conf.all.settings.set_bsr_s then + gpio.all.BSRR.BS (conf.all.kref.pin) := types.to_bit (conf.all.bsr_s); + end if; + + -- FIXME - Writing to LCKR register requires a specific sequence + -- describe in section 8.4.8 (RM 00090) + if conf.all.settings.set_lck then + gpio.all.LCKR.pin (conf.all.kref.pin) := + soc.gpio.t_pin_lock'val (conf.all.lck); + end if; + + if conf.all.settings.set_af then + if conf.all.kref.pin < 8 then + gpio.all.AFRL.pin (conf.all.kref.pin) := + to_pin_alt_func (conf.all.af); + else + gpio.all.AFRH.pin (conf.all.kref.pin) := + to_pin_alt_func (conf.all.af); + end if; + end if; + + end config; + + + procedure write_pin + (ref : in ewok.exported.gpios.t_gpio_ref; + value : in bit) + is + port : soc.gpio.t_GPIO_port_access; + begin + port := soc.gpio.get_port_access (ref.port); + port.all.ODR.pin (ref.pin) := value; + end write_pin; + + + function read_pin + (ref : ewok.exported.gpios.t_gpio_ref) + return bit + is + port : soc.gpio.t_GPIO_port_access; + begin + port := soc.gpio.get_port_access (ref.port); + return port.all.IDR.pin (ref.pin); + end read_pin; + + + function belong_to + (task_id : ewok.tasks_shared.t_task_id; + ref : ewok.exported.gpios.t_gpio_ref) + return boolean + is + begin + if gpio_points(ref.port, ref.pin).used and + gpio_points(ref.port, ref.pin).task_id = task_id + then + return true; + else + return false; + end if; + end belong_to; + + + function get_task_id + (ref : in ewok.exported.gpios.t_gpio_ref) + return ewok.tasks_shared.t_task_id + is + begin + return gpio_points(ref.port, ref.pin).task_id; + end get_task_id; + + + function get_device_id + (ref : in ewok.exported.gpios.t_gpio_ref) + return ewok.devices_shared.t_device_id + is + begin + return gpio_points(ref.port, ref.pin).device_id; + end get_device_id; + + + function get_config + (ref : in ewok.exported.gpios.t_gpio_ref) + return ewok.exported.gpios.t_gpio_config_access + is + begin + return gpio_points(ref.port, ref.pin).config; + end get_config; + +end ewok.gpio; diff --git a/Ada/ewok-gpio.ads b/Ada/ewok-gpio.ads new file mode 100644 index 0000000..d587a8d --- /dev/null +++ b/Ada/ewok-gpio.ads @@ -0,0 +1,84 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.gpio; +with ewok.exported.gpios; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.devices_shared; use ewok.devices_shared; + +package ewok.gpio + with spark_mode => off +is + + function is_used + (ref : ewok.exported.gpios.t_gpio_ref) + return boolean; + + procedure register + (task_id : in ewok.tasks_shared.t_task_id; + device_id : in ewok.devices_shared.t_device_id; + conf_a : in ewok.exported.gpios.t_gpio_config_access; + success : out boolean); + + procedure config + (conf : in ewok.exported.gpios.t_gpio_config_access); + + procedure write_pin + (ref : in ewok.exported.gpios.t_gpio_ref; + value : in bit); + + function read_pin + (ref : in ewok.exported.gpios.t_gpio_ref) + return bit; + + function belong_to + (task_id : in ewok.tasks_shared.t_task_id; + ref : in ewok.exported.gpios.t_gpio_ref) + return boolean; + + function get_task_id + (ref : in ewok.exported.gpios.t_gpio_ref) + return ewok.tasks_shared.t_task_id; + + function get_device_id + (ref : in ewok.exported.gpios.t_gpio_ref) + return ewok.devices_shared.t_device_id; + + function get_config + (ref : in ewok.exported.gpios.t_gpio_ref) + return ewok.exported.gpios.t_gpio_config_access; + +private + + type t_gpio_state is record + used : boolean := false; + task_id : ewok.tasks_shared.t_task_id; + device_id : ewok.devices_shared.t_device_id; + config : ewok.exported.gpios.t_gpio_config_access; + end record; + + -- Keep track of used GPIO points + gpio_points : array (soc.gpio.t_gpio_port_index, soc.gpio.t_gpio_pin_index) + of t_gpio_state := + (others => (others => (false, ID_UNUSED, ID_DEV_UNUSED, NULL))); + +end ewok.gpio; diff --git a/Ada/ewok-interrupts-handler.adb b/Ada/ewok-interrupts-handler.adb new file mode 100644 index 0000000..b4982f4 --- /dev/null +++ b/Ada/ewok-interrupts-handler.adb @@ -0,0 +1,185 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with system.machine_code; + +with m4.scb; +with m4.systick; +with debug; +with soc.interrupts; use soc.interrupts; +with ewok.tasks; use ewok.tasks; +with ewok.sched; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.devices_shared; use type ewok.devices_shared.t_device_id; +with ewok.isr; + +package body ewok.interrupts.handler + with spark_mode => off +is + + function hardfault_handler + (frame_a : ewok.t_stack_frame_access) return ewok.t_stack_frame_access + is + cfsr : constant m4.scb.t_SCB_CFSR := m4.scb.SCB.CFSR; + begin + + if cfsr.MMFSR.IACCVIOL then debug.log (debug.WARNING, "+cfsr.MMFSR.IACCVIOL"); end if; + if cfsr.MMFSR.DACCVIOL then debug.log (debug.WARNING, "+cfsr.MMFSR.DACCVIOL"); end if; + if cfsr.MMFSR.MUNSTKERR then debug.log (debug.WARNING, "+cfsr.MMFSR.MUNSTKERR"); end if; + if cfsr.MMFSR.MSTKERR then debug.log (debug.WARNING, "+cfsr.MMFSR.MSTKERR"); end if; + if cfsr.MMFSR.MLSPERR then debug.log (debug.WARNING, "+cfsr.MMFSR.MLSPERR"); end if; + if cfsr.MMFSR.MMARVALID then debug.log (debug.WARNING, "+cfsr.MMFSR.MMARVALID"); end if; + + if cfsr.BFSR.IBUSERR then debug.log (debug.WARNING, "+cfsr.BFSR.IBUSERR"); end if; + if cfsr.BFSR.PRECISERR then debug.log (debug.WARNING, "+cfsr.BFSR.PRECISERR"); end if; + if cfsr.BFSR.IMPRECISERR then debug.log (debug.WARNING, "+cfsr.BFSR.IMPRECISERR"); end if; + if cfsr.BFSR.UNSTKERR then debug.log (debug.WARNING, "+cfsr.BFSR.UNSTKERR"); end if; + if cfsr.BFSR.STKERR then debug.log (debug.WARNING, "+cfsr.BFSR.STKERR"); end if; + if cfsr.BFSR.LSPERR then debug.log (debug.WARNING, "+cfsr.BFSR.LSPERR"); end if; + if cfsr.BFSR.BFARVALID then debug.log (debug.WARNING, "+cfsr.BFSR.BFARVALID"); end if; + + if cfsr.UFSR.UNDEFINSTR then debug.log (debug.WARNING, "+cfsr.UFSR.UNDEFINSTR"); end if; + if cfsr.UFSR.INVSTATE then debug.log (debug.WARNING, "+cfsr.UFSR.INVSTATE"); end if; + if cfsr.UFSR.INVPC then debug.log (debug.WARNING, "+cfsr.UFSR.INVPC"); end if; + if cfsr.UFSR.NOCP then debug.log (debug.WARNING, "+cfsr.UFSR.NOCP"); end if; + if cfsr.UFSR.UNALIGNED then debug.log (debug.WARNING, "+cfsr.UFSR.UNALIGNED"); end if; + if cfsr.UFSR.DIVBYZERO then debug.log (debug.WARNING, "+cfsr.UFSR.DIVBYZERO"); end if; + + debug.log (debug.WARNING, + "registers (frame at " & + system_address'image (to_system_address (frame_a)) & + ", EXC_RETURN " & unsigned_32'image (frame_a.all.LR) & ")"); + + debug.log (debug.WARNING, + "R0 " & unsigned_32'image (frame_a.all.R0) & + ", R1 " & unsigned_32'image (frame_a.all.R1) & + ", R2 " & unsigned_32'image (frame_a.all.R2) & + ", R3 " & unsigned_32'image (frame_a.all.R3)); + + debug.log (debug.WARNING, + "R4 " & unsigned_32'image (frame_a.all.R4) & + ", R5 " & unsigned_32'image (frame_a.all.R5) & + ", R6 " & unsigned_32'image (frame_a.all.R6) & + ", R7 " & unsigned_32'image (frame_a.all.R7)); + + debug.log (debug.WARNING, + "R8 " & unsigned_32'image (frame_a.all.R8) & + ", R9 " & unsigned_32'image (frame_a.all.R9) & + ", R10 " & unsigned_32'image (frame_a.all.R10) & + ", R11 " & unsigned_32'image (frame_a.all.R11)); + + debug.log (debug.WARNING, + "R12 " & unsigned_32'image (frame_a.all.R12) & + ", PC " & unsigned_32'image (frame_a.all.PC) & + ", LR " & unsigned_32'image (frame_a.all.LR)); + + debug.panic("panic!"); + + return frame_a; + + end hardfault_handler; + + + function systick_default_handler + (frame_a : ewok.t_stack_frame_access) + return ewok.t_stack_frame_access + is + begin + m4.systick.increment; + return frame_a; + end systick_default_handler; + + + function default_sub_handler + (frame_a : t_stack_frame_access) + return t_stack_frame_access + is + it : t_interrupt; + current_id : ewok.tasks_shared.t_task_id; + new_frame_a : t_stack_frame_access; + ttype : t_task_type; + begin + + it := soc.interrupts.get_interrupt; + interrupt_table(it).count := interrupt_table(it).count + 1; + + -- FIXME - Differenciation between sync / async ISR is not clear. + -- Maybe using a specific flag: + -- "if interrupt_table(it).async then (...)" + + -- External interrupt + if it >= INT_WWDG then + if interrupt_table(it).task_id /= ewok.tasks_shared.ID_UNUSED + then + -- User or kernel ISR: asynchronous execution (postponed) + ewok.isr.postpone_isr + (it, + interrupt_table(it).handler, + interrupt_table(it).task_id, + frame_a); + elsif interrupt_table(it).handler /= NULL + then + -- Execute kernel ISR w/o associated device (handler is not + -- postponed) + interrupt_table(it).handler (frame_a); + else + debug.panic ("Unhandled interrupt " & t_interrupt'image (it)); + end if; + new_frame_a := frame_a; + + -- System exceptions are synchronously executed (handler is not postponed) + else + + if interrupt_table(it).htype = DEFAULT_HANDLER then + interrupt_table(it).handler (frame_a); + new_frame_a := frame_a; + else + new_frame_a := interrupt_table(it).task_switch_handler (frame_a); + end if; + end if; + + -- Task's execution mode must be transmitted to the Default_Handler + -- to run it with the proper privilege (set in the CONTROL register). + -- The current function uses R0 and R1 registers to return the + -- following values: + -- R0 - address of the task frame + -- R1 - execution mode + + current_id := ewok.sched.get_current; + if current_id /= ID_UNUSED then + ttype := ewok.tasks.tasks_list(current_id).ttype; + else + ttype := TASK_TYPE_KERNEL; + end if; + + system.machine_code.asm + ("mov r1, %0", + inputs => t_task_type'asm_input ("r", ttype), + clobber => "r1", + volatile => true); + + return new_frame_a; + + end default_sub_handler; + + +end ewok.interrupts.handler; diff --git a/Ada/ewok-interrupts-handler.ads b/Ada/ewok-interrupts-handler.ads new file mode 100644 index 0000000..3dd697c --- /dev/null +++ b/Ada/ewok-interrupts-handler.ads @@ -0,0 +1,41 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.interrupts.handler + with spark_mode => off +is + + function hardfault_handler + (frame_a : ewok.t_stack_frame_access) return ewok.t_stack_frame_access; + + function systick_default_handler + (frame_a : ewok.t_stack_frame_access) return ewok.t_stack_frame_access; + + function default_sub_handler + (frame_a : t_stack_frame_access) return t_stack_frame_access + with + convention => c, + export => true, + external_name => "Default_SubHandler"; + +end ewok.interrupts.handler; diff --git a/Ada/ewok-interrupts-interfaces.adb b/Ada/ewok-interrupts-interfaces.adb new file mode 100644 index 0000000..d18540b --- /dev/null +++ b/Ada/ewok-interrupts-interfaces.adb @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package body ewok.interrupts.interfaces + with spark_mode => off +is + + procedure init + is + begin + ewok.interrupts.init; + end init; + +end ewok.interrupts.interfaces; diff --git a/Ada/ewok-interrupts-interfaces.ads b/Ada/ewok-interrupts-interfaces.ads new file mode 100644 index 0000000..634d4f9 --- /dev/null +++ b/Ada/ewok-interrupts-interfaces.ads @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.interrupts.interfaces + with spark_mode => off +is + + procedure init + with + convention => c, + export => true, + external_name => "interrupts_init"; + +end ewok.interrupts.interfaces; diff --git a/Ada/ewok-interrupts.adb b/Ada/ewok-interrupts.adb new file mode 100644 index 0000000..67a195a --- /dev/null +++ b/Ada/ewok-interrupts.adb @@ -0,0 +1,136 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.interrupts.handler; +with ewok.tasks_shared; use type ewok.tasks_shared.t_task_id; +with m4.scb; +with soc.nvic; + +package body ewok.interrupts + with spark_mode => off +is + + procedure init + is + begin + + for i in interrupt_table'range loop + interrupt_table(i) := + (htype => DEFAULT_HANDLER, + handler => NULL, + task_id => ewok.tasks_shared.ID_UNUSED, + device_id => ewok.devices_shared.ID_DEV_UNUSED, + count => 0); + end loop; + + interrupt_table(soc.interrupts.INT_HARDFAULT) := + (htype => TASK_SWITCH_HANDLER, + task_switch_handler => + ewok.interrupts.handler.hardfault_handler'access, + task_id => ewok.tasks_shared.ID_UNUSED, + device_id => ewok.devices_shared.ID_DEV_UNUSED, + count => 0); + + + interrupt_table(soc.interrupts.INT_SYSTICK) := + (htype => TASK_SWITCH_HANDLER, + task_switch_handler => + ewok.interrupts.handler.systick_default_handler'access, + task_id => ewok.tasks_shared.ID_UNUSED, + device_id => ewok.devices_shared.ID_DEV_UNUSED, + count => 0); + + m4.scb.SCB.SHPR1.mem_fault.priority := 0; + m4.scb.SCB.SHPR1.bus_fault.priority := 1; + m4.scb.SCB.SHPR1.usage_fault.priority := 2; + m4.scb.SCB.SHPR2.svc_call.priority := 3; + m4.scb.SCB.SHPR3.pendsv.priority := 4; + m4.scb.SCB.SHPR3.systick.priority := 5; + + for irq in soc.nvic.NVIC.IPR'range loop + soc.nvic.NVIC.IPR(irq).priority := 7; + end loop; + + end init; + + + function is_interrupt_already_used + (interrupt : soc.interrupts.t_interrupt) return boolean + is + begin + return interrupt_table(interrupt).task_id /= ewok.tasks_shared.ID_UNUSED; + end is_interrupt_already_used; + + + procedure set_interrupt_handler + (interrupt : in soc.interrupts.t_interrupt; + handler : in t_interrupt_handler_access; + task_id : in ewok.tasks_shared.t_task_id; + device_id : in ewok.devices_shared.t_device_id; + success : out boolean) + is + begin + + if handler = NULL then + raise program_error; + end if; + + interrupt_table(interrupt).handler := handler; + interrupt_table(interrupt).task_id := task_id; + interrupt_table(interrupt).device_id := device_id; + + success := true; + + end set_interrupt_handler; + + + procedure set_task_switching_handler + (interrupt : in soc.interrupts.t_interrupt; + handler : in t_interrupt_task_switch_handler_access; + task_id : in ewok.tasks_shared.t_task_id; + device_id : in ewok.devices_shared.t_device_id; + success : out boolean) + is + begin + + if handler = NULL then + raise program_error; + end if; + + interrupt_table(interrupt) := + (TASK_SWITCH_HANDLER, task_id, device_id, 0, handler); + + success := true; + + end set_task_switching_handler; + + + function get_device_from_interrupt + (interrupt : soc.interrupts.t_interrupt) + return ewok.devices_shared.t_device_id + is + begin + return interrupt_table(interrupt).device_id; + end get_device_from_interrupt; + + +end ewok.interrupts; diff --git a/Ada/ewok-interrupts.ads b/Ada/ewok-interrupts.ads new file mode 100644 index 0000000..a266a6c --- /dev/null +++ b/Ada/ewok-interrupts.ads @@ -0,0 +1,89 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ada.unchecked_conversion; +with soc.interrupts; +with ewok.tasks_shared; +with ewok.devices_shared; + +package ewok.interrupts + with spark_mode => off +is + + type t_interrupt_handler_access is access + procedure (frame_a : in ewok.t_stack_frame_access); + + type t_interrupt_task_switch_handler_access is access + function (frame_a : ewok.t_stack_frame_access) + return ewok.t_stack_frame_access; + + type t_handler_type is (DEFAULT_HANDLER, TASK_SWITCH_HANDLER); + + type t_interrupt_cell (htype : t_handler_type := DEFAULT_HANDLER) is record + task_id : ewok.tasks_shared.t_task_id; + device_id : ewok.devices_shared.t_device_id; + count : unsigned_32; + + case htype is + when DEFAULT_HANDLER => + handler : t_interrupt_handler_access; + when TASK_SWITCH_HANDLER => + task_switch_handler : t_interrupt_task_switch_handler_access; + end case; + + end record; + + type t_interrupt_cell_access is access all t_interrupt_cell; + + interrupt_table : array (soc.interrupts.t_interrupt) of aliased t_interrupt_cell; + + + function to_system_address is new ada.unchecked_conversion + (t_interrupt_handler_access, system_address); + + function to_handler_access is new ada.unchecked_conversion + (system_address, t_interrupt_handler_access); + + procedure init; + + function is_interrupt_already_used + (interrupt : soc.interrupts.t_interrupt) return boolean; + + procedure set_interrupt_handler + (interrupt : in soc.interrupts.t_interrupt; + handler : in t_interrupt_handler_access; + task_id : in ewok.tasks_shared.t_task_id; + device_id : in ewok.devices_shared.t_device_id; + success : out boolean); + + procedure set_task_switching_handler + (interrupt : in soc.interrupts.t_interrupt; + handler : in t_interrupt_task_switch_handler_access; + task_id : in ewok.tasks_shared.t_task_id; + device_id : in ewok.devices_shared.t_device_id; + success : out boolean); + + function get_device_from_interrupt + (interrupt : soc.interrupts.t_interrupt) + return ewok.devices_shared.t_device_id; + +end ewok.interrupts; diff --git a/Ada/ewok-ipc.adb b/Ada/ewok-ipc.adb new file mode 100644 index 0000000..2c14965 --- /dev/null +++ b/Ada/ewok-ipc.adb @@ -0,0 +1,115 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ada.unchecked_conversion; + +package body ewok.ipc + with spark_mode => off +is + + function to_task_id + (eid : t_extended_task_id) return ewok.tasks_shared.t_task_id + is + pragma warnings (off); -- size may differ + function convert is new ada.unchecked_conversion + (t_extended_task_id, ewok.tasks_shared.t_task_id); + pragma warnings (on); + ret : constant ewok.tasks_shared.t_task_id := convert (eid); + begin + if ret'valid then + return ret; + else + raise constraint_error; + end if; + end to_task_id; + + + function to_ext_task_id + (id : ewok.tasks_shared.t_task_id) return t_extended_task_id + is + pragma warnings (off); -- size may differ + function convert is new ada.unchecked_conversion + (ewok.tasks_shared.t_task_id, t_extended_task_id); + pragma warnings (on); + ret : constant t_extended_task_id := convert (id); + begin + if ret'valid then + return ret; + else + raise constraint_error; + end if; + end to_ext_task_id; + + + procedure init_endpoint + (ep : in out t_endpoint) + is + begin + ep.from := ewok.ipc.ID_UNUSED; + ep.to := ewok.ipc.ID_UNUSED; + ep.state := FREE; + ep.size := 0; + for i in ep.data'range loop + ep.data(i) := 0; + end loop; + end init_endpoint; + + + procedure init_endpoints + is + begin + for i in ipc_endpoints'range loop + init_endpoint (ipc_endpoints(i)); + end loop; + end init_endpoints; + + + procedure get_endpoint + (endpoint_a : out t_endpoint_access; + success : out boolean) + is + begin + + for i in ipc_endpoints'range loop + if ipc_endpoints(i).state = FREE then + ipc_endpoints(i).state := READY; + endpoint_a := ipc_endpoints(i)'access; + success := true; + return; + end if; + end loop; + + endpoint_a := NULL; + success := false; + end get_endpoint; + + + procedure release_endpoint + (endpoint_a : in t_endpoint_access) + is + begin + init_endpoint (endpoint_a.all); + end release_endpoint; + + +end ewok.ipc; diff --git a/Ada/ewok-ipc.ads b/Ada/ewok-ipc.ads new file mode 100644 index 0000000..76450d9 --- /dev/null +++ b/Ada/ewok-ipc.ads @@ -0,0 +1,111 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok.tasks_shared; + +package ewok.ipc + with spark_mode => off +is + + MAX_IPC_MSG_SIZE : constant := 128; + ENDPOINTS_POOL_SIZE : constant := 10; + + -- + -- IPC EndPoints + -- + + type t_endpoint_state is ( + -- IPC endpoint is unused + FREE, + -- IPC endpoint is used and is ready for message passing + READY, + -- send() block until the receiver read the message + WAIT_FOR_RECEIVER); + + type t_extended_task_id is + (ID_UNUSED, + ID_APP1, + ID_APP2, + ID_APP3, + ID_APP4, + ID_APP5, + ID_APP6, + ID_APP7, + ANY_APP) + with size => 8; + + for t_extended_task_id use + (ID_UNUSED => 0, + ID_APP1 => 1, + ID_APP2 => 2, + ID_APP3 => 3, + ID_APP4 => 4, + ID_APP5 => 5, + ID_APP6 => 6, + ID_APP7 => 7, + ANY_APP => 255); + + function to_task_id + (eid : t_extended_task_id) return ewok.tasks_shared.t_task_id; + + function to_ext_task_id + (id : ewok.tasks_shared.t_task_id) return t_extended_task_id; + + type t_extended_task_id_access is access all t_extended_task_id; + + type t_endpoint is record + from : t_extended_task_id; + to : t_extended_task_id; + state : t_endpoint_state; + data : byte_array (1 .. MAX_IPC_MSG_SIZE); + size : unsigned_8; + end record; + + type t_endpoint_access is access all t_endpoint; + + type t_endpoints is + array (ewok.tasks_shared.t_task_id range <>) of t_endpoint_access; + + -- + -- Global pool of IPC EndPoints + -- + + ipc_endpoints : array (1 .. ENDPOINTS_POOL_SIZE) of aliased t_endpoint; + + -- + -- Functions + -- + + -- Init IPC endpoints + procedure init_endpoints; + + -- Get a free IPC endpoint + procedure get_endpoint + (endpoint_a : out t_endpoint_access; + success : out boolean); + + -- Release a used IPC endpoint + procedure release_endpoint + (endpoint_a : in t_endpoint_access); + +end ewok.ipc; diff --git a/Ada/ewok-isr.adb b/Ada/ewok-isr.adb new file mode 100644 index 0000000..ff5953a --- /dev/null +++ b/Ada/ewok-isr.adb @@ -0,0 +1,90 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.interrupts; use soc.interrupts; +with ewok.tasks; use ewok.tasks; +with ewok.posthook; +with ewok.softirq; +with ewok.dma; +with ewok.dma.interfaces; +with soc.dma; +with soc.nvic; + +package body ewok.isr + with spark_mode => off +is + + procedure postpone_isr + (intr : in soc.interrupts.t_interrupt; + handler : in ewok.interrupts.t_interrupt_handler_access; + task_id : in ewok.tasks_shared.t_task_id; + frame_a : in t_stack_frame_access) + is + status : unsigned_32 := 0; + data : unsigned_32 := 0; + isr_params : ewok.softirq.t_isr_parameters; + begin + + -- If the current ISR is handled by the kernel, we just execute it we + -- return without requesting schedule + + if ewok.tasks.tasks_list(task_id).ttype = TASK_TYPE_KERNEL then + handler (frame_a); + return; + end if; + + -- Acknowledge interrupt: + -- - DMAs are managed by the kernel + -- - Devices managed by user tasks should use the posthook mechanism + -- to acknowledge interrupt (in order to avoid bursts). Note that + -- posthook execution is mandatory for hardware devices that wait for + -- a quick answer from the driver. It permit to execute some + -- instructions (reading and writing registers) and to return some + -- results in the 'args' parameter. + +#if CONFIG_KERNEL_DMA_ENABLE + if soc.dma.soc_is_dma_irq (intr) then + status := ewok.dma.interfaces.dma_get_status (task_id, intr); + ewok.dma.clear_dma_interrupts (task_id, intr); + else + ewok.posthook.exec (intr, status, data); + end if; +#else + ewok.posthook.exec (intr, status, data); +#end if; + + -- All user ISR have their Pending IRQ bit clean here + soc.nvic.clear_pending_irq (soc.nvic.to_irq_number (intr)); + + -- FIXME - softirq.query parameters interface must use some + -- explanatory names + isr_params.handler := ewok.interrupts.to_system_address (handler); + isr_params.interrupt := intr; + isr_params.posthook_status := status; + isr_params.posthook_data := data; + + ewok.softirq.push_isr (task_id, isr_params); + return; + + end postpone_isr; + +end ewok.isr; diff --git a/Ada/ewok-isr.ads b/Ada/ewok-isr.ads new file mode 100644 index 0000000..0082944 --- /dev/null +++ b/Ada/ewok-isr.ads @@ -0,0 +1,37 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; +with ewok.interrupts; +with soc.interrupts; + +package ewok.isr + with spark_mode => off +is + + procedure postpone_isr + (intr : in soc.interrupts.t_interrupt; + handler : in ewok.interrupts.t_interrupt_handler_access; + task_id : in ewok.tasks_shared.t_task_id; + frame_a : in t_stack_frame_access); + +end ewok.isr; diff --git a/Ada/ewok-layout.ads b/Ada/ewok-layout.ads new file mode 100644 index 0000000..3a1f210 --- /dev/null +++ b/Ada/ewok-layout.ads @@ -0,0 +1,187 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with soc.layout; + +package ewok.layout + with spark_mode => on +is + + VTORS_SIZE : constant := 392; + + -- +----------------+0x0800 0000 + -- | LDR (32k) | + -- +----------------+0x0800 8000 + -- | SHR (32k) | + -- +----------------+0x0801 0000 + -- | DFU1_k (64k) | + -- + - - - - - - - -+0x0802 0000 + -- | DFU1_u (64k) | + -- +----------------+0x0803 0000 + -- | FW1_k (64k) | + -- + - - - - - - - -+0x0804 0000 + -- | | + -- | FW1_u (256k) | + -- | | + -- +----------------+0x0808 0000 + -- | | + -- | FW2_u (256k) | + -- | | + -- + - - - - - - - -+0x080c 0000 + -- | FW2_k (64k) | + -- +----------------+0x080d 0000 + -- | DFU2_k (64k) | + -- + - - - - - - - -+0x080e 0000 + -- | DFU2_u (64k) | + -- +----------------+0x080f 0000 + + FLASH_SIZE : constant := 1024 * KBYTE; + + LDR_BASE : constant system_address := 16#0800_0000#; + LDR_SIZE : constant := 32 * KBYTE; + + SHR_BASE : constant system_address := 16#0800_8000#; + SHR_SIZE : constant := 32 * KBYTE; + + -- + -- DFU 1 + -- + + DFU1_BASE : constant system_address := 16#0801_0000#; + DFU1_SIZE : constant := 128 * KBYTE; + DFU1_KERN_BASE : constant system_address := DFU1_BASE; + DFU1_KERN_SIZE : constant := 64 * KBYTE; + DFU1_START : constant system_address := DFU1_KERN_BASE + VTORS_SIZE + 1; + DFU1_USER_BASE : constant system_address := DFU1_KERN_BASE + DFU1_KERN_SIZE; + DFU1_USER_SIZE : constant := 64 * KBYTE; + + -- + -- Firmware 1 + -- + + FW1_BASE : constant system_address := 16#0803_0000#; + FW1_SIZE : constant := 320 * KBYTE; + FW1_KERN_BASE : constant system_address := FW1_BASE; + FW1_KERN_SIZE : constant := 64 * KBYTE; + FW1_START : constant system_address := FW1_KERN_BASE + VTORS_SIZE + 1; + FW1_USER_BASE : constant system_address := FW1_KERN_BASE + FW1_KERN_SIZE; + FW1_USER_SIZE : constant := 256 * KBYTE; + + -- + -- Firmware 2 + -- + + FW2_BASE : constant system_address := 16#0808_0000#; + FW2_SIZE : constant := 320 * KBYTE; + FW2_USER_BASE : constant system_address := FW2_BASE; + FW2_USER_SIZE : constant := 256 * KBYTE; + FW2_KERN_BASE : constant system_address := FW2_USER_BASE + FW2_USER_SIZE; + FW2_START : constant system_address := FW2_KERN_BASE + VTORS_SIZE + 1; + FW2_KERN_SIZE : constant := 64 * KBYTE; + + + + DFU2_BASE : constant system_address := 16#080d_0000#; + DFU2_START : constant system_address := DFU2_BASE + VTORS_SIZE + 1; + + DFU2_KERN_BASE : constant system_address := DFU2_BASE; + DFU2_USER_BASE : constant system_address := DFU2_BASE + (64*KBYTE); + + DFU2_SIZE : constant := 128 * KBYTE; + DFU2_KERN_SIZE : constant := 64 * KBYTE; + DFU2_USER_SIZE : constant := 64 * KBYTE; + + --------------------------------------------------------------- + + -- +----------------+ <- 16#1001_0000# + -- | IDLE_STACK | + -- +----------------+ <- 16#1000_F000# + -- | SOFTIRQ_STACK | + -- | | + -- +----------------+ <- 16#1000_D000# + -- | ISR_STACK | + -- +----------------+ <- 16#1000_C000# + -- | INITIAL_STACK | + -- +----------------+ + -- + + KERN_DATA_BASE : constant system_address := 16#1000_0000#; + KERN_DATA_SIZE : constant := 64 * KBYTE; + + USER_DATA_BASE : constant system_address := soc.layout.RAM_BASE; + + LDR_DATA_BASE : constant system_address := 16#2001_c000#; + LDR_DATA_SIZE : constant := 16 * KBYTE; + + STACK_TOP_IDLE : constant system_address := KERN_DATA_BASE + KERN_DATA_SIZE; + STACK_SIZE_IDLE : constant := 4 * KBYTE; + + STACK_TOP_SOFTIRQ : constant system_address := STACK_TOP_IDLE - STACK_SIZE_IDLE; + STACK_SIZE_SOFTIRQ : constant := 8 * KBYTE; + + STACK_TOP_TASK_ISR : constant system_address := STACK_TOP_SOFTIRQ - STACK_SIZE_SOFTIRQ; + STACK_SIZE_TASK_ISR : constant := 4 * KBYTE; + STACK_BOTTOM_TASK_ISR : constant system_address := STACK_TOP_TASK_ISR - STACK_SIZE_TASK_ISR; + + -- Transient stack. Used only during kernel initialization + STACK_TOP_TASK_INITIAL : constant system_address := STACK_BOTTOM_TASK_ISR; + + --------------------------------------------------------------- + --------------------------------------------------------------- + + FW_MAX_USER_SIZE : constant := 64 * KBYTE; + DFU_MAX_USER_SIZE : constant := 32 * KBYTE; + + FW_MAX_USER_DATA : constant := 8 * KBYTE; + USER_RAM_SIZE : constant := 128 * KBYTE; + USER_DATA_SIZE : constant := 16 * KBYTE; + + FW1_APP1_BASE : constant system_address := FW1_USER_BASE; + FW1_APP2_BASE : constant system_address := FW1_USER_BASE + (1 * FW_MAX_USER_SIZE); + FW1_APP3_BASE : constant system_address := FW1_USER_BASE + (2 * FW_MAX_USER_SIZE); + FW1_APP4_BASE : constant system_address := FW1_USER_BASE + (3 * FW_MAX_USER_SIZE); + FW1_APP5_BASE : constant system_address := FW1_USER_BASE + (4 * FW_MAX_USER_SIZE); + FW1_APP6_BASE : constant system_address := FW1_USER_BASE + (5 * FW_MAX_USER_SIZE); + FW1_APP7_BASE : constant system_address := FW1_USER_BASE + (6 * FW_MAX_USER_SIZE); + FW1_APP8_BASE : constant system_address := FW1_USER_BASE + (7 * FW_MAX_USER_SIZE); + + FW2_APP1_BASE : constant system_address := FW2_USER_BASE; + FW2_APP2_BASE : constant system_address := FW2_USER_BASE + (1 * FW_MAX_USER_SIZE); + FW2_APP3_BASE : constant system_address := FW2_USER_BASE + (2 * FW_MAX_USER_SIZE); + FW2_APP4_BASE : constant system_address := FW2_USER_BASE + (3 * FW_MAX_USER_SIZE); + FW2_APP5_BASE : constant system_address := FW2_USER_BASE + (4 * FW_MAX_USER_SIZE); + FW2_APP6_BASE : constant system_address := FW2_USER_BASE + (5 * FW_MAX_USER_SIZE); + FW2_APP7_BASE : constant system_address := FW2_USER_BASE + (6 * FW_MAX_USER_SIZE); + FW2_APP8_BASE : constant system_address := FW2_USER_BASE + (7 * FW_MAX_USER_SIZE); + + + USER_APP1_DATA_BASE : constant system_address := soc.layout.RAM_BASE; + USER_APP2_DATA_BASE : constant system_address := soc.layout.RAM_BASE + (1 * USER_DATA_SIZE); + USER_APP3_DATA_BASE : constant system_address := soc.layout.RAM_BASE + (2 * USER_DATA_SIZE); + USER_APP4_DATA_BASE : constant system_address := soc.layout.RAM_BASE + (3 * USER_DATA_SIZE); + USER_APP5_DATA_BASE : constant system_address := soc.layout.RAM_BASE + (4 * USER_DATA_SIZE); + USER_APP6_DATA_BASE : constant system_address := soc.layout.RAM_BASE + (5 * USER_DATA_SIZE); + USER_APP7_DATA_BASE : constant system_address := soc.layout.RAM_BASE + (6 * USER_DATA_SIZE); + USER_APP8_DATA_BASE : constant system_address := soc.layout.RAM_BASE + (7 * USER_DATA_SIZE); -- SHM +end ewok.layout; + diff --git a/Ada/ewok-mpu-handler.adb b/Ada/ewok-mpu-handler.adb new file mode 100644 index 0000000..000012a --- /dev/null +++ b/Ada/ewok-mpu-handler.adb @@ -0,0 +1,111 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ada.unchecked_conversion; +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.devices_shared; use ewok.devices_shared; +with ewok.sched; +with ewok.interrupts; +with soc.interrupts; +with m4.scb; +with debug; + +package body ewok.mpu.handler + with spark_mode => off +is + + function memory_fault_handler + (frame_a : t_stack_frame_access) + return t_stack_frame_access + is + current : ewok.tasks.t_task_access; + begin + + if m4.scb.SCB.CFSR.MMFSR.MMARVALID then + debug.log (debug.WARNING, "MPU error: MMFAR.ADDRESS = " & + system_address'image (m4.scb.SCB.MMFAR.ADDRESS)); + end if; + + if m4.scb.SCB.CFSR.MMFSR.MLSPERR then + debug.log (debug.WARNING, "MPU error: a MemManage fault occurred during floating-point lazy state preservation"); + end if; + + if m4.scb.SCB.CFSR.MMFSR.MSTKERR then + debug.log (debug.WARNING, "MPU error: stacking for an exception entry has caused one or more access violation"); + end if; + + if m4.scb.SCB.CFSR.MMFSR.MUNSTKERR then + debug.log (debug.WARNING, "MPU error: unstack for an exception return has caused one or more access violation"); + end if; + + if m4.scb.SCB.CFSR.MMFSR.DACCVIOL then + debug.log (debug.WARNING, "MPU error: the processor attempted a load or store at a location that does not permit the operation"); + end if; + + if m4.scb.SCB.CFSR.MMFSR.IACCVIOL then + debug.log (debug.WARNING, "MPU error: the processor attempted an instruction fetch from a location that does not permit execution"); + end if; + + current := ewok.tasks.get_task(ewok.sched.get_current); + + if current = NULL then + debug.panic ("MPU error: No current task."); + end if; + + declare + begin + debug.log (debug.WARNING, + "MPU error: task: " & current.all.name & + ", id:" & ewok.tasks_shared.t_task_id'image (current.all.id) & + ", PC:" & system_address'image (frame_a.all.PC)); + end; + + -- On memory fault, the task is not scheduled anymore + ewok.tasks.set_state + (current.all.id, TASK_MODE_MAINTHREAD, ewok.tasks.TASK_STATE_FAULT); + + -- Request schedule + m4.scb.SCB.ICSR.PENDSVSET := 1; + + debug.panic("panic!"); + + return frame_a; + end memory_fault_handler; + + + procedure init + is + ok : boolean; + begin + ewok.interrupts.set_task_switching_handler + (soc.interrupts.INT_MEMMANAGE, + memory_fault_handler'access, + ID_UNUSED, + ID_DEV_UNUSED, + ok); + if not ok then raise program_error; end if; + end init; + + +end ewok.mpu.handler; diff --git a/Ada/ewok-mpu-handler.ads b/Ada/ewok-mpu-handler.ads new file mode 100644 index 0000000..1c76583 --- /dev/null +++ b/Ada/ewok-mpu-handler.ads @@ -0,0 +1,36 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok; use ewok; + +package ewok.mpu.handler + with spark_mode => off -- all _access variabls are not SPARK compatible +is + + procedure init; + + function memory_fault_handler + (frame_a : t_stack_frame_access) + return t_stack_frame_access; + +end ewok.mpu.handler; diff --git a/Ada/ewok-mpu-interfaces.adb b/Ada/ewok-mpu-interfaces.adb new file mode 100644 index 0000000..35ec9a2 --- /dev/null +++ b/Ada/ewok-mpu-interfaces.adb @@ -0,0 +1,41 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package body ewok.mpu.interfaces + with spark_mode => off +is + + function init + return types.c.t_retval + is + ok : boolean; + begin + ewok.mpu.init (ok); + if ok then + return types.c.SUCCESS; + else + return types.c.FAILURE; + end if; + end init; + +end ewok.mpu.interfaces; diff --git a/Ada/ewok-mpu-interfaces.ads b/Ada/ewok-mpu-interfaces.ads new file mode 100644 index 0000000..f932835 --- /dev/null +++ b/Ada/ewok-mpu-interfaces.ads @@ -0,0 +1,35 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with types.c; + +package ewok.mpu.interfaces + with spark_mode => off +is + + function init + return types.c.t_retval + with convention => c, + export => true, + external_name => "mpu_kernel_init"; + +end ewok.mpu.interfaces; diff --git a/Ada/ewok-mpu.adb b/Ada/ewok-mpu.adb new file mode 100644 index 0000000..bf709e3 --- /dev/null +++ b/Ada/ewok-mpu.adb @@ -0,0 +1,335 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ada.unchecked_conversion; + +with m4.mpu; use m4.mpu; +with ewok.mpu.handler; +with ewok.layout; +with soc.layout; +with debug; +with applications; -- generated + +package body ewok.mpu + with spark_mode => on +is + + + procedure init + (success : out boolean) + with spark_mode => off -- handler is not SPARK compatible + is + + function get_region_size (size : t_region_size) return unsigned_32 + is (2**(natural (size) + 1)); + + region_config : m4.mpu.t_region_config; + begin + + -- Testing if there's an MPU + m4.mpu.is_mpu_available (success); + + if not success then + debug.log (debug.WARNING, "Error: no MPU found!"); + return; + end if; + + -- Register memory fault handler + -- Note: unproved because SPARK doesn't allow "'address" attribute + ewok.mpu.handler.init; -- not PARK compatible + + -- Disable MPU + m4.mpu.disable; + + -- Enable privileged software access (PRIVDEFENA) to default memory map + -- and enable the memory fault exception. When ENABLE and PRIVDEFENA are + -- both set to 1, privileged code can freely access the default memory + -- map. Any access by unprivileged software that does not address an + -- enabled memory region causes a memory management fault. + m4.mpu.init; + + -- SHR + if get_region_size (REGION_SIZE_32KB) /= ewok.layout.SHR_SIZE then + debug.log (debug.WARNING, "MPU error: invalid 'SHARED' region size"); + return; + end if; + + region_config := + (region_number => SHARED_REGION, + addr => ewok.layout.SHR_BASE, + size => REGION_SIZE_32KB, + subregion_mask => 0, + access_perm => REGION_AP_RO_RO, + xn => true, + b => false, + s => false); + + -- A memory region must never be mapped RWX + m4.mpu.configure_region (region_config); + + -- Kernel code + if get_region_size (REGION_SIZE_64KB) /= ewok.layout.FW1_KERN_SIZE then + debug.log (debug.WARNING, "MPU error: invalid 'KERNEL CODE' region size"); + return; + end if; + + region_config := + (region_number => KERN_CODE_REGION, + addr => applications.txt_kern_region_base, + size => applications.txt_kern_region_size, + subregion_mask => 0, + access_perm => REGION_AP_RO_NO, + xn => false, + b => false, + s => false); + + m4.mpu.configure_region (region_config); + + -- Devices + region_config := + (region_number => DEVICES_REGION, + addr => soc.layout.PERIPH_BASE, + size => REGION_SIZE_512KB, + subregion_mask => 0, + access_perm => REGION_AP_RW_NO, + xn => true, + b => true, + s => true); + + m4.mpu.configure_region (region_config); + + -- kernel data + stacks + if get_region_size (REGION_SIZE_64KB) /= ewok.layout.KERN_DATA_SIZE then + debug.log (debug.WARNING, "MPU error: invalid 'KERNEL DATA' region size"); + return; + end if; + + region_config := + (region_number => KERN_DATA_REGION, + addr => ewok.layout.KERN_DATA_BASE, + size => REGION_SIZE_64KB, + subregion_mask => 0, + access_perm => REGION_AP_RW_NO, + xn => true, + b => false, + s => true); + + m4.mpu.configure_region (region_config); + + -- User data + if get_region_size (REGION_SIZE_128KB) /= ewok.layout.USER_RAM_SIZE then + debug.log (debug.WARNING, "MPU error: invalid 'USER DATA' region size"); + return; + end if; + + region_config := + (region_number => USER_DATA_REGION, + addr => ewok.layout.USER_DATA_BASE, + size => REGION_SIZE_128KB, + subregion_mask => 0, + access_perm => REGION_AP_RW_RW, + xn => true, + b => false, + s => true); + + m4.mpu.configure_region (region_config); + + -- USER code area + -- Note: This is for the whole area. Each task will use only a fixed + -- number of sub-regions + if get_region_size (REGION_SIZE_256KB) /= ewok.layout.FW1_USER_SIZE then + debug.log (debug.WARNING, "MPU error: invalid 'USER CODE' region size"); + return; + end if; + + region_config := + (region_number => USER_CODE_REGION, + addr => applications.txt_user_region_base, + size => applications.txt_user_region_size, + subregion_mask => 0, + access_perm => REGION_AP_RO_RO, + xn => false, + b => false, + s => false); + + m4.mpu.configure_region (region_config); + + -- User ISR stack + region_config := + (region_number => ISR_STACK_REGION, + addr => ewok.layout.STACK_BOTTOM_TASK_ISR, + size => REGION_SIZE_4KB, + subregion_mask => 0, + access_perm => REGION_AP_RW_RW, + xn => true, + b => false, + s => true); + + m4.mpu.configure_region (region_config); + + debug.log (debug.INFO, "MPU is configured"); + m4.mpu.enable; + debug.log (debug.INFO, "MPU is enabled"); + + end init; + + + procedure regions_schedule + (region_number : in m4.mpu.t_region_number; + addr : in system_address; + size : in m4.mpu.t_region_size; + region_type : in t_region_type; + subregion_mask : in unsigned_8) + is + region_config : m4.mpu.t_region_config; + begin + -- A memory region must never be mapped RWX + case (region_type) is + when REGION_TYPE_USER_DEV => + region_config := + (region_number => region_number, + addr => addr, + size => size, + subregion_mask => subregion_mask, + access_perm => REGION_AP_RW_RW, + xn => true, + b => true, + s => true); + + m4.mpu.configure_region (region_config); + + when REGION_TYPE_RO_USER_DEV => + region_config := + (region_number => region_number, + addr => addr, + size => size, + subregion_mask => subregion_mask, + access_perm => REGION_AP_RW_RO, + xn => true, + b => true, + s => true); + + m4.mpu.configure_region (region_config); + + when REGION_TYPE_USER_CODE => + region_config := + (region_number => region_number, + addr => addr, + size => size, + subregion_mask => subregion_mask, + access_perm => REGION_AP_RO_RO, + xn => false, + b => false, + s => false); + + m4.mpu.update_subregion_mask (region_config); + + when REGION_TYPE_USER_DATA => + region_config := + (region_number => region_number, + addr => addr, + size => size, + subregion_mask => subregion_mask, + access_perm => REGION_AP_RW_RW, + xn => true, + b => false, + s => true); + + m4.mpu.update_subregion_mask (region_config); + + when REGION_TYPE_BOOTROM => + + -- MPU makes Boot ROM region unattainable to avoid ROP attacks + + region_config := + (region_number => region_number, + addr => addr, + size => size, + subregion_mask => 0, + access_perm => REGION_AP_NO_NO, + xn => true, + b => false, + s => false); + + m4.mpu.configure_region (region_config); + + when REGION_TYPE_ISR_DATA => + region_config := + (region_number => region_number, + addr => addr, + size => size, + subregion_mask => 0, + access_perm => REGION_AP_RW_RW, + xn => true, + b => false, + s => true); + + m4.mpu.configure_region (region_config); + + end case; + + end regions_schedule; + + + procedure bytes_to_region_size + (bytes : in unsigned_32; + region_size : out m4.mpu.t_region_size; + success : out boolean) + is + begin + success := true; + case (bytes) is + when 32 => region_size := REGION_SIZE_32B; + when 64 => region_size := REGION_SIZE_64B; + when 128 => region_size := REGION_SIZE_128B; + when 256 => region_size := REGION_SIZE_256B; + when 512 => region_size := REGION_SIZE_512B; + when 1*KBYTE => region_size := REGION_SIZE_1KB; + when 2*KBYTE => region_size := REGION_SIZE_2KB; + when 4*KBYTE => region_size := REGION_SIZE_4KB; + when 8*KBYTE => region_size := REGION_SIZE_8KB; + when 16*KBYTE => region_size := REGION_SIZE_16KB; + when 32*KBYTE => region_size := REGION_SIZE_32KB; + when 64*KBYTE => region_size := REGION_SIZE_64KB; + when 128*KBYTE => region_size := REGION_SIZE_128KB; + when 256*KBYTE => region_size := REGION_SIZE_256KB; + when 512*KBYTE => region_size := REGION_SIZE_512KB; + when 1*MBYTE => region_size := REGION_SIZE_1MB; + when 2*MBYTE => region_size := REGION_SIZE_2MB; + when 4*MBYTE => region_size := REGION_SIZE_4MB; + when 8*MBYTE => region_size := REGION_SIZE_8MB; + when 16*MBYTE => region_size := REGION_SIZE_16MB; + when 32*MBYTE => region_size := REGION_SIZE_32MB; + when 64*MBYTE => region_size := REGION_SIZE_64MB; + when 128*MBYTE => region_size := REGION_SIZE_128MB; + when 256*MBYTE => region_size := REGION_SIZE_256MB; + when 512*MBYTE => region_size := REGION_SIZE_512MB; + when 1*GBYTE => region_size := REGION_SIZE_1GB; + when 2*GBYTE => region_size := REGION_SIZE_2GB; + when others => + region_size := REGION_SIZE_32B; + success := false; + end case; + end bytes_to_region_size; + +end ewok.mpu; diff --git a/Ada/ewok-mpu.ads b/Ada/ewok-mpu.ads new file mode 100644 index 0000000..dd27e9f --- /dev/null +++ b/Ada/ewok-mpu.ads @@ -0,0 +1,92 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with m4.mpu; +with m4.scb; + +package ewok.mpu + with spark_mode => on +is + + type t_region_type is + (REGION_TYPE_USER_DATA, + REGION_TYPE_USER_CODE, + REGION_TYPE_USER_DEV, + REGION_TYPE_RO_USER_DEV, + REGION_TYPE_BOOTROM, + REGION_TYPE_ISR_DATA) + with size => 32; + + -- FIXME to be set in core.mpu + MPU_MAX_EMPTY_REGIONS : constant unsigned_8 := 2; + + SHARED_REGION : constant m4.mpu.t_region_number := 0; + KERN_CODE_REGION : constant m4.mpu.t_region_number := 1; + DEVICES_REGION : constant m4.mpu.t_region_number := 2; + BOOT_ROM_REGION : constant m4.mpu.t_region_number := 3; + KERN_DATA_REGION : constant m4.mpu.t_region_number := 3; + USER_DATA_REGION : constant m4.mpu.t_region_number := 4; -- USER_RAM + USER_CODE_REGION : constant m4.mpu.t_region_number := 5; -- USER_TXT + ISR_STACK_REGION : constant m4.mpu.t_region_number := 6; + USER_DEV1_REGION : constant m4.mpu.t_region_number := 6; + ISR_DEVICE_REGION : constant m4.mpu.t_region_number := 7; + USER_DEV2_REGION : constant m4.mpu.t_region_number := 7; + + --------------- + -- Functions -- + --------------- + + -- Initialize the MPU + procedure init + (success : out boolean) + with global => (in_out => (m4.mpu.MPU, m4.scb.SCB)); + + -- That function is only used by SPARK prover + function get_region_size_mask (size : m4.mpu.t_region_size) return unsigned_32 + is (2**(natural (size) + 1) - 1) + with ghost; + + procedure regions_schedule + (region_number : in m4.mpu.t_region_number; + addr : in system_address; + size : in m4.mpu.t_region_size; + region_type : in t_region_type; + subregion_mask : in unsigned_8) + with + global => (in_out => (m4.mpu.MPU)), + pre => + (region_number < 8 + and + (addr and 2#11111#) = 0 + and + size >= 4 + and + (addr and get_region_size_mask(size)) = 0); + + procedure bytes_to_region_size + (bytes : in unsigned_32; + region_size : out m4.mpu.t_region_size; + success : out boolean) + with global => null; + +end ewok.mpu; diff --git a/Ada/ewok-perm.adb b/Ada/ewok-perm.adb new file mode 100644 index 0000000..87933a3 --- /dev/null +++ b/Ada/ewok-perm.adb @@ -0,0 +1,156 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +#if CONFIG_KERNEL_DOMAIN +with ewok.tasks; +#end if; + +package body ewok.perm + with spark_mode => on +is + + + function dmashm_is_granted + (from : in t_real_task_id; + to : in t_real_task_id) + return boolean + is + begin + -- Assertion on the statically built com_dmashm_perm: + -- a task is not allowed to declare a DMA_SHM to itself + -- This assertion is a DMA_SHM matrix sanitation + pragma Assert + (for all x in t_real_task_id => + (not ewok.perm_auto.com_dmashm_perm(x,x))); + return ewok.perm_auto.com_dmashm_perm (from, to); + end dmashm_is_granted; + + + function ipc_is_granted + (from : in t_real_task_id; + to : in t_real_task_id) + return boolean + is + begin + -- Assertion on the statically built com_ipc_perm: + -- a task is not allowed to declare an IPC channel to itself + -- This assertion is an IPC matrix sanitation + pragma Assert + (for all x in t_real_task_id => + (not ewok.perm_auto.com_ipc_perm(x,x))); + return ewok.perm_auto.com_ipc_perm (from, to); + end ipc_is_granted; + +#if CONFIG_KERNEL_DOMAIN + function is_same_domain + (from : in t_real_task_id; + to : in t_real_task_id) + return boolean + with + Spark_Mode => Off -- implies tasks.get_domain() to be Spark compatible + is + begin + return + (ewok.tasks.get_domain(from) = + ewok.tasks.get_domain(to)); + end is_same_domain; +#end if; + + + function ressource_is_granted + (perm_name : in t_perm_name; + task_id : in applications.t_real_task_id) + return boolean + is + begin + -- is there some assertion checking that some ressources tuples are + -- forbidden + + case perm_name is + when PERM_RES_DEV_DMA => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).DEV_DMA = 1; + + when PERM_RES_DEV_CRYPTO_USR => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).DEV_CRYPTO = 1 or + ewok.perm_auto.ressource_perm_register_tab(task_id).DEV_CRYPTO = 3; + + when PERM_RES_DEV_CRYPTO_CFG => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).DEV_CRYPTO = 2 or + ewok.perm_auto.ressource_perm_register_tab(task_id).DEV_CRYPTO = 3; + + when PERM_RES_DEV_CRYPTO_FULL => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).DEV_CRYPTO = 3; + + when PERM_RES_DEV_BUSES => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).DEV_BUS = 1; + + when PERM_RES_DEV_EXTI => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).DEV_EXTI = 1; + + when PERM_RES_DEV_TIM => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).DEV_TIM = 1; + + when PERM_RES_TIM_GETMILLI => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).TIM_TIME > 0; + + when PERM_RES_TIM_GETMICRO => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).TIM_TIME > 1; + + when PERM_RES_TIM_GETCYCLE => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).TIM_TIME > 2; + + when PERM_RES_TSK_FISR => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).TSK_FISR = 1; + + when PERM_RES_TSK_FIPC => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).TSK_FIPC = 1; + + when PERM_RES_TSK_RESET => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).TSK_RESET = 1; + + when PERM_RES_TSK_UPGRADE => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).TSK_UPGRADE = 1; + + when PERM_RES_MEM_DYNAMIC_MAP => + return + ewok.perm_auto.ressource_perm_register_tab(task_id).MEM_DYNAMIC_MAP = 1; + + end case; + + end ressource_is_granted; + +end ewok.perm; diff --git a/Ada/ewok-perm.ads b/Ada/ewok-perm.ads new file mode 100644 index 0000000..c819022 --- /dev/null +++ b/Ada/ewok-perm.ads @@ -0,0 +1,138 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with applications; use applications; +with ewok.perm_auto; +with ewok.tasks_shared; use ewoK.tasks_shared; + +package ewok.perm + with spark_mode => on +is + + --------------- + -- Types -- + --------------- + + type t_perm_name is + (PERM_RES_DEV_DMA, + PERM_RES_DEV_CRYPTO_USR, + PERM_RES_DEV_CRYPTO_CFG, + PERM_RES_DEV_CRYPTO_FULL, + PERM_RES_DEV_BUSES, + PERM_RES_DEV_EXTI, + PERM_RES_DEV_TIM, + PERM_RES_TIM_GETMILLI, + PERM_RES_TIM_GETMICRO, + PERM_RES_TIM_GETCYCLE, + PERM_RES_TSK_FISR, + PERM_RES_TSK_FIPC, + PERM_RES_TSK_RESET, + PERM_RES_TSK_UPGRADE, + PERM_RES_MEM_DYNAMIC_MAP); + + --------------- + -- Functions -- + --------------- + + -- + -- \brief test if a task is allow to declare a DMA SHM with another task + -- + -- Here we are based on a symetric paradigm (i.e. when a + -- task is allowed to declare a DMA SHM with another task, the other + -- task is allowed to host a DMA SHM from it). Nonetheless it + -- is still an half duplex communication channel (DMA SHM are + -- read-only or write-only, accessible only by the DMA controler + -- and never mapped into the task memory slot). + -- + -- \param[in] from the task which want to declare a DMA SHM + -- \param[in] tto the task target of the DMA SHM peering + -- + -- \return true if the permission is granted, of false + -- + + function dmashm_is_granted + (from : in t_real_task_id; + to : in t_real_task_id) + return boolean + with + Global => null, -- com_dmashm_perm is a constant, not a variable + Post => (if (from = to) then dmashm_is_granted'Result = false), + Contract_Cases => (ewok.perm_auto.com_dmashm_perm(from,to) => dmashm_is_granted'Result, + others => not dmashm_is_granted'Result); + + -- + -- \brief test if a task is allow to send an IPC to another task + -- + -- Here we are based on a symetric paradigm (i.e. when a + -- task is allowed to send an IPC to another task, the other + -- task is allowed to receive an IPC from it). Nonetheless it + -- is still an half duplex communication channel. + -- + -- \param[in] from the task which want to send an IPC data + -- \param[in] tto the task target of the IPC + -- + -- \return true if the permission is granted, of false + -- + + function ipc_is_granted + (from : in t_real_task_id; + to : in t_real_task_id) + return boolean + with + Global => null, -- com_ipc_perm is a constant, not a variable + Post => (if (from = to) then ipc_is_granted'Result = false), + Contract_Cases => (ewok.perm_auto.com_ipc_perm(from,to) => ipc_is_granted'Result, + others => not ipc_is_granted'Result); + +#if CONFIG_KERNEL_DOMAIN + function is_same_domain + (from : in t_real_task_id; + to : in t_real_task_id) + return boolean + with + Global => null, + Post => (if (from = to) then is_same_domain'Result = false); +#end if; + + -- + -- \brief test if the ressource is allowed for the task + -- + -- A typical example of such an API is the following: + -- if (!perm_ressource_is_granted(PERM_RES_DEV_DMA, mytask)) { + -- goto ret_denied; + -- } + -- + -- \param[in] perm_name the name of the permission + -- \param[in] task the task requiring the permission + -- + -- \return true if the permission is granted, of false + -- + + function ressource_is_granted + (perm_name : in t_perm_name; + task_id : in applications.t_real_task_id) + return boolean + with Global => (Input => ewok.perm_auto.ressource_perm_register_tab); + + +end ewok.perm; diff --git a/Ada/ewok-posthook.adb b/Ada/ewok-posthook.adb new file mode 100644 index 0000000..105e7ec --- /dev/null +++ b/Ada/ewok-posthook.adb @@ -0,0 +1,217 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.exported.interrupts; use ewok.exported.interrupts; +with ewok.devices_shared; use ewok.devices_shared; +with ewok.interrupts; +with ewok.devices; + +package body ewok.posthook + with spark_mode => off +is + + + function read_register (addr : system_address) + return unsigned_32 + is + reg : unsigned_32 + with import, volatile_full_access, address => to_address (addr); + begin + return reg; + end read_register; + + pragma inline (read_register); + + + procedure set_bits_in_register + (addr : in system_address; + bits : in unsigned_32; + val : in unsigned_32) + is + reg : unsigned_32 + with import, volatile_full_access, address => to_address (addr); + begin + if bits = 16#FFFF_FFFF# then + reg := val; + else + reg := (reg and (not bits)) or (val and bits); + end if; + end set_bits_in_register; + + + procedure exec + (intr : in soc.interrupts.t_interrupt; + status : out unsigned_32; + data : out unsigned_32) + is + dev_id : ewok.devices_shared.t_device_id; + dev_addr : system_address; + config : ewok.exported.interrupts.t_interrupt_config_access; + found : boolean; + val : unsigned_32; + mask : unsigned_32; + begin + + config := ewok.devices.get_interrupt_config_from_interrupt (intr); + if config = NULL then + status := 0; + data := 0; + return; + end if; + + dev_id := ewok.interrupts.get_device_from_interrupt (intr); + if dev_id = ID_DEV_UNUSED then + status := 0; + data := 0; + return; + end if; + + dev_addr := ewok.devices.get_user_device_addr (dev_id); + + for i in config.all.posthook.action'range loop + case config.all.posthook.action(i).instr is + + when POSTHOOK_NIL => + -- No subsequent action. Returning. + return; + + when POSTHOOK_READ => + val := read_register (dev_addr + + system_address (config.all.posthook.action(i).read.offset)); + + config.all.posthook.action(i).read.value := val; + + -- This value need to be saved ? + if config.all.posthook.status = + config.all.posthook.action(i).read.offset + then + status := val; + end if; + + -- This value need to be saved ? + if + config.all.posthook.data = + config.all.posthook.action(i).read.offset + then + data := val; + end if; + + when POSTHOOK_WRITE => + set_bits_in_register + (dev_addr + system_address + (config.all.posthook.action(i).write.offset), + config.all.posthook.action(i).write.mask, + config.all.posthook.action(i).write.value); + + when POSTHOOK_WRITE_REG => + -- Retrieving the already read register value + found := false; + for j in config.all.posthook.action'first .. i loop + if config.all.posthook.action(j).instr = POSTHOOK_READ and then + config.all.posthook.action(j).read.offset = + config.all.posthook.action(i).write_reg.offset_src + then + val := config.all.posthook.action(j).read.value; + found := true; + exit; + end if; + end loop; + + if not found then + val := read_register (dev_addr + system_address + (config.all.posthook.action(i).write_reg.offset_src)); + end if; + + -- Calculating the mask to apply in order to write only active + -- bits + mask := config.all.posthook.action(i).write_reg.mask and val; + + -- Inverted write might be needed + if config.all.posthook.action(i).write_reg.mode = MODE_NOT then + val := not val; + end if; + + -- Writing into the destination register + set_bits_in_register + (dev_addr + system_address + (config.all.posthook.action(i).write_reg.offset_dest), + mask, + val); + + when POSTHOOK_WRITE_MASK => + -- Retrieving the value + found := false; + for j in config.all.posthook.action'first .. i loop + if config.all.posthook.action(j).instr = POSTHOOK_READ and then + config.all.posthook.action(j).read.offset = + config.all.posthook.action(i).write_mask.offset_src + then + val := config.all.posthook.action(j).read.value; + found := true; + exit; + end if; + end loop; + + if not found then + val := read_register (dev_addr + system_address + (config.all.posthook.action(i).write_mask.offset_src)); + end if; + + -- Retrieving the mask + found := false; + for j in config.all.posthook.action'first .. i loop + if config.all.posthook.action(j).instr = POSTHOOK_READ and then + config.all.posthook.action(j).read.offset = + config.all.posthook.action(i).write_mask.offset_mask + then + mask := config.all.posthook.action(j).read.value; + found := true; + exit; + end if; + end loop; + + if not found then + mask := read_register (dev_addr + system_address + (config.all.posthook.action(i).write_mask.offset_mask)); + end if; + + -- Calculating the mask + mask := mask and val; + + -- Inverted write might be needed + if config.all.posthook.action(i).write_mask.mode = MODE_NOT then + val := not val; + end if; + + -- Writing into the destination register + set_bits_in_register + (dev_addr + system_address + (config.all.posthook.action(i).write_mask.offset_dest), + mask, + val); + + end case; + end loop; + + end exec; + +end ewok.posthook; diff --git a/Ada/ewok-posthook.ads b/Ada/ewok-posthook.ads new file mode 100644 index 0000000..167f925 --- /dev/null +++ b/Ada/ewok-posthook.ads @@ -0,0 +1,38 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.interrupts; + +package ewok.posthook + with spark_mode => off +is + + type t_args is new unsigned_32_array (1 .. 2); + type t_args_access is access all t_args; + + -- Execute posthook for a given interrupt + procedure exec + (intr : in soc.interrupts.t_interrupt; + status : out unsigned_32; + data : out unsigned_32); + +end ewok.posthook; diff --git a/Ada/ewok-sanitize.adb b/Ada/ewok-sanitize.adb new file mode 100644 index 0000000..6967437 --- /dev/null +++ b/Ada/ewok-sanitize.adb @@ -0,0 +1,215 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok.layout; use ewok.layout; +with ewok.tasks; use ewok.tasks; +with ewok.devices_shared; use ewok.devices_shared; +with ewok.devices; +with ewok.exported.dma; use type ewok.exported.dma.t_dma_shm_access; + +package body ewok.sanitize + with spark_mode => on +is + + function is_word_in_data_slot + (ptr : system_address; + task_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) + return boolean + with spark_mode => off -- access incompatible with SPARK + is + user_task_a : constant ewok.tasks.t_task_access := ewok.tasks.get_task (task_id); + begin + + if ptr >= user_task_a.all.data_slot_start and + ptr + 4 <= user_task_a.all.data_slot_end + then + return true; + end if; + + -- ISR mode is a special case because the stack is therefore + -- mutualized (thus only one ISR can be executed at the same time) + if mode = TASK_MODE_ISRTHREAD and + ptr >= STACK_BOTTOM_TASK_ISR and + ptr < STACK_TOP_TASK_ISR + then + return true; + end if; + + return false; + end is_word_in_data_slot; + + + function is_word_in_txt_slot + (ptr : system_address; + task_id : ewok.tasks_shared.t_task_id) + return boolean + with spark_mode => off -- access incompatible with SPARK + is + user_task_a : constant ewok.tasks.t_task_access := ewok.tasks.get_task (task_id); + begin + if ptr >= user_task_a.all.txt_slot_start and + ptr + 4 <= user_task_a.all.txt_slot_end + then + return true; + else + return false; + end if; + end is_word_in_txt_slot; + + + function is_word_in_allocated_device + (ptr : system_address; + task_id : ewok.tasks_shared.t_task_id) + return boolean + with spark_mode => off -- access incompatible with SPARK + is + dev_id : ewok.devices_shared.t_device_id; + dev_size : unsigned_32; + dev_addr : system_address; + user_task_a : constant ewok.tasks.t_task_access + := ewok.tasks.get_task (task_id); + begin + + for i in 1 .. user_task_a.all.num_devs loop + dev_id := user_task_a.all.device_id(i); + dev_addr := ewok.devices.get_user_device_addr (dev_id); + dev_size := unsigned_32 (ewok.devices.get_user_device_size (dev_id)); + if ptr >= dev_addr and + ptr + 4 >= dev_addr and + ptr + 4 < dev_addr + dev_size + then + return true; + end if; + end loop; + + return false; + end is_word_in_allocated_device; + + + function is_word_in_any_slot + (ptr : system_address; + task_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) + return boolean + is + begin + return + is_word_in_data_slot (ptr, task_id, mode) or + is_word_in_txt_slot (ptr, task_id); + end is_word_in_any_slot; + + + function is_range_in_data_slot + (ptr : system_address; + size : unsigned_32; + task_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) + return boolean + with spark_mode => off -- access incompatible with SPARK + is + user_task_a : constant ewok.tasks.t_task_access := ewok.tasks.get_task (task_id); + begin + + if ptr >= user_task_a.all.data_slot_start and + ptr + size >= ptr and + ptr + size <= user_task_a.all.data_slot_end + then + return true; + end if; + + if mode = TASK_MODE_ISRTHREAD and + ptr >= STACK_BOTTOM_TASK_ISR and + ptr + size >= ptr and + ptr + size < STACK_TOP_TASK_ISR + then + return true; + end if; + + return false; + end is_range_in_data_slot; + + + function is_range_in_txt_slot + (ptr : system_address; + size : unsigned_32; + task_id : ewok.tasks_shared.t_task_id) + return boolean + with spark_mode => off -- access incompatible with SPARK + is + user_task_a : constant ewok.tasks.t_task_access := ewok.tasks.get_task (task_id); + begin + if ptr >= user_task_a.all.txt_slot_start and + ptr + size >= ptr and + ptr + size <= user_task_a.all.txt_slot_end + then + return true; + else + return false; + end if; + end is_range_in_txt_slot; + + + function is_range_in_any_slot + (ptr : system_address; + size : unsigned_32; + task_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) + return boolean + is + begin + return + is_range_in_data_slot (ptr, size, task_id, mode) or + is_range_in_txt_slot (ptr, size, task_id); + end is_range_in_any_slot; + + + function is_range_in_dma_shm + (ptr : system_address; + size : unsigned_32; + dma_access : ewok.exported.dma.t_dma_shm_access; + task_id : ewok.tasks_shared.t_task_id) + return boolean + with spark_mode => off -- access incompatible with SPARK + is + user_task_a : constant ewok.tasks.t_task_access := ewok.tasks.get_task (task_id); + begin + + for i in 1 .. user_task_a.all.num_dma_shms loop + + if user_task_a.all.dma_shm(i).access_type = dma_access and + ptr >= user_task_a.all.dma_shm(i).base and + ptr + size >= ptr and + ptr + size <= (user_task_a.all.dma_shm(i).base + + unsigned_32 (user_task_a.all.dma_shm(i).size)) + then + return true; + end if; + + end loop; + + return false; + end is_range_in_dma_shm; + + +end ewok.sanitize; diff --git a/Ada/ewok-sanitize.ads b/Ada/ewok-sanitize.ads new file mode 100644 index 0000000..0fdde4d --- /dev/null +++ b/Ada/ewok-sanitize.ads @@ -0,0 +1,107 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.exported.dma; + +package ewok.sanitize + with spark_mode => on +is + + function is_word_in_data_slot + (ptr : system_address; + task_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) return boolean + with + Global => null, + Post => (if (ptr + 4 not in system_address'range) then is_word_in_data_slot'Result = false); + + function is_word_in_txt_slot + (ptr : system_address; + task_id : ewok.tasks_shared.t_task_id) return boolean + with + Global => null, + -- there is now hypothesis on input values, yet we impose some + -- specific behavior for various overflows + Post => (if (ptr + 4 not in system_address'range) then is_word_in_txt_slot'Result = false); + + function is_word_in_allocated_device + (ptr : system_address; + task_id : ewok.tasks_shared.t_task_id) + return boolean; + + function is_word_in_any_slot + (ptr : system_address; + task_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) return boolean + with + Global => null, + -- there is now hypothesis on input values, yet we impose some + -- specific behavior for various overflows + Post => (if (ptr + 4 not in system_address'range) then is_word_in_any_slot'Result = false); + + function is_range_in_data_slot + (ptr : system_address; + size : unsigned_32; + task_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) return boolean + with + Global => null, + -- there is now hypothesis on input values, yet we impose some + -- specific behavior for various overflows + Post => (if (ptr + size not in system_address'range) then is_range_in_data_slot'Result = false); + + function is_range_in_txt_slot + (ptr : system_address; + size : unsigned_32; + task_id : ewok.tasks_shared.t_task_id) return boolean + with + Global => null, + -- there is now hypothesis on input values, yet we impose some + -- specific behavior for various overflows + Post => (if (ptr + size not in system_address'range) then is_range_in_txt_slot'Result = false); + + function is_range_in_any_slot + (ptr : system_address; + size : unsigned_32; + task_id : ewok.tasks_shared.t_task_id; + mode : ewok.tasks_shared.t_task_mode) return boolean + with + Global => null, + -- there is now hypothesis on input values, yet we impose some + -- specific behavior for various overflows + Post => (if (ptr + size not in system_address'range) then is_range_in_any_slot'Result = false); + + function is_range_in_dma_shm + (ptr : system_address; + size : unsigned_32; + dma_access : ewok.exported.dma.t_dma_shm_access; + task_id : ewok.tasks_shared.t_task_id) return boolean + with + Spark_Mode => off, + Global => null, + -- there is now hypothesis on input values, yet we impose some + -- specific behavior for various overflows + Post => (if (ptr + size not in system_address'range) then is_range_in_dma_shm'Result = false); + +end ewok.sanitize; diff --git a/Ada/ewok-sched-interfaces.adb b/Ada/ewok-sched-interfaces.adb new file mode 100644 index 0000000..c515ec2 --- /dev/null +++ b/Ada/ewok-sched-interfaces.adb @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package body ewok.sched.interfaces + with spark_mode => off +is + + procedure interface_init + is + begin + ewok.sched.init; + end interface_init; + +end ewok.sched.interfaces; diff --git a/Ada/ewok-sched-interfaces.ads b/Ada/ewok-sched-interfaces.ads new file mode 100644 index 0000000..e480bc7 --- /dev/null +++ b/Ada/ewok-sched-interfaces.ads @@ -0,0 +1,33 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.sched.interfaces + with spark_mode => off +is + + procedure interface_init + with convention => c, + export => true, + external_name => "sched_init"; + +end ewok.sched.interfaces; diff --git a/Ada/ewok-sched.adb b/Ada/ewok-sched.adb new file mode 100644 index 0000000..6c0ebe7 --- /dev/null +++ b/Ada/ewok-sched.adb @@ -0,0 +1,606 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with system.machine_code; + +with ewok.tasks; use ewok.tasks; +with ewok.devices_shared; use ewok.devices_shared; +with ewok.sleep; +with ewok.devices; +with ewok.syscalls.handler; +with ewok.mpu; +with ewok.layout; +with ewok.interrupts; +with soc.layout; +with soc.interrupts; +with soc.dwt; +with m4.scb; +with m4.mpu; +with m4.systick; +with debug; +with applications; -- Automatically generated + + +package body ewok.sched + with SPARK_Mode => On +is + + package TSK renames ewok.tasks; + sched_period : unsigned_32 := 0; + current_task_id : t_task_id := ID_KERNEL; + + ----------------------------------------------- + -- SPARK/ghost specific functions & procedures + ----------------------------------------------- + + function current_task_is_valid + return boolean + is + begin + return (current_task_id /= ID_UNUSED); + end current_task_is_valid; + + ---------------------------------------------- + -- sched functions + ---------------------------------------------- + + function get_current return ewok.tasks_shared.t_task_id + is + begin + return current_task_id; + end get_current; + + + procedure request_schedule + with SPARK_Mode => Off + is + begin + m4.scb.SCB.ICSR.PENDSVSET := 1; + end request_schedule; + + + function task_elect + return t_task_id + with SPARK_Mode => Off + is + elected : t_task_id; + begin + + -- + -- Execute pending user ISRs first + -- + + for id in applications.list'range loop + if TSK.tasks_list(id).mode = TASK_MODE_ISRTHREAD + and then + ewok.tasks.get_state(id, TASK_MODE_ISRTHREAD) = TASK_STATE_RUNNABLE + and then + ewok.tasks.get_state(id, TASK_MODE_MAINTHREAD) /= TASK_STATE_LOCKED + then + elected := id; + goto ok_return; + end if; + end loop; + + -- + -- Execute tasks in critical sections + -- + + for id in applications.list'range loop + if TSK.tasks_list(id).state = TASK_STATE_LOCKED then + elected := id; + goto ok_return; + end if; + end loop; + + -- + -- Updating finished ISRs state + -- + + for id in applications.list'range loop + + if TSK.tasks_list(id).mode = TASK_MODE_ISRTHREAD + and then + ewok.tasks.get_state(id, TASK_MODE_ISRTHREAD) = TASK_STATE_ISR_DONE + then + ewok.tasks.set_state + (id, TASK_MODE_ISRTHREAD, TASK_STATE_IDLE); + TSK.tasks_list(id).isr_ctx.frame_a := NULL; + TSK.tasks_list(id).isr_ctx.device_id := ID_DEV_UNUSED; + TSK.tasks_list(id).isr_ctx.sched_policy := ISR_STANDARD; + TSK.tasks_list(id).mode := TASK_MODE_MAINTHREAD; + + + -- When a task has just finished its ISR its main thread might + -- become runnable + if ewok.sleep.is_sleeping (id) then + ewok.sleep.try_waking_up (id); + elsif TSK.tasks_list(id).state = TASK_STATE_IDLE then + TSK.tasks_list(id).state := TASK_STATE_RUNNABLE; + end if; + + end if; + + end loop; + + -- + -- Execute SOFTIRQ if there are some pending ISRs and/or syscalls + -- + + if ewok.tasks.get_state + (ID_SOFTIRQ, TASK_MODE_MAINTHREAD) = TASK_STATE_RUNNABLE then + elected := ID_SOFTIRQ; + goto ok_return; + end if; + +#if CONFIG_SCHED_SUPPORT_FIPC or CONFIG_SCHED_SUPPORT_FISR + -- + -- IPC can force task election to reduce IPC overhead + -- + + for id in applications.list'range loop + if TSK.tasks_list(id).state = TASK_STATE_FORCED then + TSK.tasks_list(id).state := TASK_STATE_RUNNABLE; + elected := id; + goto ok_return; + end if; + end loop; +#end if; + +#if CONFIG_SCHED_RAND + declare + random : aliased unsigned_32; + id : t_task_id; + begin + soc_rng_getrng (random'access); + id := t_task_id'val ((applications.list'first)'pos + + (random mod applications.list'length)); + for i in 1 .. applications.list'length loop + if ewok.tasks.get_state + (id, TASK_MODE_MAINTHREAD) = TASK_STATE_RUNNABLE then + elected := id; + goto ok_return; + end if; + if id /= applications.list'last then + id := t_task_id'succ (id); + else + id := applications.list'first; + end if; + end loop; + end; +#end if; + +#if CONFIG_SCHED_RR + declare + id : t_task_id; + begin + id := current_task_id; + for i in 1 .. applications.list'length loop + if id < applications.list'last then + id := t_task_id'succ (id); + else + id := applications.list'first; + end if; + if ewok.tasks.get_state + (id, TASK_MODE_MAINTHREAD) = TASK_STATE_RUNNABLE then + elected := id; + goto ok_return; + end if; + end loop; + end; +#end if; + +#if CONFIG_SCHED_MLQ_RR + declare + max_prio : unsigned_8 := 0; + id : t_task_id; + begin + + -- Max priority + for id in applications.list'range loop + if TSK.tasks_list(id).prio > max_prio and + ewok.tasks.get_state + (id, TASK_MODE_MAINTHREAD) = TASK_STATE_RUNNABLE + then + max_prio := TSK.tasks_list(id).prio; + end if; + end loop; + + -- Round Robin election on tasks with the max priority + id := current_task_id; + for i in 1 .. applications.list'length loop + if id < applications.list'last then + id := t_task_id'succ (id); + else + id := applications.list'first; + end if; + if TSK.tasks_list(id).prio = max_prio and + ewok.tasks.get_state + (id, TASK_MODE_MAINTHREAD) = TASK_STATE_RUNNABLE + then + elected := id; + goto ok_return; + end if; + end loop; + end; +#end if; + + -- Default + elected := ID_KERNEL; + + <> + +#if CONFIG_DBGLEVEL > 6 + debug.log (debug.DEBUG, "task " & t_task_id'image (elected) & " elected"); +#end if; + return elected; + + end task_elect; + + + procedure mpu_switching + (id : in t_task_id) + with SPARK_Mode => Off + is + new_task : t_task_access; + dev_id : t_device_id; + dev_size : unsigned_16; + dev_addr : system_address; + mpu_region_size : m4.mpu.t_region_size; + region_type : ewok.mpu.t_region_type; + dev_region : m4.mpu.t_region_number; + dev_cannot_be_mapped : boolean; + ok : boolean; + begin + + new_task := ewok.tasks.get_task (id); + + if new_task.all.ttype = TASK_TYPE_USER then + + if new_task.all.mode = TASK_MODE_ISRTHREAD then + + -------------- + -- User ISR -- + -------------- + + dev_id := new_task.all.isr_ctx.device_id; + + -- Notes + -- - EXTIs are a special case where an interrupt can trigger a + -- user ISR without any device_id associated + -- - DMAs are not registered in devices + if dev_id /= ID_DEV_UNUSED then + dev_size := ewok.devices.get_user_device_size (dev_id); + dev_addr := ewok.devices.get_user_device_addr (dev_id); + end if; + + -- Mapping the ISR device + if dev_id /= ID_DEV_UNUSED and dev_size > 0 then + + ewok.mpu.bytes_to_region_size (unsigned_32 (dev_size), mpu_region_size, ok); + if not ok then + debug.panic("mpu_switching(): bytes_to_region_size() failed!"); + end if; + + if ewok.devices.is_user_device_region_ro (dev_id) then + region_type := ewok.mpu.REGION_TYPE_RO_USER_DEV; + else + region_type := ewok.mpu.REGION_TYPE_USER_DEV; + end if; + + ewok.mpu.regions_schedule + (region_number => ewok.mpu.ISR_DEVICE_REGION, + addr => dev_addr, + size => mpu_region_size, + region_type => region_type, + subregion_mask => + ewok.devices.get_user_device_subregions_mask (dev_id)); + + else + m4.mpu.disable_region (ewok.mpu.ISR_DEVICE_REGION); + end if; + + -- Mapping the ISR stack + ewok.mpu.regions_schedule + (region_number => ewok.mpu.ISR_STACK_REGION, + addr => ewok.layout.STACK_BOTTOM_TASK_ISR, + size => m4.mpu.REGION_SIZE_4KB, + region_type => ewok.mpu.REGION_TYPE_ISR_DATA, + subregion_mask => 0); + + else -- TASK_MODE_MAINTHREAD + + -------------------- + -- User main task -- + -------------------- + + dev_region := ewok.mpu.USER_DEV1_REGION; + dev_cannot_be_mapped := false; + + for i in 1 .. new_task.all.num_devs loop + dev_id := new_task.all.device_id(i); + + if dev_id = ID_DEV_UNUSED then + raise program_error; + end if; + + dev_size := ewok.devices.get_user_device_size (dev_id); + dev_addr := ewok.devices.get_user_device_addr (dev_id); + + if dev_id /= ID_DEV_UNUSED and dev_size > 0 and + ewok.devices.is_mapped (dev_id) + then + + ewok.mpu.bytes_to_region_size + (unsigned_32 (dev_size), mpu_region_size, ok); + + if not ok then + debug.panic + ("mpu_switching(): bytes_to_region_size() failed!"); + end if; + + if ewok.devices.is_user_device_region_ro (dev_id) then + region_type := ewok.mpu.REGION_TYPE_RO_USER_DEV; + else + region_type := ewok.mpu.REGION_TYPE_USER_DEV; + end if; + + if dev_cannot_be_mapped then + debug.log (debug.ALERT, + "task " & t_task_id'image (id) & + "mpu_switching(): DEVICE " & + t_device_id'image (dev_id) & " CANNOT BE MAPPED!"); + raise program_error; + else + ewok.mpu.regions_schedule + (region_number => dev_region, + addr => dev_addr, + size => mpu_region_size, + region_type => region_type, + subregion_mask => + ewok.devices.get_user_device_subregions_mask (dev_id)); + + if dev_region < ewok.mpu.USER_DEV2_REGION then + dev_region := dev_region + 1; + else + dev_cannot_be_mapped := true; + end if; + end if; + + end if; -- device must be mapped + + end loop; -- each device_id() + + -- Unmapping devices previously mapped by other tasks + if not dev_cannot_be_mapped then + for unused_region in dev_region .. ewok.mpu.USER_DEV2_REGION + loop + m4.mpu.disable_region (unused_region); + end loop; + end if; + + end if; -- ISR or MAIN thread + + -- + -- Mapping user code and data + -- + + declare + type t_mask is array (unsigned_8 range 1 .. 8) of bit + with pack, size => 8; + + function to_unsigned_8 is new ada.unchecked_conversion + (t_mask, unsigned_8); + + mask : t_mask := (others => 1); + begin + for i in 0 .. new_task.all.num_slots - 1 loop + mask(new_task.all.slot + i) := 0; + end loop; + + ewok.mpu.regions_schedule + (region_number => ewok.mpu.USER_CODE_REGION, + addr => applications.txt_user_region_base, + size => applications.txt_user_region_size, + region_type => ewok.mpu.REGION_TYPE_USER_CODE, + subregion_mask => to_unsigned_8 (mask)); + + -- FIXME: 128KB for user RAM is SoC Specific + ewok.mpu.regions_schedule + (region_number => ewok.mpu.USER_DATA_REGION, + addr => ewok.layout.USER_DATA_BASE, + size => m4.mpu.REGION_SIZE_128KB, + region_type => ewok.mpu.REGION_TYPE_USER_DATA, + subregion_mask => to_unsigned_8 (mask)); + end; + + else -- KERNEL TASK + + ewok.mpu.regions_schedule + (region_number => ewok.mpu.BOOT_ROM_REGION, + addr => soc.layout.BOOTROM_BASE, + size => m4.mpu.REGION_SIZE_32KB, + region_type => ewok.mpu.REGION_TYPE_BOOTROM, + subregion_mask => 0); + + end if; + + end mpu_switching; + + + function pendsv_handler + (frame_a : ewok.t_stack_frame_access) + return ewok.t_stack_frame_access + with SPARK_Mode => Off + is + begin + + sched_period := 0; + + if TSK.tasks_list(current_task_id).mode = TASK_MODE_ISRTHREAD and + ewok.tasks.get_state + (current_task_id, TASK_MODE_ISRTHREAD) = TASK_STATE_RUNNABLE + then + -- Keep ISR threads running until they finish + return frame_a; + end if; + + -- Save current context + if TSK.tasks_list(current_task_id).mode = TASK_MODE_ISRTHREAD then + -- ISR is done here. We don't really need to save its context. + TSK.tasks_list(current_task_id).isr_ctx.frame_a := frame_a; + else + TSK.tasks_list(current_task_id).ctx.frame_a := frame_a; + end if; + + -- Elect a new task and change current_task_id + current_task_id := task_elect; + + -- Apply MPU specific configuration + mpu_switching (current_task_id); + + -- Return the new context + if TSK.tasks_list(current_task_id).mode = TASK_MODE_ISRTHREAD then + return TSK.tasks_list(current_task_id).isr_ctx.frame_a; + else + return TSK.tasks_list(current_task_id).ctx.frame_a; + end if; + + end pendsv_handler; + + + function systick_handler + (frame_a : ewok.t_stack_frame_access) + return ewok.t_stack_frame_access + with SPARK_Mode => Off + is + begin + + m4.systick.increment; + sched_period := sched_period + 1; + + -- FIXME - CONFIG_SCHED_PERIOD must be in milliseconds, + -- not in ticks + if sched_period /= $CONFIG_SCHED_PERIOD then + return frame_a; + else + sched_period := 0; + end if; + + -- Waking-up sleeping tasks + ewok.sleep.check_is_awoke; + + -- Managing DWT cycle count overflow + soc.dwt.ovf_manage; + + -- Keep ISR threads running until they finish + if TSK.tasks_list(current_task_id).mode = TASK_MODE_ISRTHREAD and + ewok.tasks.get_state + (current_task_id, TASK_MODE_ISRTHREAD) = TASK_STATE_RUNNABLE + then + return frame_a; + end if; + + -- Save current context + if TSK.tasks_list(current_task_id).mode = TASK_MODE_ISRTHREAD then + -- ISR is done here. We don't really need to save its context. + TSK.tasks_list(current_task_id).isr_ctx.frame_a := frame_a; + else + TSK.tasks_list(current_task_id).ctx.frame_a := frame_a; + end if; + + -- Elect a new task + current_task_id := task_elect; + + -- Apply MPU specific configuration + mpu_switching (current_task_id); + + -- Return the new context + if TSK.tasks_list(current_task_id).mode = TASK_MODE_ISRTHREAD then + return TSK.tasks_list(current_task_id).isr_ctx.frame_a; + else + return TSK.tasks_list(current_task_id).ctx.frame_a; + end if; + + end systick_handler; + + + procedure init + with SPARK_Mode => Off + is + idle_task : t_task_access; + ok : boolean; + begin + + current_task_id := ID_KERNEL; + idle_task := get_task (current_task_id); + + ewok.interrupts.set_task_switching_handler + (soc.interrupts.INT_SYSTICK, + systick_handler'access, + ID_UNUSED, + ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + ewok.interrupts.set_task_switching_handler + (soc.interrupts.INT_PENDSV, + pendsv_handler'access, + ID_UNUSED, + ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + ewok.interrupts.set_task_switching_handler + (soc.interrupts.INT_SVC, + ewok.syscalls.handler.svc_handler'access, + ID_UNUSED, + ID_DEV_UNUSED, + ok); + + if not ok then raise program_error; end if; + + -- + -- Jump to the kernel task + -- + system.machine_code.asm + ("mov r0, %0" & ascii.lf & + "msr psp, r0" & ascii.lf & + "mov r0, 2" & ascii.lf & + "msr control, r0" & ascii.lf & + "mov r1, %1" & ascii.lf & + "bx r1", + inputs => + (system_address'asm_input + ("r",to_system_address (idle_task.ctx.frame_a)), + system_address'asm_input + ("r",idle_task.entry_point)), + clobber => "r0, r1", + volatile => true); + + end init; + + +end ewok.sched; diff --git a/Ada/ewok-sched.ads b/Ada/ewok-sched.ads new file mode 100644 index 0000000..89ea34a --- /dev/null +++ b/Ada/ewok-sched.ads @@ -0,0 +1,56 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok.tasks_shared; use ewok.tasks_shared; + +package ewok.sched + with SPARK_Mode => On +is + + ----------------------------------------------- + -- SPARK/ghost specific functions & procedures + ----------------------------------------------- + function current_task_is_valid + return boolean + with ghost; + + ---------------------------------------------- + -- sched functions + ---------------------------------------------- + + function get_current return ewok.tasks_shared.t_task_id + with + inline, + pre => (current_task_is_valid); + + procedure request_schedule + with SPARK_Mode => Off; + + function task_elect return t_task_id + with SPARK_Mode => Off; + + procedure init + with SPARK_Mode => Off; + +end ewok.sched; + diff --git a/Ada/ewok-sleep.adb b/Ada/ewok-sleep.adb new file mode 100644 index 0000000..800f1bf --- /dev/null +++ b/Ada/ewok-sleep.adb @@ -0,0 +1,95 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; + +package body ewok.sleep + with spark_mode => off +is + + package TSK renames ewok.tasks; + + + procedure sleeping + (task_id : in t_real_task_id; + ms : in milliseconds; + mode : in t_sleep_mode) + is + begin + sleep_info(task_id).sleep_until := + m4.systick.get_ticks + m4.systick.to_ticks (ms); + + if mode = SLEEP_MODE_INTERRUPTIBLE then + sleep_info(task_id).interruptible := true; + else + sleep_info(task_id).interruptible := false; + end if; + + TSK.set_state (task_id, TASK_MODE_MAINTHREAD, TASK_STATE_SLEEPING); + end sleeping; + + + procedure check_is_awoke + is + t : constant m4.systick.t_tick := m4.systick.get_ticks; + begin + for id in applications.list'range loop + if TSK.tasks_list(id).state = TASK_STATE_SLEEPING and then + t > sleep_info(id).sleep_until + then + TSK.set_state (id, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + end if; + end loop; + end check_is_awoke; + + + procedure try_waking_up + (task_id : in t_real_task_id) + is + begin + if sleep_info(task_id).sleep_until < m4.systick.get_ticks or + sleep_info(task_id).interruptible + then + TSK.set_state (task_id, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + end if; + end try_waking_up; + + + function is_sleeping + (task_id : in t_real_task_id) + return boolean + is + begin + if TSK.tasks_list(task_id).state = TASK_STATE_SLEEPING then + if sleep_info(task_id).sleep_until > m4.systick.get_ticks then + return true; + else + TSK.set_state (task_id, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + return false; + end if; + else + return false; + end if; + end is_sleeping; + +end ewok.sleep; diff --git a/Ada/ewok-sleep.ads b/Ada/ewok-sleep.ads new file mode 100644 index 0000000..90ba8c9 --- /dev/null +++ b/Ada/ewok-sleep.ads @@ -0,0 +1,106 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with applications; use applications; +with ewok.exported.sleep; use ewok.exported.sleep; +with m4.systick; + +package ewok.sleep + with spark_mode => off +is + + type t_sleep_info is record + sleep_until : m4.systick.t_tick; + interruptible : boolean; + end record; + + sleep_info : array (t_real_task_id'range) of t_sleep_info := + (others => (0, false)); + + + -- + -- \brief declare a time to sleep. + -- + -- This function is called in a syscall context and make the task + -- unschedulable for at least the given sleep_until. Only external events + -- (ISR, IPC) can awake the task during this period. If no external events + -- happend, the task is marked as schedulable at the end of the sleep + -- period, which means that the task is schedule *after* the sleep time, + -- not exactly at the sleep time end. + -- The variation of the time to wait between the end of the sleep time and + -- the effective time execution depends on the scheduling policy, the task + -- priority and the number of tasks on the system. + -- + -- \param id -- --e task id requesting to sleep + -- \param sleep_until the sleep duration in unit given by unit argument + -- \param mode -- sleep mode (preemptible by ISR or IPC, or not) + -- + procedure sleeping + (task_id : in t_real_task_id; + ms : in milliseconds; + mode : in t_sleep_mode) + with + global => (Output => sleep_info); + + -- + -- This function is called at each sched time of the systick handler, to + -- decrement the sleep_until of each task of 1. + -- If the speeptime reaches 0, the task mainthread is awoken. + -- + -- WARNING: there is case where the task is awoken *before* the end of + -- its sleep period: + -- - when an ISR arise + -- - when an IPC targeting the task is pushed + -- + -- In theses two cases, the sleep_cancel() function must be called in order + -- to cancel the current sleep round. The task is awoken by the corresponding + -- kernel module instead. + -- + procedure check_is_awoke + with + global => (In_Out => sleep_info); + + -- + -- As explain in sleep_round function explanations, some external events + -- may awake the main thread. In that case, the sleep process must be + -- canceled as the awoking process is made by another module. + -- tasks that have requested locked sleep will continue to sleep + -- + procedure try_waking_up + (task_id : in t_real_task_id) + with + global => (In_Out => sleep_info); + + -- + -- \brief check if a task is currently sleeping + -- + -- \param id the task id to check + -- + -- return true if a task is sleeping, or false + -- + function is_sleeping + (task_id : in t_real_task_id) + return boolean + with + global => (Input => sleep_info); + +end ewok.sleep; diff --git a/Ada/ewok-softirq.adb b/Ada/ewok-softirq.adb new file mode 100644 index 0000000..c6303e4 --- /dev/null +++ b/Ada/ewok-softirq.adb @@ -0,0 +1,394 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok.syscalls; use ewok.syscalls; +with ewok.tasks; use ewok.tasks; +with ewok.devices; +with ewok.exported.interrupts; + use type ewok.exported.interrupts.t_interrupt_config_access; +with ewok.interrupts; +with ewok.layout; +with ewok.sched; +with ewok.syscalls.init; +with ewok.syscalls.cfg; +with ewok.syscalls.gettick; +with ewok.syscalls.ipc; +with ewok.syscalls.lock; +with ewok.syscalls.reset; +with ewok.syscalls.sleep; +with ewok.syscalls.yield; +with soc.interrupts; use type soc.interrupts.t_interrupt; +with soc.nvic; +with m4.cpu; +with m4.cpu.instructions; +with debug; + +#if CONFIG_DBGLEVEL > 6 +with types.c; use types.c; +#end if; + +package body ewok.softirq + with spark_mode => off +is + + package TSK renames ewok.tasks; + + + procedure init + is + begin + p_isr_requests.init (isr_queue); + p_syscall_requests.init (syscall_queue); + debug.log + (debug.INFO, + "SOFTIRQ subsystem initialized: syscalls and user IRQ/FIQ are handled out of interrupt mode."); + end init; + + + procedure push_isr + (task_id : in ewok.tasks_shared.t_task_id; + params : in t_isr_parameters) + is + req : constant t_isr_request := (task_id, WAITING, params); + ok : boolean; + begin + p_isr_requests.write (isr_queue, req, ok); + if not ok then + debug.panic ("ewok.softirq.push_isr() failed. isr_queue is " + & p_isr_requests.ring_state'image + (p_isr_requests.state (isr_queue))); + end if; + ewok.tasks.set_state + (ID_SOFTIRQ, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + ewok.sched.request_schedule; + m4.cpu.instructions.full_memory_barrier; + end push_isr; + + + procedure push_syscall + (task_id : in ewok.tasks_shared.t_task_id) + is + req : constant t_syscall_request := (task_id, WAITING); + ok : boolean; + begin + p_syscall_requests.write (syscall_queue, req, ok); + if not ok then + debug.panic ("ewok.softirq.push_syscall() failed. syscall_queue is " + & p_syscall_requests.ring_state'image + (p_syscall_requests.state (syscall_queue))); + end if; + ewok.tasks.set_state + (ID_SOFTIRQ, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + ewok.sched.request_schedule; + m4.cpu.instructions.full_memory_barrier; + end push_syscall; + + + procedure syscall_handler (req : in t_syscall_request) + is + + type t_syscall_parameters_access is access all t_syscall_parameters; + + function to_syscall_parameters_access is new ada.unchecked_conversion + (system_address, t_syscall_parameters_access); + + svc : t_svc_type; + params_a : t_syscall_parameters_access; + begin + + -- + -- Getting the svc number from the SVC instruction + -- + + declare + PC : constant system_address := + TSK.tasks_list(req.caller_id).ctx.frame_a.all.PC; + inst : m4.cpu.instructions.t_svc_instruction + with import, address => to_address (PC - 2); + begin + if not inst.opcode'valid then + raise program_error; + end if; + + declare + svc_type : t_svc_type with address => inst.svc_num'address; + val : unsigned_8 with address => inst.svc_num'address; + begin + if not svc_type'valid then + debug.log (debug.WARNING, "invalid SVC: " + & unsigned_8'image (val)); + ewok.tasks.set_state + (req.caller_id, TASK_MODE_MAINTHREAD, TASK_STATE_FAULT); + set_return_value + (req.caller_id, TSK.tasks_list(req.caller_id).mode, SYS_E_DENIED); + return; + end if; + svc := svc_type; + end; + end; + + -- + -- Getting syscall parameters + -- + + params_a := + to_syscall_parameters_access (TSK.tasks_list(req.caller_id).ctx.frame_a.all.R0); + + if params_a = NULL then + debug.log (debug.WARNING, "(task" + & ewok.tasks_shared.t_task_id'image (req.caller_id) + & ") syscall with no parameters"); + return; + end if; + + if not params_a.all.syscall_type'valid then + debug.log (debug.WARNING, "(task" + & ewok.tasks_shared.t_task_id'image (req.caller_id) + & ") unknown syscall" & + ewok.syscalls.t_syscall_type'image (params_a.all.syscall_type)); + return; + end if; + + -- + -- Logging + -- + +#if CONFIG_DBGLEVEL > 6 + declare + len : constant natural := types.c.len (TSK.tasks_list(req.caller_id).name.all); + name : string (1 .. len); + begin + to_ada (name, TSK.tasks_list(req.caller_id).name.all); + debug.log (debug.INFO, "[" & name & "] svc" + & ewok.syscalls.t_svc_type'image (svc) + & ", syscall" & ewok.syscalls.t_syscall_type'image + (params_a.all.syscall_type)); + end; +#end if; + + -- + -- Calling the handler + -- + + if svc /= SVC_SYSCALL then + debug.panic ("ewok.softirq.syscall_handler(): wrong SVC" + & ewok.syscalls.t_svc_type'image (svc)); + end if; + + case params_a.all.syscall_type is + when SYS_YIELD => + ewok.syscalls.yield.sys_yield (req.caller_id, TASK_MODE_MAINTHREAD); + when SYS_INIT => + ewok.syscalls.init.sys_init + (req.caller_id, params_a.all.args, TASK_MODE_MAINTHREAD); + when SYS_IPC => + ewok.syscalls.ipc.sys_ipc + (req.caller_id, params_a.all.args, TASK_MODE_MAINTHREAD); + when SYS_CFG => + ewok.syscalls.cfg.sys_cfg + (req.caller_id, params_a.all.args, TASK_MODE_MAINTHREAD); + when SYS_GETTICK => + ewok.syscalls.gettick.sys_gettick + (req.caller_id, params_a.all.args, TASK_MODE_MAINTHREAD); + when SYS_RESET => + ewok.syscalls.reset.sys_reset + (req.caller_id, TASK_MODE_MAINTHREAD); + when SYS_SLEEP => + ewok.syscalls.sleep.sys_sleep + (req.caller_id, params_a.all.args, TASK_MODE_MAINTHREAD); + when SYS_LOCK => + ewok.syscalls.lock.sys_lock + (req.caller_id, params_a.all.args, TASK_MODE_MAINTHREAD); + end case; + + end syscall_handler; + + + procedure isr_handler (req : in t_isr_request) + is + params : t_parameters; + config_a : ewok.exported.interrupts.t_interrupt_config_access; + begin + + -- For further MPU mapping of the device, we need to know which device + -- triggered that interrupt. + -- Note + -- - EXTIs are not associated to any device because they can be + -- associated to several GPIO pins + -- - DMAs are not considered as devices because a single controller + -- can be used by several drivers. DMA streams are registered in a + -- specific table + + TSK.tasks_list(req.caller_id).isr_ctx.device_id := + ewok.interrupts.get_device_from_interrupt (req.params.interrupt); + + -- Keep track of some hint about scheduling policy to apply after the end + -- of the ISR execution + -- Note - see above + + config_a := + ewok.devices.get_interrupt_config_from_interrupt (req.params.interrupt); + + if config_a /= NULL then + TSK.tasks_list(req.caller_id).isr_ctx.sched_policy := config_a.all.mode; + else + TSK.tasks_list(req.caller_id).isr_ctx.sched_policy := ISR_STANDARD; + end if; + + -- Zeroing the ISR stack if the ISR previously executed belongs to + -- another task + if previous_isr_owner /= req.caller_id then + declare + stack : byte_array(1 .. ewok.layout.STACK_SIZE_TASK_ISR) + with address => to_address (ewok.layout.STACK_BOTTOM_TASK_ISR); + begin + stack := (others => 0); + end; + + previous_isr_owner := req.caller_id; + end if; + + -- + -- Note - isr_ctx.entry_point is a wrapper. The real ISR entry + -- point is defined in params(0) + -- + + -- User defined ISR handler + params(0) := req.params.handler; + + -- IRQ + params(1) := unsigned_32'val + (soc.nvic.to_irq_number (req.params.interrupt)); + + -- Status and data returned by the 'posthook' treatement + -- (cf. ewok.posthook.exec) + params(2) := req.params.posthook_status; + params(3) := req.params.posthook_data; + + create_stack + (ewok.layout.STACK_TOP_TASK_ISR, + TSK.tasks_list(req.caller_id).isr_ctx.entry_point, -- Wrapper + params, + TSK.tasks_list(req.caller_id).isr_ctx.frame_a); + + TSK.tasks_list(req.caller_id).mode := TASK_MODE_ISRTHREAD; + ewok.tasks.set_state + (req.caller_id, TASK_MODE_ISRTHREAD, TASK_STATE_RUNNABLE); + + end isr_handler; + + + procedure main_task + is + isr_req : t_isr_request; + sys_req : t_syscall_request; + ok : boolean; + begin + + loop + + -- + -- User ISRs + -- + + loop + m4.cpu.disable_irq; + p_isr_requests.read (isr_queue, isr_req, ok); + m4.cpu.enable_irq; + + exit when not ok; + + if isr_req.state = WAITING then + if TSK.tasks_list(isr_req.caller_id).state /= TASK_STATE_LOCKED + then + m4.cpu.disable_irq; + isr_handler (isr_req); + isr_req.state := DONE; + m4.cpu.enable_irq; +#if CONFIG_ISR_REACTIVITY + m4.cpu.instructions.full_memory_barrier; + ewok.sched.request_schedule; +#end if; + else + m4.cpu.disable_irq; + p_isr_requests.write (isr_queue, isr_req, ok); + if not ok then + debug.panic + ("softirq.main_task() failed to add ISR request"); + end if; + m4.cpu.instructions.full_memory_barrier; + ewok.sched.request_schedule; + m4.cpu.enable_irq; + end if; + else + raise program_error; + end if; + + end loop; + + m4.cpu.instructions.full_memory_barrier; + + -- + -- Syscalls + -- + + loop + + m4.cpu.disable_irq; + p_syscall_requests.read (syscall_queue, sys_req, ok); + m4.cpu.enable_irq; + + exit when not ok; + + if sys_req.state = WAITING then + syscall_handler (sys_req); + sys_req.state := DONE; + else + debug.panic + ("ewok.softirq.main_task() syscall request not in WAITING state"); + end if; + end loop; + + -- + -- Set softirq task as IDLE if there is no more request to handle + -- + + m4.cpu.disable_irq; + + if p_isr_requests.state (isr_queue) = p_isr_requests.EMPTY and + p_syscall_requests.state (syscall_queue) = p_syscall_requests.EMPTY + then + ewok.tasks.set_state + (ID_SOFTIRQ, TASK_MODE_MAINTHREAD, TASK_STATE_IDLE); + m4.cpu.instructions.full_memory_barrier; + ewok.sched.request_schedule; + end if; + + m4.cpu.enable_irq; + + end loop; + + end main_task; + + +end ewok.softirq; diff --git a/Ada/ewok-softirq.ads b/Ada/ewok-softirq.ads new file mode 100644 index 0000000..72d4972 --- /dev/null +++ b/Ada/ewok-softirq.ads @@ -0,0 +1,89 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ada.unchecked_conversion; +with ewok.tasks_shared; use ewok.tasks_shared; +with soc.interrupts; +with rings; + +package ewok.softirq + with spark_mode => off +is + + type t_state is (DONE, WAITING); + + type t_isr_parameters is record + handler : system_address; + interrupt : soc.interrupts.t_interrupt; + posthook_status : unsigned_32; + posthook_data : unsigned_32; + end record; + + type t_isr_request is record + caller_id : ewok.tasks_shared.t_task_id; + state : t_state; + params : t_isr_parameters; + end record; + + type t_syscall_request is record + caller_id : ewok.tasks_shared.t_task_id; + state : t_state; + end record; + + MAX_QUEUE_SIZE : constant := 20; + + package p_isr_requests is new rings (t_isr_request, MAX_QUEUE_SIZE); + use p_isr_requests; + + isr_queue : p_isr_requests.ring; + + package p_syscall_requests is new rings (t_syscall_request, MAX_QUEUE_SIZE); + use p_syscall_requests; + + syscall_queue : p_syscall_requests.ring; + + procedure init + with + convention => c, + export => true, + external_name => "softirq_init", + global => null; + + procedure push_isr + (task_id : in ewok.tasks_shared.t_task_id; + params : in t_isr_parameters); + + procedure push_syscall + (task_id : in ewok.tasks_shared.t_task_id); + + procedure syscall_handler (req : in t_syscall_request); + + procedure isr_handler (req : in t_isr_request); + + procedure main_task; + +private + + previous_isr_owner : t_task_id := ID_UNUSED; + +end ewok.softirq; diff --git a/Ada/ewok-syscalls-handler.adb b/Ada/ewok-syscalls-handler.adb new file mode 100644 index 0000000..0565f64 --- /dev/null +++ b/Ada/ewok-syscalls-handler.adb @@ -0,0 +1,300 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.sched; +with ewok.softirq; +with ewok.syscalls.dma; +with ewok.syscalls.yield; +with ewok.syscalls.reset; +with ewok.syscalls.sleep; +with ewok.syscalls.gettick; +with ewok.syscalls.lock; +with ewok.syscalls.cfg.mem; +with ewok.exported.interrupts; + use type ewok.exported.interrupts.t_interrupt_config_access; +with applications; +with m4.cpu.instructions; +with debug; + +package body ewok.syscalls.handler + with spark_mode => off +is + + type t_syscall_parameters_access is access all t_syscall_parameters; + function to_syscall_parameters_access is new ada.unchecked_conversion + (system_address, t_syscall_parameters_access); + + function is_synchronous_syscall + (sys_params_a : t_syscall_parameters_access) + return boolean + is + begin + + case sys_params_a.all.syscall_type is + when SYS_YIELD => return true; + when SYS_INIT => return false; + when SYS_IPC => return false; + when SYS_CFG => + declare + syscall : t_syscalls_cfg + with address => sys_params_a.all.args(0)'address; + begin + if syscall = CFG_DMA_RELOAD or + syscall = CFG_DMA_RECONF or + syscall = CFG_DMA_DISABLE or + syscall = CFG_DEV_MAP or + syscall = CFG_DEV_UNMAP + then + return true; + else + return false; + end if; + end; + when SYS_GETTICK => return true; + when SYS_RESET => return true; + when SYS_SLEEP => return true; + when SYS_LOCK => return true; + end case; + + end is_synchronous_syscall; + + + procedure exec_synchronous_syscall + (current_id : in ewok.tasks_shared.t_task_id; + mode : in ewok.tasks_shared.t_task_mode; + sys_params_a : in t_syscall_parameters_access) + is + begin + + case sys_params_a.all.syscall_type is + when SYS_YIELD => + ewok.syscalls.yield.sys_yield (current_id, mode); + + when SYS_INIT => raise program_error; + when SYS_IPC => raise program_error; + + when SYS_CFG => + declare + syscall : t_syscalls_cfg + with address => sys_params_a.all.args(0)'address; + begin + case syscall is + when CFG_GPIO_SET => raise program_error; + when CFG_GPIO_GET => raise program_error; + + when CFG_DMA_RECONF => + ewok.syscalls.dma.sys_cfg_dma_reconf (current_id, + sys_params_a.all.args, mode); + + when CFG_DMA_RELOAD => + ewok.syscalls.dma.sys_cfg_dma_reload (current_id, + sys_params_a.all.args, mode); + + when CFG_DMA_DISABLE => + ewok.syscalls.dma.sys_cfg_dma_disable (current_id, + sys_params_a.all.args, mode); + + when CFG_DEV_MAP => + ewok.syscalls.cfg.mem.dev_map (current_id, + sys_params_a.all.args, mode); + + when CFG_DEV_UNMAP => + ewok.syscalls.cfg.mem.dev_unmap (current_id, + sys_params_a.all.args, mode); + end case; + end; + + when SYS_GETTICK => + ewok.syscalls.gettick.sys_gettick + (current_id, + sys_params_a.all.args, mode); + + when SYS_RESET => + ewok.syscalls.reset.sys_reset + (current_id, mode); + + when SYS_SLEEP => + ewok.syscalls.sleep.sys_sleep + (current_id, sys_params_a.all.args, mode); + + when SYS_LOCK => + ewok.syscalls.lock.sys_lock + (current_id, sys_params_a.all.args, mode); + end case; + + end exec_synchronous_syscall; + + + function svc_handler + (frame_a : t_stack_frame_access) + return t_stack_frame_access + is + + svc : t_svc_type; + sys_params_a : t_syscall_parameters_access; + current_a : ewok.tasks.t_task_access; + current_id : t_task_id; + +#if CONFIG_SCHED_SUPPORT_FISR + fast_isr : constant boolean := true; +#else + fast_isr : constant boolean := false; +#end if; + + begin + + current_id := ewok.sched.get_current; + current_a := ewok.tasks.get_task (current_id); + + -- FIXME + -- When there are numerous SVC, it seems that SYSTICK might generate an + -- improper tail-chaining with a priority inversion resulting in SVC + -- beeing handled after SYSTICK. + if current_id not in applications.list'range then + debug.log (""); + raise program_error; + end if; + + -- + -- We must save the frame pointer because synchronous syscall don't refer + -- to the parameters on the stack indexed by 'frame_a' but to + -- 'current_a' (they access 'frame_a' via 'current_a.all.ctx.frame_a' + -- or 'current_a.all.isr_ctx.frame_a') + -- + + if ewok.tasks.get_mode (current_id) = TASK_MODE_MAINTHREAD then + current_a.all.ctx.frame_a := frame_a; + else + current_a.all.isr_ctx.frame_a := frame_a; + end if; + + -- + -- Getting the svc number from the SVC instruction + -- + + declare + inst : m4.cpu.instructions.t_svc_instruction + with import, address => to_address (frame_a.all.PC - 2); + begin + if not inst.opcode'valid then + raise program_error; + end if; + + declare + svc_type : t_svc_type with address => inst.svc_num'address; + begin + if not svc_type'valid then + ewok.tasks.set_state + (current_id, TASK_MODE_MAINTHREAD, TASK_STATE_FAULT); + set_return_value + (current_id, current_a.all.mode, SYS_E_DENIED); + return frame_a; + end if; + svc := svc_type; + end; + end; + + -- + -- Managing SVCs + -- + + case svc is + + when SVC_SYSCALL => + + -- Extracting syscall parameters + sys_params_a := to_syscall_parameters_access (frame_a.all.R0); + + if not sys_params_a.all.syscall_type'valid then + ewok.tasks.set_state + (current_id, TASK_MODE_MAINTHREAD, TASK_STATE_FAULT); + set_return_value + (current_id, ewok.tasks.get_mode(current_id), SYS_E_DENIED); + return frame_a; + end if; + + if current_a.all.mode = TASK_MODE_ISRTHREAD then + if is_synchronous_syscall (sys_params_a) then + exec_synchronous_syscall + (current_id, current_a.all.mode, sys_params_a); + else + set_return_value + (current_id, TASK_MODE_ISRTHREAD, SYS_E_DENIED); + end if; + else -- TASK_MODE_MAINTHREAD + if is_synchronous_syscall (sys_params_a) then + exec_synchronous_syscall + (current_id, current_a.all.mode, sys_params_a); + else + + ewok.softirq.push_syscall (current_id); + + ewok.tasks.set_state + (ID_SOFTIRQ, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + + ewok.tasks.set_state (current_id, TASK_MODE_MAINTHREAD, + TASK_STATE_SVC_BLOCKED); + + ewok.sched.request_schedule; + end if; + + end if; + + when SVC_TASK_DONE => + ewok.tasks.set_state + (current_id, TASK_MODE_MAINTHREAD, TASK_STATE_FINISHED); + + ewok.sched.request_schedule; + + when SVC_ISR_DONE => + + if fast_isr and + current_a.all.isr_ctx.sched_policy = ISR_FORCE_MAINTHREAD + then + declare + current_state : constant t_task_state := + ewok.tasks.get_state (current_id, TASK_MODE_MAINTHREAD); + begin + if current_state = TASK_STATE_RUNNABLE or + current_state = TASK_STATE_IDLE + then + ewok.tasks.set_state + (current_id, TASK_MODE_MAINTHREAD, TASK_STATE_FORCED); + end if; + end; + end if; + + ewok.tasks.set_state + (current_id, TASK_MODE_ISRTHREAD, TASK_STATE_ISR_DONE); + + ewok.sched.request_schedule; + + end case; + + return frame_a; + + end svc_handler; + + +end ewok.syscalls.handler; diff --git a/Ada/ewok-syscalls-handler.ads b/Ada/ewok-syscalls-handler.ads new file mode 100644 index 0000000..48cc0ec --- /dev/null +++ b/Ada/ewok-syscalls-handler.ads @@ -0,0 +1,30 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.syscalls.handler + with spark_mode => off +is + function svc_handler + (frame_a : t_stack_frame_access) + return t_stack_frame_access; +end ewok.syscalls.handler; diff --git a/Ada/ewok-syscalls.ads b/Ada/ewok-syscalls.ads new file mode 100644 index 0000000..37ade56 --- /dev/null +++ b/Ada/ewok-syscalls.ads @@ -0,0 +1,95 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ada.unchecked_conversion; + +package ewok.syscalls + with spark_mode +is + + -- FIXME - using an enumeration with size 32 + subtype t_syscall_ret is unsigned_32; + + SYS_E_DONE : constant t_syscall_ret := 0; + -- Syscall has succesfully being executed + SYS_E_INVAL : constant t_syscall_ret := 1; + -- Invalid input data + SYS_E_DENIED : constant t_syscall_ret := 2; + -- Permission is denied + SYS_E_BUSY : constant t_syscall_ret := 3; + -- Target is busy OR not enough ressources OR ressource is already used + + type t_svc_type is + (SVC_SYSCALL, + SVC_TASK_DONE, + SVC_ISR_DONE) + with size => 8; + + function to_svc_type is new ada.unchecked_conversion + (unsigned_8, t_svc_type); + + type t_syscall_type is + (SYS_YIELD, + SYS_INIT, + SYS_IPC, + SYS_CFG, + SYS_GETTICK, + SYS_RESET, + SYS_SLEEP, + SYS_LOCK) + with size => 32; + + type t_syscalls_init is + (INIT_DEVACCESS, + INIT_DMA, + INIT_DMA_SHM, + INIT_GETTASKID, + INIT_DONE); + + type t_syscalls_ipc is + (IPC_LOG, + IPC_RECV_SYNC, + IPC_SEND_SYNC, + IPC_RECV_ASYNC, + IPC_SEND_ASYNC); + + type t_syscalls_cfg is + (CFG_GPIO_SET, + CFG_GPIO_GET, + CFG_DMA_RECONF, + CFG_DMA_RELOAD, + CFG_DMA_DISABLE, + CFG_DEV_MAP, + CFG_DEV_UNMAP); + + type t_syscalls_lock is + (LOCK_ENTER, + LOCK_EXIT); + + type t_syscall_parameters is record + syscall_type : t_syscall_type; + args : aliased t_parameters; + end record + with pack; + +end ewok.syscalls; diff --git a/Ada/ewok-tasks.adb b/Ada/ewok-tasks.adb new file mode 100644 index 0000000..fca8378 --- /dev/null +++ b/Ada/ewok-tasks.adb @@ -0,0 +1,552 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with debug; +with m4.cpu; +with m4.cpu.instructions; +with ewok.layout; use ewok.layout; +with ewok.devices_shared; use ewok.devices_shared; +with ewok.softirq; + +with applications; -- Automatically generated +with sections; -- Automatically generated + +package body ewok.tasks + with spark_mode => off +is + + procedure idle_task + is + begin + debug.log (debug.INFO, "IDLE thread"); + m4.cpu.enable_irq; + loop + m4.cpu.instructions.wait_for_interrupt; + end loop; + end idle_task; + + + procedure finished_task + is + begin + loop null; end loop; + end finished_task; + + + procedure create_stack + (sp : in system_address; + pc : in system_address; + params : in ewok.t_parameters; + frame_a : out ewok.t_stack_frame_access) + is + begin + + frame_a := to_stack_frame_access (sp - (t_stack_frame'size / 8)); + + frame_a.all.R0 := params(0); + frame_a.all.R1 := params(1); + frame_a.all.R2 := params(2); + frame_a.all.R3 := params(3); + + frame_a.all.R4 := 0; + frame_a.all.R5 := 0; + frame_a.all.R6 := 0; + frame_a.all.R7 := 0; + frame_a.all.R8 := 0; + frame_a.all.R9 := 0; + frame_a.all.R10 := 0; + frame_a.all.R11 := 0; + frame_a.all.R12 := 0; + + frame_a.all.exc_return := m4.cpu.EXC_THREAD_MODE; + frame_a.all.LR := to_system_address (finished_task'address); + frame_a.all.PC := pc; + frame_a.all.PSR := m4.cpu.t_PSR_register' + (ISR_NUMBER => 0, + ICI_IT_lo => 0, + GE => 0, + Thumb => 1, + ICI_IT_hi => 0, + DSP_overflow => 0, + Overflow => 0, + Carry => 0, + Zero => 0, + Negative => 0); + + end create_stack; + + + procedure set_default_values (tsk : out t_task) + is + begin + tsk.name := " "; + tsk.entry_point := 0; + tsk.ttype := TASK_TYPE_USER; + tsk.mode := TASK_MODE_MAINTHREAD; + tsk.id := ID_UNUSED; + tsk.slot := 0; + tsk.num_slots := 0; + tsk.prio := 0; +#if CONFIG_KERNEL_DOMAIN + tsk.domain := 0; +#end if; + tsk.num_devs := 0; + tsk.num_devs_mmapped := 0; +#if CONFIG_KERNEL_SCHED_DEBUG + tsk.count := 0; + tsk.force_count := 0; + tsk.isr_count := 0; +#end if; +#if CONFIG_KERNEL_DMA_ENABLE + tsk.num_dma_shms := 0; + tsk.dma_shm := + (others => ewok.exported.dma.t_dma_shm_info' + (granted_id => ID_UNUSED, + accessed_id => ID_UNUSED, + base => 0, + size => 0, + access_type => ewok.exported.dma.SHM_ACCESS_READ)); + + tsk.num_dma_id := 0; + tsk.dma_id := (others => ewok.dma_shared.ID_DMA_UNUSED); +#end if; + tsk.init_done := false; + tsk.device_id := (others => ewok.devices_shared.ID_DEV_UNUSED); + tsk.data_slot_start := 0; + tsk.data_slot_end := 0; + tsk.txt_slot_start := 0; + tsk.txt_slot_end := 0; + tsk.stack_size := 0; + tsk.state := TASK_STATE_EMPTY; + tsk.isr_state := TASK_STATE_EMPTY; + tsk.ipc_endpoints := (others => NULL); + tsk.ctx.frame_a := NULL; + tsk.isr_ctx := t_isr_context'(0, ID_DEV_UNUSED, ISR_STANDARD, NULL); + end set_default_values; + + + procedure init_softirq_task + is + params : constant t_parameters := (others => 0); + begin + + -- Setting default values + set_default_values (tasks_list(ID_SOFTIRQ)); + + tasks_list(ID_SOFTIRQ).name := softirq_task_name; + + tasks_list(ID_SOFTIRQ).entry_point := + to_system_address (ewok.softirq.main_task'address); + + if tasks_list(ID_SOFTIRQ).entry_point mod 2 = 0 then + tasks_list(ID_SOFTIRQ).entry_point := + tasks_list(ID_SOFTIRQ).entry_point + 1; + end if; + + tasks_list(ID_SOFTIRQ).ttype := TASK_TYPE_KERNEL; + tasks_list(ID_SOFTIRQ).mode := TASK_MODE_MAINTHREAD; + tasks_list(ID_SOFTIRQ).id := ID_SOFTIRQ; + + tasks_list(ID_SOFTIRQ).slot := 0; -- unused + tasks_list(ID_SOFTIRQ).num_slots := 0; -- unused + + -- Zeroing the stack + declare + stack : byte_array(1 .. STACK_SIZE_SOFTIRQ) + with address => to_address (STACK_TOP_SOFTIRQ - STACK_SIZE_SOFTIRQ); + begin + stack := (others => 0); + end; + + -- Create the initial stack frame and set the stack pointer + create_stack + (STACK_TOP_SOFTIRQ, + tasks_list(ID_SOFTIRQ).entry_point, + params, + tasks_list(ID_SOFTIRQ).ctx.frame_a); + + tasks_list(ID_SOFTIRQ).stack_size := STACK_SIZE_SOFTIRQ; + tasks_list(ID_SOFTIRQ).state := TASK_STATE_IDLE; + tasks_list(ID_SOFTIRQ).isr_state := TASK_STATE_IDLE; + + for i in tasks_list(ID_SOFTIRQ).ipc_endpoints'range loop + tasks_list(ID_SOFTIRQ).ipc_endpoints(i) := NULL; + end loop; + + debug.log (debug.INFO, "Created context for SOFTIRQ task (pc: " + & system_address'image (tasks_list(ID_SOFTIRQ).entry_point) + & ") sp: " + & system_address'image + (to_system_address (tasks_list(ID_SOFTIRQ).ctx.frame_a))); + + end init_softirq_task; + + + procedure init_idle_task + is + params : constant t_parameters := (others => 0); + begin + + -- Setting default values + set_default_values (tasks_list(ID_KERNEL)); + + tasks_list(ID_KERNEL).name := idle_task_name; + + tasks_list(ID_KERNEL).entry_point := + to_system_address (idle_task'address); + + if tasks_list(ID_KERNEL).entry_point mod 2 = 0 then + tasks_list(ID_KERNEL).entry_point := + tasks_list(ID_KERNEL).entry_point + 1; + end if; + + tasks_list(ID_KERNEL).ttype := TASK_TYPE_KERNEL; + tasks_list(ID_KERNEL).mode := TASK_MODE_MAINTHREAD; + tasks_list(ID_KERNEL).id := ID_KERNEL; + + tasks_list(ID_KERNEL).slot := 0; -- unused + tasks_list(ID_KERNEL).num_slots := 0; -- unused + + -- Zeroing the stack + declare + stack : byte_array(1 .. STACK_SIZE_IDLE) + with address => to_address (STACK_TOP_IDLE - STACK_SIZE_IDLE); + begin + stack := (others => 0); + end; + + -- Create the initial stack frame and set the stack pointer + create_stack + (STACK_TOP_IDLE, + tasks_list(ID_KERNEL).entry_point, + params, + tasks_list(ID_KERNEL).ctx.frame_a); + + tasks_list(ID_KERNEL).stack_size := STACK_SIZE_IDLE; + tasks_list(ID_KERNEL).state := TASK_STATE_RUNNABLE; + tasks_list(ID_KERNEL).isr_state := TASK_STATE_IDLE; + + for i in tasks_list(ID_KERNEL).ipc_endpoints'range loop + tasks_list(ID_KERNEL).ipc_endpoints(i) := NULL; + end loop; + + debug.log (debug.INFO, "Created context for IDLE task (pc: " + & system_address'image (tasks_list(ID_KERNEL).entry_point) + & ") sp: " + & system_address'image + (to_system_address (tasks_list(ID_KERNEL).ctx.frame_a))); + + end init_idle_task; + + + procedure init_apps + is + user_base : system_address; + params : t_parameters; + begin + + if applications.t_real_task_id'last > ID_APP7 then + debug.panic ("Too many apps"); + end if; + + user_base := applications.txt_user_region_base; + + for id in applications.list'range loop + + set_default_values (tasks_list(id)); + + tasks_list(id).name := applications.list(id).name; + + tasks_list(id).entry_point := + user_base + + to_unsigned_32 (applications.list(id).slot - 1) + * FW_MAX_USER_SIZE; + + if tasks_list(id).entry_point mod 2 = 0 then + tasks_list(id).entry_point := tasks_list(id).entry_point + 1; + end if; + + tasks_list(id).ttype := TASK_TYPE_USER; + tasks_list(id).mode := TASK_MODE_MAINTHREAD; + tasks_list(id).id := id; + + tasks_list(id).slot := applications.list(id).slot; + tasks_list(id).num_slots := applications.list(id).num_slots; + + tasks_list(id).prio := applications.list(id).priority; + +#if CONFIG_KERNEL_DOMAIN + tasks_list(id).domain := applications.list(id).domain; +#end if; + +#if CONFIG_KERNEL_SCHED_DEBUG + tasks_list(id).count := 0; + tasks_list(id).force_count := 0; + tasks_list(id).isr_count := 0; +#end if; + +#if CONFIG_KERNEL_DMA_ENABLE + tasks_list(id).num_dma_shms := 0; + tasks_list(id).dma_shm := + (others => ewok.exported.dma.t_dma_shm_info' + (granted_id => ID_UNUSED, + accessed_id => ID_UNUSED, + base => 0, + size => 0, + access_type => ewok.exported.dma.SHM_ACCESS_READ)); + tasks_list(id).num_dma_id := 0; + tasks_list(id).dma_id := + (others => ewok.dma_shared.ID_DMA_UNUSED); +#end if; + + tasks_list(id).num_devs := 0; + tasks_list(id).num_devs_mmapped := 0; + + tasks_list(id).device_id := (others => ID_DEV_UNUSED); + + tasks_list(id).init_done := false; + + tasks_list(id).data_slot_start := + USER_DATA_BASE + + to_unsigned_32 (tasks_list(id).slot - 1) + * USER_DATA_SIZE; + + tasks_list(id).data_slot_end := + USER_DATA_BASE + + to_unsigned_32 + (tasks_list(id).slot + tasks_list(id).num_slots - 1) + * USER_DATA_SIZE; + + tasks_list(id).txt_slot_start := tasks_list(id).entry_point - 1; + + tasks_list(id).txt_slot_end := + user_base + + to_unsigned_32 + (applications.list(id).slot + tasks_list(id).num_slots - 1) + * FW_MAX_USER_SIZE; + + tasks_list(id).stack_size := applications.list(id).stack_size; + tasks_list(id).state := TASK_STATE_RUNNABLE; + tasks_list(id).isr_state := TASK_STATE_IDLE; + + for i in tasks_list(id).ipc_endpoints'range loop + tasks_list(id).ipc_endpoints(i) := NULL; + end loop; + + -- Zeroing the stack + declare + stack : byte_array(1 .. unsigned_32 (tasks_list(id).stack_size)) + with address => to_address + (tasks_list(id).data_slot_end - + unsigned_32 (tasks_list(id).stack_size)); + begin + stack := (others => 0); + end; + + -- Create the initial stack frame and set the stack pointer + params := t_parameters'(to_unsigned_32 (id), 0, 0, 0); + + create_stack + (tasks_list(id).data_slot_end, + tasks_list(id).entry_point, + params, + tasks_list(id).ctx.frame_a); + + tasks_list(id).isr_ctx.entry_point := applications.list(id).start_isr; + + declare + begin + debug.log (debug.INFO, "created task " & tasks_list(id).name + & " (pc: " & system_address'image (tasks_list(id).entry_point) + & ", sp: " & system_address'image + (to_system_address (tasks_list(id).ctx.frame_a)) + & ", ID" & t_task_id'image (id) & ")"); + end; + + end loop; + + end init_apps; + + + function get_task (id : ewok.tasks_shared.t_task_id) + return t_task_access + is + begin + return tasks_list(id)'access; + end get_task; + + + function get_task_id (name : t_task_name) + return ewok.tasks_shared.t_task_id + is + + -- String comparison is a bit tricky here because: + -- - We want it case-unsensitive ('a' and 'A' are the same) + -- - The nul character and space ' ' are consider the same + -- + -- The following inner functions are needed to effect comparisons: + + -- Convert a character to uppercase + function to_upper (c : character) + return character + is + val : constant natural := character'pos (c); + begin + return + (if c in 'a' .. 'z' then character'val (val - 16#20#) else c); + end; + + -- Test if a character is 'nul' + function is_nul (c : character) + return boolean + is begin + return c = ASCII.NUL or c = ' '; + end; + + -- Test if the 2 strings are the same + function is_same (s1: t_task_name; s2 : t_task_name) + return boolean + is begin + for i in t_task_name'range loop + if is_nul (s1(i)) and is_nul (s2(i)) then + return true; + end if; + if to_upper (s1(i)) /= to_upper (s2(i)) then + return false; + end if; + end loop; + return true; + end; + + begin + for id in applications.list'range loop + if is_same (tasks_list(id).name, name) then + return id; + end if; + end loop; + return ID_UNUSED; + end get_task_id; + + +#if CONFIG_KERNEL_DOMAIN + function get_domain (id : in ewok.tasks_shared.t_task_id) + return unsigned_8 + is + begin + return tasks_list(id).domain; + end get_domain; +#end if; + + + function get_state + (id : ewok.tasks_shared.t_task_id; + mode : t_task_mode) + return t_task_state + is + begin + if mode = TASK_MODE_MAINTHREAD then + return tasks_list(id).state; + else -- TASK_MODE_ISRTHREAD + return tasks_list(id).isr_state; + end if; + end get_state; + + procedure set_state + (id : ewok.tasks_shared.t_task_id; + mode : t_task_mode; + state : t_task_state) + is + begin + if mode = TASK_MODE_MAINTHREAD then + tasks_list(id).state := state; + else -- TASK_MODE_ISRTHREAD + tasks_list(id).isr_state := state; + end if; + end set_state; + + function get_mode + (id : in ewok.tasks_shared.t_task_id) + return t_task_mode + is + begin + return tasks_list(id).mode; + end get_mode; + + procedure set_mode + (id : in ewok.tasks_shared.t_task_id; + mode : in ewok.tasks_shared.t_task_mode) + is + begin + tasks_list(id).mode := mode; + end set_mode; + + -- FIXME useful ? + function is_user (id : ewok.tasks_shared.t_task_id) return boolean + is + begin + return (id in applications.t_real_task_id); + end is_user; + + + procedure set_return_value + (id : in ewok.tasks_shared.t_task_id; + mode : in t_task_mode; + val : in unsigned_32) + is + begin + case mode is + when TASK_MODE_MAINTHREAD => + tasks_list(id).ctx.frame_a.all.R0 := val; + when TASK_MODE_ISRTHREAD => + tasks_list(id).isr_ctx.frame_a.all.R0 := val; + end case; + end set_return_value; + + + procedure task_init + is + begin + + for id in tasks_list'range loop + set_default_values (tasks_list(id)); + end loop; + + init_idle_task; + init_softirq_task; + init_apps; + + sections.task_map_data; + + end task_init; + + + function is_init_done + (id : ewok.tasks_shared.t_task_id) + return boolean + is + begin + return tasks_list(id).init_done; + end is_init_done; + + +end ewok.tasks; diff --git a/Ada/ewok-tasks.ads b/Ada/ewok-tasks.ads new file mode 100644 index 0000000..0abd0f0 --- /dev/null +++ b/Ada/ewok-tasks.ads @@ -0,0 +1,253 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.devices_shared; +with ewok.ipc; +with ewok.exported.dma; +with ewok.dma_shared; + + +package ewok.tasks + with spark_mode => off +is + + subtype t_task_name is string (1 .. 8); + + type t_task_state is ( + -- No task in this slot + TASK_STATE_EMPTY, + + -- Task can be elected by the scheduler with its standard priority + -- or an ISR is ready for execution + TASK_STATE_RUNNABLE, + + -- Force the scheduler to choose that task + TASK_STATE_FORCED, + + -- Pending syscall. Task can't be scheduled. + TASK_STATE_SVC_BLOCKED, + + -- An ISR is finished + TASK_STATE_ISR_DONE, + + -- Task currently has nothing to do, not schedulable + TASK_STATE_IDLE, + + -- Task is sleeping + TASK_STATE_SLEEPING, + + -- Task has generated an exception (memory fault, etc.), not + -- schedulable anymore + TASK_STATE_FAULT, + + -- Task has return from its main() function. Yet its ISR handlers can + -- still be executed if needed + TASK_STATE_FINISHED, + + -- Task has emitted a blocking send(target) and is waiting for that + -- the EndPoint shared with the receiver gets ready + TASK_STATE_IPC_SEND_BLOCKED, + + -- Task has emitted a blocking recv(target) and is waiting for a + -- send() + TASK_STATE_IPC_RECV_BLOCKED, + + -- Task has emitted a blocking send(target) and is waiting recv() + -- acknowledgement from the target task + TASK_STATE_IPC_WAIT_ACK, + + -- Task has entered in a critical section. Related ISRs can't be executed + TASK_STATE_LOCKED); + + type t_task_type is + (-- Kernel task + TASK_TYPE_KERNEL, + -- User task, being executed in user mode, with restricted access + TASK_TYPE_USER); + + type t_main_context is record + frame_a : ewok.t_stack_frame_access; + end record; + + type t_isr_context is record + entry_point : system_address; + device_id : ewok.devices_shared.t_device_id; + sched_policy : ewok.tasks_shared.t_scheduling_post_isr; + frame_a : ewok.t_stack_frame_access; + end record; + + -- + -- Tasks + -- + + MAX_DEVS_PER_TASK : constant := 4; + MAX_DMAS_PER_TASK : constant := 8; + MAX_INTERRUPTS_PER_TASK : constant := 8; + MAX_DMA_SHM_PER_TASK : constant := 4; + + type t_registered_dma_index_list is array (unsigned_32 range <>) of + ewok.dma_shared.t_user_dma_index; + + type t_dma_shm_info_list is array (unsigned_32 range <>) of + ewok.exported.dma.t_dma_shm_info; + + type t_device_id_list is array (unsigned_8 range <>) of + ewok.devices_shared.t_device_id; + + type t_task is record + name : t_task_name; + entry_point : system_address; + ttype : t_task_type; + mode : t_task_mode; + id : ewok.tasks_shared.t_task_id; + slot : unsigned_8; -- 1: first slot (0: unused) + num_slots : unsigned_8; + prio : unsigned_8; +#if CONFIG_KERNEL_DOMAIN + domain : unsigned_8; +#end if; +#if CONFIG_KERNEL_SCHED_DEBUG + count : unsigned_32; + force_count : unsigned_32; + isr_count : unsigned_32; +#end if; +#if CONFIG_KERNEL_DMA_ENABLE + num_dma_shms : unsigned_32 range 0 .. MAX_DMA_SHM_PER_TASK; + dma_shm : t_dma_shm_info_list (1 .. MAX_DMA_SHM_PER_TASK); + num_dma_id : unsigned_32 range 0 .. MAX_DMAS_PER_TASK; + dma_id : t_registered_dma_index_list (1 .. MAX_DMAS_PER_TASK); +#end if; + num_devs : unsigned_8 range 0 .. MAX_DEVS_PER_TASK; + num_devs_mmapped : unsigned_8; + device_id : t_device_id_list (1 .. MAX_DEVS_PER_TASK); + + init_done : boolean; + data_slot_start : system_address; + data_slot_end : system_address; + txt_slot_start : system_address; + txt_slot_end : system_address; + stack_size : unsigned_16; + state : t_task_state; + isr_state : t_task_state; + ipc_endpoints : ewok.ipc.t_endpoints (ewok.tasks_shared.t_task_id'range); + ctx : aliased t_main_context; + isr_ctx : aliased t_isr_context; + end record; + + type t_task_access is access all t_task; + + type t_task_array is array (t_task_id range <>) of aliased t_task; + + ------------- + -- Globals -- + ------------- + + -- The list of the running tasks + tasks_list : t_task_array (ID_APP1 .. ID_KERNEL); + + softirq_task_name : aliased t_task_name := "SOFTIRQ" & " "; + idle_task_name : aliased t_task_name := "IDLE" & " "; + + + --------------- + -- Functions -- + --------------- + + procedure idle_task with no_return; + procedure finished_task with no_return; + + procedure create_stack + (sp : in system_address; + pc : in system_address; + params : in ewok.t_parameters; + frame_a : out ewok.t_stack_frame_access); + -- Note: see ewok.tasks.interfaces + + procedure set_default_values (tsk : out t_task); + + procedure init_softirq_task; + procedure init_idle_task; + procedure init_apps; + + function is_user (id : ewok.tasks_shared.t_task_id) return boolean; + + function get_task (id : ewok.tasks_shared.t_task_id) + return t_task_access; + +#if CONFIG_KERNEL_DOMAIN + function get_domain (id : in ewok.tasks_shared.t_task_id) + return unsigned_8 + with inline; +#end if; + + function get_task_id (name : t_task_name) + return ewok.tasks_shared.t_task_id; + + -- FIXME - transitions between states + procedure set_state + (id : ewok.tasks_shared.t_task_id; + mode : t_task_mode; + state : t_task_state) + with inline; + + function get_state + (id : ewok.tasks_shared.t_task_id; + mode : t_task_mode) + return t_task_state + with inline; + + function get_mode + (id : in ewok.tasks_shared.t_task_id) + return t_task_mode + with + inline, + global => null; + + procedure set_mode + (id : in ewok.tasks_shared.t_task_id; + mode : in ewok.tasks_shared.t_task_mode) + with + inline, + global => ( In_Out => tasks_list ); + + -- Set return value inside a syscall + -- Note: mode must be defined as a task can do a syscall while in ISR mode + -- or in THREAD mode + procedure set_return_value + (id : in ewok.tasks_shared.t_task_id; + mode : in t_task_mode; + val : in unsigned_32); + + procedure task_init + with + convention => c, + export => true, + external_name => "task_init", + global => null; + + function is_init_done + (id : ewok.tasks_shared.t_task_id) + return boolean; + +end ewok.tasks; diff --git a/Ada/ewok-tasks_shared.ads b/Ada/ewok-tasks_shared.ads new file mode 100644 index 0000000..e7a7fdf --- /dev/null +++ b/Ada/ewok-tasks_shared.ads @@ -0,0 +1,61 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ada.unchecked_conversion; + +package ewok.tasks_shared + with spark_mode => off +is + type t_task_id is + (ID_UNUSED, + ID_APP1, + ID_APP2, + ID_APP3, + ID_APP4, + ID_APP5, + ID_APP6, + ID_APP7, + ID_SOFTIRQ, -- Softirq thread + ID_KERNEL); -- Idle thread + + type t_task_mode is + (TASK_MODE_MAINTHREAD, TASK_MODE_ISRTHREAD); + + type t_scheduling_post_isr is + (ISR_STANDARD, + ISR_FORCE_MAINTHREAD, + ISR_WITHOUT_MAINTHREAD); + + pragma Warnings (Off); + -- We have to turn warnings off because the size of the t_task_id may + -- differ + + function to_task_id is new ada.unchecked_conversion + (unsigned_32, t_task_id); + + function to_unsigned_32 is new ada.unchecked_conversion + (t_task_id, unsigned_32); + + pragma Warnings (On); + +end ewok.tasks_shared; diff --git a/Ada/ewok.ads b/Ada/ewok.ads new file mode 100644 index 0000000..5a57304 --- /dev/null +++ b/Ada/ewok.ads @@ -0,0 +1,61 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ada.unchecked_conversion; +with interfaces; use interfaces; +with types; use types; +with m4.cpu; + +package ewok + with spark_mode => off +is + + type t_stack_frame is record + R4, R5, R6, R7 : unsigned_32; + R8, R9, R10, R11 : unsigned_32; + exc_return : unsigned_32; + R0, R1, R2, R3 : unsigned_32; + R12 : unsigned_32; + LR : system_address; + PC : system_address; + PSR : m4.cpu.t_PSR_register; + end record + with size => 17 * 32; + + type t_stack_frame_access is access all t_stack_frame; + + function to_stack_frame_access is new ada.unchecked_conversion + (system_address, t_stack_frame_access); + + function to_system_address is new ada.unchecked_conversion + (t_stack_frame_access, system_address); + + + type t_parameters is array (0 .. 3) of unsigned_32 with pack; + + type t_parameters_access is access all t_parameters; + + function to_parameters_access is new ada.unchecked_conversion + (system_address, t_parameters_access); + +end ewok; diff --git a/Ada/exported/config.def b/Ada/exported/config.def new file mode 120000 index 0000000..c256095 --- /dev/null +++ b/Ada/exported/config.def @@ -0,0 +1 @@ +../generated/config.def \ No newline at end of file diff --git a/Ada/exported/ewok-exported-devices.ads b/Ada/exported/ewok-exported-devices.ads new file mode 100644 index 0000000..6bfde87 --- /dev/null +++ b/Ada/exported/ewok-exported-devices.ads @@ -0,0 +1,62 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with types.c; +with ewok.exported.interrupts; +with ewok.exported.gpios; + +package ewok.exported.devices + with spark_mode => off +is + + MAX_INTERRUPTS : constant := 4; + MAX_GPIOS : constant := 16; + + subtype t_device_name is types.c.c_string (1 .. 16); + type t_device_name_access is access all t_device_name; + + type t_interrupt_config_array is + array (unsigned_8 range <>) of + aliased ewok.exported.interrupts.t_interrupt_config; + + type t_gpio_config_array is + array (unsigned_8 range <>) of + aliased ewok.exported.gpios.t_gpio_config; + + type t_dev_map_mode is + (DEV_MAP_AUTO, + DEV_MAP_VOLUNTARY); + + type t_user_device is record + name : t_device_name; + base_addr : system_address; + size : unsigned_16; + interrupt_num : unsigned_8 range 0 .. MAX_INTERRUPTS; + gpio_num : unsigned_8 range 0 .. MAX_GPIOS; + map_mode : t_dev_map_mode; + interrupts : t_interrupt_config_array (1 .. MAX_INTERRUPTS); + gpios : t_gpio_config_array (1 .. MAX_GPIOS); + end record; + + type t_user_device_access is access all t_user_device; + +end ewok.exported.devices; diff --git a/Ada/exported/ewok-exported-dma.ads b/Ada/exported/ewok-exported-dma.ads new file mode 100644 index 0000000..9b85782 --- /dev/null +++ b/Ada/exported/ewok-exported-dma.ads @@ -0,0 +1,86 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; use ewok.tasks_shared; +with soc.dma.interfaces; +with types.c; + +package ewok.exported.dma + with spark_mode => off +is + + -- Specify DMA elements to (re)configure + type t_config_mask is new soc.dma.interfaces.t_config_mask; + + -- + -- User defined DMA configuration + -- + + type t_mode is new soc.dma.interfaces.t_mode; + type t_transfer_dir is new soc.dma.interfaces.t_transfer_dir; + type t_priority_level is new soc.dma.interfaces.t_priority_level; + type t_data_size is new soc.dma.interfaces.t_data_size; + type t_burst_size is new soc.dma.interfaces.t_burst_size; + type t_flow_controller is new soc.dma.interfaces.t_flow_controller; + + type t_controller is new soc.dma.t_dma_periph_index with size => 8; + subtype t_stream is unsigned_8 range 0 .. 7; + subtype t_channel is unsigned_8 range 0 .. 7; + + type t_dma_user_config is record + in_addr : system_address; + out_addr : system_address; + in_priority : t_priority_level; + out_priority : t_priority_level; + size : unsigned_16; -- size in bytes + controller : t_controller := ID_DMA1; + channel : t_channel := 0; + stream : t_stream := 0; + flow_controller : t_flow_controller; + transfer_dir : t_transfer_dir; + mode : t_mode; + memory_inc : types.c.bool; + periph_inc : types.c.bool; + data_size : t_data_size; + mem_burst_size : t_burst_size; + periph_burst_size : t_burst_size; + in_handler : system_address; -- ISR + out_handler : system_address; -- ISR + end record; + + type t_dma_user_config_access is access all t_dma_user_config; + + type t_dma_shm_access is (SHM_ACCESS_READ, SHM_ACCESS_WRITE); + + -- The caller (accessed_id) grant access to another task (granted_id) + -- to a range in its inner memory space. That mechanism permits to the + -- 'granted' to configure the DMA with an address that belongs to + -- the 'accessed' task. + type t_dma_shm_info is record + granted_id : t_task_id; + accessed_id : t_task_id; -- caller + base : system_address; + size : unsigned_16; + access_type : t_dma_shm_access; + end record; + +end ewok.exported.dma; diff --git a/Ada/exported/ewok-exported-gpios.ads b/Ada/exported/ewok-exported-gpios.ads new file mode 100644 index 0000000..b3876e5 --- /dev/null +++ b/Ada/exported/ewok-exported-gpios.ads @@ -0,0 +1,96 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.gpio; + +package ewok.exported.gpios + with spark_mode => off +is + + type t_gpio_settings is record + set_mode : bool; + set_type : bool; + set_speed : bool; + set_pupd : bool; + set_bsr_r : bool; + set_bsr_s : bool; + set_lck : bool; + set_af : bool; + set_exti : bool; + end record + with size => 16; + + for t_gpio_settings use record + set_mode at 0 range 0 .. 0; + set_type at 0 range 1 .. 1; + set_speed at 0 range 2 .. 2; + set_pupd at 0 range 3 .. 3; + set_bsr_r at 0 range 4 .. 4; + set_bsr_s at 0 range 5 .. 5; + set_lck at 0 range 6 .. 6; + set_af at 0 range 7 .. 7; + set_exti at 0 range 8 .. 8; + end record; + + type t_gpio_ref is record + pin : soc.gpio.t_gpio_pin_index; + port : soc.gpio.t_gpio_port_index; + end record + with pack, size => 8, convention => c_pass_by_copy; + + type t_interface_gpio_mode is (GPIO_IN, GPIO_OUT, GPIO_AF, GPIO_ANALOG); + + type t_interface_gpio_pupd is (GPIO_NOPULL, GPIO_PULLUP, GPIO_PULLDOWN); + + type t_interface_gpio_type is (GPIO_PUSH_PULL, GPIO_OPEN_DRAIN); + + type t_interface_gpio_speed is + (GPIO_LOW_SPEED, + GPIO_MEDIUM_SPEED, + GPIO_HIGH_SPEED, + GPIO_VERY_HIGH_SPEED); + + type t_interface_gpio_exti_trigger is + (GPIO_EXTI_TRIGGER_NONE, + GPIO_EXTI_TRIGGER_RISE, + GPIO_EXTI_TRIGGER_FALL, + GPIO_EXTI_TRIGGER_BOTH); + + type t_gpio_config is record + settings : t_gpio_settings; -- gpio_mask_t + kref : t_gpio_ref; + mode : t_interface_gpio_mode; + pupd : t_interface_gpio_pupd; + otype : t_interface_gpio_type; + ospeed : t_interface_gpio_speed; + af : unsigned_32; + bsr_r : unsigned_32; + bsr_s : unsigned_32; + lck : unsigned_32; + exti_trigger : t_interface_gpio_exti_trigger; + exti_handler : system_address; + end record; + + type t_gpio_config_access is access all t_gpio_config; + + +end ewok.exported.gpios; diff --git a/Ada/exported/ewok-exported-interrupts.ads b/Ada/exported/ewok-exported-interrupts.ads new file mode 100644 index 0000000..5ae87e0 --- /dev/null +++ b/Ada/exported/ewok-exported-interrupts.ads @@ -0,0 +1,111 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; +with ewok.interrupts; +with soc.interrupts; + +package ewok.exported.interrupts + with spark_mode => off +is + + MAX_POSTHOOK_INSTR : constant := 10; + + type t_posthook_action is + (POSTHOOK_NIL, + POSTHOOK_READ, + POSTHOOK_WRITE, + POSTHOOK_WRITE_REG, -- C name "and" + POSTHOOK_WRITE_MASK); -- C name "mask" + + -- value <- register + type t_posthook_action_read is record + offset : unsigned_16; + value : unsigned_32; + end record; + + -- register <- value & mask + type t_posthook_action_write is record + offset : unsigned_16; + value : unsigned_32; + mask : unsigned_32; + end record; + + -- register(dest) <- register(src) & mask + type t_posthook_action_write_reg is record + offset_dest : unsigned_16; + offset_src : unsigned_16; + mask : unsigned_32; + mode : unsigned_8; + end record; + + -- register(dest) <- register(src) & register(mask) + type t_posthook_action_write_mask is record + offset_dest : unsigned_16; + offset_src : unsigned_16; + offset_mask : unsigned_16; + mode : unsigned_8; + end record; + + MODE_STANDARD : constant := 0; + MODE_NOT : constant := 1; + + type t_posthook_instruction (instr : t_posthook_action := POSTHOOK_NIL) is + record + case instr is + when POSTHOOK_NIL => + null; + when POSTHOOK_READ => + read : t_posthook_action_read; + when POSTHOOK_WRITE => + write : t_posthook_action_write; + when POSTHOOK_WRITE_REG => + write_reg : t_posthook_action_write_reg; + when POSTHOOK_WRITE_MASK => + write_mask : t_posthook_action_write_mask; + end case; + end record; + + -- number of posthooks + subtype t_posthook_instruction_number is + integer range 1 .. MAX_POSTHOOK_INSTR; + + -- array of posthooks + type t_posthook_instruction_list is + array (t_posthook_instruction_number'range) of t_posthook_instruction; + + type t_interrupt_posthook is record + action : t_posthook_instruction_list; -- Reading, writing, masking... + status : unsigned_16; + data : unsigned_16; + end record; + + type t_interrupt_config is record + handler : ewok.interrupts.t_interrupt_handler_access; + interrupt : soc.interrupts.t_interrupt; + mode : ewok.tasks_shared.t_scheduling_post_isr; + posthook : t_interrupt_posthook; + end record; + + type t_interrupt_config_access is access all t_interrupt_config; + +end ewok.exported.interrupts; diff --git a/Ada/exported/ewok-exported-sleep.ads b/Ada/exported/ewok-exported-sleep.ads new file mode 100644 index 0000000..e17e86a --- /dev/null +++ b/Ada/exported/ewok-exported-sleep.ads @@ -0,0 +1,32 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +package ewok.exported.sleep + with spark_mode => off +is + + type t_sleep_mode is + (SLEEP_MODE_INTERRUPTIBLE, + SLEEP_MODE_DEEP) -- Not interruptible + with size => 32; + +end ewok.exported.sleep; diff --git a/Ada/exported/ewok-exported-ticks.ads b/Ada/exported/ewok-exported-ticks.ads new file mode 100644 index 0000000..d38b081 --- /dev/null +++ b/Ada/exported/ewok-exported-ticks.ads @@ -0,0 +1,33 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.exported.ticks + with spark_mode => off +is + + type t_precision is + (PRECISION_MILLI_SEC, + PRECISION_MICRO_SEC, + PRECISION_CYCLE); + +end ewok.exported.ticks; diff --git a/Ada/exported/ewok-exported.ads b/Ada/exported/ewok-exported.ads new file mode 100644 index 0000000..267f9cf --- /dev/null +++ b/Ada/exported/ewok-exported.ads @@ -0,0 +1,25 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package ewok.exported is +end ewok.exported; diff --git a/Ada/generated/.placeholder b/Ada/generated/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/Ada/libgnat/Makefile b/Ada/libgnat/Makefile new file mode 100644 index 0000000..666ae71 --- /dev/null +++ b/Ada/libgnat/Makefile @@ -0,0 +1,33 @@ +LIB_NAME ?= libgnat +PROJ_FILES = ../../../ +LIB_FULL_NAME = $(LIB_NAME).a + +include $(PROJ_FILES)/Makefile.conf +include $(PROJ_FILES)/Makefile.gen + +APP_BUILD_DIR = $(BUILD_DIR)/kernel/$(LIB_NAME) +GNATLIB = $(APP_BUILD_DIR)/libabsp.a +OBJ_DIR = $(BUILD_DIR)/objs + +SRC_ADB = $(wildcard gnat/*.adb) +SRC_ADS = $(wildcard gnat/*.ads) + + +default: all + +show: + @echo "\tAPP_BUILD_DIR\t=> " $(APP_BUILD_DIR) + +all: $(APP_BUILD_DIR) $(APP_BUILD_DIR)/obj $(APP_BUILD_DIR)/libgnat.a + +$(APP_BUILD_DIR): + $(call cmd,mkdir) + +$(APP_BUILD_DIR)/obj: + $(call cmd,mkdir) + +$(APP_BUILD_DIR)/libgnat.a: gnat.gpr $(SRC_ADB) $(SRC_ADS) + $(call cmd,ada_lib) + +__clean: gnat.gpr + $(call cmd,ada_clean) diff --git a/Ada/libgnat/gnat.gpr b/Ada/libgnat/gnat.gpr new file mode 100644 index 0000000..6d68277 --- /dev/null +++ b/Ada/libgnat/gnat.gpr @@ -0,0 +1,35 @@ +library project Gnat is + + for Languages use ("Ada", "C"); + for Library_Kind use "static"; + for Library_Name use "gnat"; + for Target use "arm-eabi"; + for Runtime ("ada") use external("ADA_RUNTIME") & "/arm-eabi/lib/gnat/zfp-stm32f4/"; + + for Source_Dirs use ("gnat"); + for Object_Dir use external("BUILD_DIR") & "/obj"; + for Library_Dir use external("BUILD_DIR"); + + package Builder is + for Default_Switches ("Ada") use + ("-Os", "-x", "-nostdinc", "-nostdlib"); + end Builder; + + package Compiler is + + Common_Required_Switches := + ("-mlittle-endian", + "-mhard-float", + "-mcpu=cortex-m4", + "-mfpu=fpv4-sp-d16", + "-mthumb"); + + for Leading_Required_Switches ("Ada") use + Compiler'Leading_Required_Switches ("Ada") & + Common_Required_Switches & + ("-gnatg", -- Mandatory to compile GNAT units + "-gnatp"); -- Suppress all checks + + end Compiler; + +end Gnat; diff --git a/Ada/libgnat/gnat/ada.ads b/Ada/libgnat/gnat/ada.ads new file mode 120000 index 0000000..15f70cd --- /dev/null +++ b/Ada/libgnat/gnat/ada.ads @@ -0,0 +1 @@ +/opt/adacore-arm-eabi/arm-eabi/lib/gnat/zfp-stm32f4/gnat/ada.ads \ No newline at end of file diff --git a/Ada/libgnat/gnat/gnat.ads b/Ada/libgnat/gnat/gnat.ads new file mode 120000 index 0000000..f3c6ee3 --- /dev/null +++ b/Ada/libgnat/gnat/gnat.ads @@ -0,0 +1 @@ +/opt/adacore-arm-eabi/arm-eabi/lib/gnat/zfp-stm32f4/gnat/gnat.ads \ No newline at end of file diff --git a/Ada/libgnat/gnat/last_chance_handler.c b/Ada/libgnat/gnat/last_chance_handler.c new file mode 100644 index 0000000..a682f09 --- /dev/null +++ b/Ada/libgnat/gnat/last_chance_handler.c @@ -0,0 +1,12 @@ + +void dbg_log(const char const *fmt, ...); +void dbg_flush(void); + +void __gnat_last_chance_handler (char *file, int line) +{ + dbg_log("Error: ADA exception at %s +%d\n", file, line); + dbg_flush(); + while (1) + ; +} + diff --git a/Ada/libgnat/gnat/link_list.txt b/Ada/libgnat/gnat/link_list.txt new file mode 100644 index 0000000..d7bdf92 --- /dev/null +++ b/Ada/libgnat/gnat/link_list.txt @@ -0,0 +1,10 @@ +ada.ads +s-imgint.ads +s-imgint.adb +s-imglli.ads +s-imglli.adb +gnat.ads +s-imguns.ads +s-memmov.adb +s-memmov.ads +system.ads diff --git a/Ada/libgnat/gnat/s-imguns.adb b/Ada/libgnat/gnat/s-imguns.adb new file mode 100644 index 0000000..a110bd7 --- /dev/null +++ b/Ada/libgnat/gnat/s-imguns.adb @@ -0,0 +1,43 @@ +with System.Unsigned_Types; use System.Unsigned_Types; + +package body System.Img_Uns is + + -------------------- + -- Image_Unsigned -- + -------------------- + + procedure Image_Unsigned + (V : System.Unsigned_Types.Unsigned; + S : in out String; + P : out Natural) + is + pragma Assert (S'First = 1); + begin + P := 0; + Set_Image_Unsigned (V, S, P); + end Image_Unsigned; + + ------------------------ + -- Set_Image_Unsigned -- + ------------------------ + + Hex : constant array (System.Unsigned_Types.Unsigned range 0 .. 15) + of Character := "0123456789ABCDEF"; + + procedure Set_Image_Unsigned + (V : System.Unsigned_Types.Unsigned; + S : in out String; + P : in out Natural) + is + begin + if V >= 16 then + Set_Image_Unsigned (V / 16, S, P); + P := P + 1; + S (P) := Hex (V rem 16); + else + P := P + 1; + S (P) := Hex (V); + end if; + end Set_Image_Unsigned; + +end System.Img_Uns; diff --git a/Ada/processor.adb b/Ada/processor.adb new file mode 100644 index 0000000..e4cf355 --- /dev/null +++ b/Ada/processor.adb @@ -0,0 +1,35 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with m4.cpu; +with ewok.layout; + +package body processor + with spark_mode => on +is + + procedure processor_init is + begin + m4.cpu.set_msp_register (ewok.layout.STACK_TOP_TASK_INITIAL); + end processor_init; + +end processor; diff --git a/Ada/processor.ads b/Ada/processor.ads new file mode 100644 index 0000000..62736cb --- /dev/null +++ b/Ada/processor.ads @@ -0,0 +1,37 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package processor + with spark_mode => on +is + + procedure processor_init + with + convention => c, + export => true, + external_name => "processor_init", + global => null, + inline; + +end processor; + diff --git a/Ada/rings.adb b/Ada/rings.adb new file mode 100644 index 0000000..ef05d89 --- /dev/null +++ b/Ada/rings.adb @@ -0,0 +1,144 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + + +package body rings is + + procedure init + (r : out ring) + is + begin + r.top := ring_range'first; + r.bottom := ring_range'first; + r.state := EMPTY; + end init; + + + procedure write + (r : out ring; + item : in object; + success : out boolean) + is + begin + + if r.state = FULL then + success := false; + return; + end if; + + -- write + r.buf(r.top) := item; + + -- increment top + if r.top = r.buf'last then + r.top := r.buf'first; + else + r.top := r.top + 1; + end if; + + -- adjust state + if r.top = r.bottom then + r.state := FULL; + else + r.state := USED; + end if; + + success := true; + + end write; + + + procedure read + (r : in out ring; + item : out object; + success : out boolean) + is + begin + + -- read data only if buffer is not empty + if r.state = EMPTY then + success := false; + return; + end if; + + -- read + item := r.buf(r.bottom); + + -- incrementing bottom + if r.bottom = r.buf'last then + r.bottom := r.buf'first; + else + r.bottom := r.bottom + 1; + end if; + + -- adjust state + if r.bottom = r.top then + r.state := EMPTY; + else + r.state := USED; + end if; + + success := true; + + end read; + + + procedure unwrite + (r : out ring; + success : out boolean) + is + begin + + if r.state = EMPTY then + success := false; + return; + end if; + + -- decrementing top counter + if r.top = r.buf'first then + r.top := r.buf'last; + else + r.top := r.top - 1; + end if; + + -- adjust state + if r.bottom = r.top then + r.state := EMPTY; + else + r.state := USED; + end if; + + success := true; + + end unwrite; + + + function state + (r : in ring) + return ring_state + is + begin + return r.state; + end state; + +end rings; diff --git a/Ada/rings.ads b/Ada/rings.ads new file mode 100644 index 0000000..5ff385b --- /dev/null +++ b/Ada/rings.ads @@ -0,0 +1,77 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +-- +-- Ring buffer generic implementation +-- + +generic + type object is private; + size : in integer := 512; + +package rings is + pragma Preelaborate; + + type ring is private; + type ring_state is (EMPTY, USED, FULL); + + procedure init + (r : out ring); + + -- write some new data and increment top counter + procedure write + (r : out ring; + item : in object; + success : out boolean); + + -- read some data and increment bottom counter + procedure read + (r : in out ring; + item : out object; + success : out boolean); + + -- decrement top counter + procedure unwrite + (r : out ring; + success : out boolean); + + -- return ring state (empty, used or full) + function state + (r : in ring) + return ring_state; + pragma inline (state); + +private + + type ring_range is new integer range 1 .. size; + type buffer is array (ring_range) of object; + + type ring is + record + buf : buffer; + top : ring_range := ring_range'first; -- place to write + bottom : ring_range := ring_range'first; -- place to read + state : ring_state := EMPTY; + end record; + +end rings; diff --git a/Ada/syscalls/config.def b/Ada/syscalls/config.def new file mode 120000 index 0000000..c256095 --- /dev/null +++ b/Ada/syscalls/config.def @@ -0,0 +1 @@ +../generated/config.def \ No newline at end of file diff --git a/Ada/syscalls/ewok-syscalls-cfg-gpio.adb b/Ada/syscalls/ewok-syscalls-cfg-gpio.adb new file mode 100644 index 0000000..03f31a7 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-cfg-gpio.adb @@ -0,0 +1,134 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.gpio; +with ewok.exported.gpios; +with ewok.sanitize; + +package body ewok.syscalls.cfg.gpio + with spark_mode => off +is + + procedure gpio_set + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + + ref : ewok.exported.gpios.t_gpio_ref + with address => params(1)'address; + + val : unsigned_8 + with address => params(2)'address; + + begin + + -- Task initialization is complete ? + if not is_init_done (caller_id) then + goto ret_denied; + end if; + + -- Valid t_gpio_ref ? + if not ref.pin'valid or not ref.port'valid then + goto ret_inval; + end if; + + -- Does that GPIO really belongs to the caller ? + if not ewok.gpio.belong_to (caller_id, ref) then + goto ret_denied; + end if; + + -- Write the pin + if val >= 1 then + ewok.gpio.write_pin (ref, 1); + else + ewok.gpio.write_pin (ref, 0); + end if; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end gpio_set; + + + procedure gpio_get + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + + ref : ewok.exported.gpios.t_gpio_ref + with address => params(1)'address; + + val : unsigned_8 + with address => to_address (params(2)); + + begin + + -- Task initialization is complete ? + if not is_init_done (caller_id) then + goto ret_denied; + end if; + + -- Valid t_gpio_ref ? + if not ref.pin'valid or not ref.port'valid then + goto ret_inval; + end if; + + -- Does &val is in the caller address space ? + if not ewok.sanitize.is_word_in_data_slot + (to_system_address (val'address), caller_id, mode) + then + goto ret_denied; + end if; + + -- Read the pin + val := unsigned_8 (ewok.gpio.read_pin (ref)); + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end gpio_get; + +end ewok.syscalls.cfg.gpio; diff --git a/Ada/syscalls/ewok-syscalls-cfg-gpio.ads b/Ada/syscalls/ewok-syscalls-cfg-gpio.ads new file mode 100644 index 0000000..eec5198 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-cfg-gpio.ads @@ -0,0 +1,38 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; + +package ewok.syscalls.cfg.gpio + with spark_mode => off +is + procedure gpio_set + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + + procedure gpio_get + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + +end ewok.syscalls.cfg.gpio; diff --git a/Ada/syscalls/ewok-syscalls-cfg-mem.adb b/Ada/syscalls/ewok-syscalls-cfg-mem.adb new file mode 100644 index 0000000..dca7eed --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-cfg-mem.adb @@ -0,0 +1,263 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.exported.devices; use ewok.exported.devices; +with ewok.devices; +with ewok.devices_shared; +with ewok.sched; + +#if CONFIG_DEBUG_SYS_CFG_MEM +with debug; +#end if; + +package body ewok.syscalls.cfg.mem + with spark_mode => off +is + + procedure dev_map + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + dev_descriptor : unsigned_8 + with address => params(1)'address; + dev_id : ewok.devices_shared.t_device_id; + dev : ewok.exported.devices.t_user_device_access; + ok : boolean; + begin + + -- Valid device descriptor ? + + if dev_descriptor < ewok.tasks.tasks_list(caller_id).device_id'first or + dev_descriptor > ewok.tasks.tasks_list(caller_id).num_devs + then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "invalid device descriptor"); +#end if; + goto ret_inval; + end if; + + dev_id := ewok.tasks.tasks_list(caller_id).device_id (dev_descriptor); + dev := ewok.devices.get_user_device (dev_id); + + -- + -- Checking user inputs + -- + + if mode = ewok.tasks_shared.TASK_MODE_ISRTHREAD then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): forbidden in ISR mode"); +#end if; + goto ret_denied; + end if; + + if not is_init_done (caller_id) then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): forbidden during init sequence"); +#end if; + goto ret_denied; + end if; + + if ewok.devices.get_task_from_id (dev_id) /= caller_id then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): device not owned by the task"); +#end if; + goto ret_inval; + end if; + + if dev.map_mode /= ewok.exported.devices.DEV_MAP_VOLUNTARY then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): not a DEV_MAP_VOLUNTARY device"); +#end if; + goto ret_denied; + end if; + + -- + -- End of checks, let's do the mapping + -- + + if ewok.devices.is_mapped (dev_id) then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): device already mapped"); +#end if; + goto ret_busy; + end if; + + + ewok.devices.map_device (dev_id, ok); + + if not ok then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): unable to map device"); +#end if; + goto ret_busy; + end if; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + ewok.sched.request_schedule; + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_BUSY); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end dev_map; + + + procedure dev_unmap + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + dev_descriptor : unsigned_8 + with address => params(1)'address; + dev_id : ewok.devices_shared.t_device_id; + dev : ewok.exported.devices.t_user_device_access; + ok : boolean; + begin + + -- Valid device descriptor ? + if dev_descriptor < ewok.tasks.tasks_list(caller_id).device_id'first or + dev_descriptor > ewok.tasks.tasks_list(caller_id).num_devs + then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "invalid device descriptor"); +#end if; + goto ret_inval; + end if; + + dev_id := ewok.tasks.tasks_list(caller_id).device_id (dev_descriptor); + dev := ewok.devices.get_user_device (dev_id); + + -- + -- Checking user inputs + -- + + if mode = ewok.tasks_shared.TASK_MODE_ISRTHREAD then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): forbidden in ISR mode"); +#end if; + goto ret_denied; + end if; + + if not is_init_done (caller_id) then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): forbidden during init sequence"); +#end if; + goto ret_denied; + end if; + + if ewok.devices.get_task_from_id (dev_id) /= caller_id then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): device not owned by the task"); +#end if; + goto ret_inval; + end if; + + if dev.map_mode /= ewok.exported.devices.DEV_MAP_VOLUNTARY then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): not a DEV_MAP_VOLUNTARY device"); +#end if; + goto ret_denied; + end if; + + -- + -- End of checks, unmapping the device + -- + + if not ewok.devices.is_mapped (dev_id) then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): device is not mapped"); +#end if; + goto ret_inval; + end if; + + ewok.devices.unmap_device (dev_id, ok); + + if not ok then +#if CONFIG_DEBUG_SYS_CFG_MEM + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_cfg(CFG_DEV_MAP): unable to unmap device"); +#end if; + goto ret_busy; + end if; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + ewok.sched.request_schedule; + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_BUSY); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + + end dev_unmap; + +end ewok.syscalls.cfg.mem; diff --git a/Ada/syscalls/ewok-syscalls-cfg-mem.ads b/Ada/syscalls/ewok-syscalls-cfg-mem.ads new file mode 100644 index 0000000..ed0f928 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-cfg-mem.ads @@ -0,0 +1,38 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; + +package ewok.syscalls.cfg.mem + with spark_mode => off +is + procedure dev_map + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + + procedure dev_unmap + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + +end ewok.syscalls.cfg.mem; diff --git a/Ada/syscalls/ewok-syscalls-cfg.adb b/Ada/syscalls/ewok-syscalls-cfg.adb new file mode 100644 index 0000000..f7bbf7c --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-cfg.adb @@ -0,0 +1,73 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.syscalls.cfg.gpio; +with ewok.syscalls.cfg.mem; +with ewok.syscalls.dma; + +package body ewok.syscalls.cfg + with spark_mode => off +is + + procedure sys_cfg + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out ewok.t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + syscall : t_syscalls_cfg + with address => params(0)'address; + begin + + if not syscall'valid then + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end if; + + case syscall is + when CFG_GPIO_SET => + ewok.syscalls.cfg.gpio.gpio_set (caller_id, params, mode); + when CFG_GPIO_GET => + ewok.syscalls.cfg.gpio.gpio_get (caller_id, params, mode); +#if CONFIG_KERNEL_DMA_ENABLE + when CFG_DMA_RECONF => + ewok.syscalls.dma.sys_cfg_dma_reconf (caller_id, params, mode); + when CFG_DMA_RELOAD => + ewok.syscalls.dma.sys_cfg_dma_reload (caller_id, params, mode); + when CFG_DMA_DISABLE => + ewok.syscalls.dma.sys_cfg_dma_disable (caller_id, params, mode); +#else + when CFG_DMA_RECONF => null; + when CFG_DMA_RELOAD => null; + when CFG_DMA_DISABLE => null; +#end if; + when CFG_DEV_MAP => + ewok.syscalls.cfg.mem.dev_map (caller_id, params, mode); + when CFG_DEV_UNMAP => + ewok.syscalls.cfg.mem.dev_unmap (caller_id, params, mode); + end case; + + end sys_cfg; + + +end ewok.syscalls.cfg; diff --git a/Ada/syscalls/ewok-syscalls-cfg.ads b/Ada/syscalls/ewok-syscalls-cfg.ads new file mode 100644 index 0000000..9f7d556 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-cfg.ads @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; + +package ewok.syscalls.cfg + with spark_mode => off +is + + procedure sys_cfg + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out ewok.t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + +end ewok.syscalls.cfg; diff --git a/Ada/syscalls/ewok-syscalls-dma.adb b/Ada/syscalls/ewok-syscalls-dma.adb new file mode 100644 index 0000000..4f4027a --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-dma.adb @@ -0,0 +1,408 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.exported.dma; +with ewok.dma_shared; +with ewok.dma; +with ewok.perm; +with ewok.sanitize; +with debug; + +package body ewok.syscalls.dma + with spark_mode => off +is + + package TSK renames ewok.tasks; + + procedure init_do_reg_dma + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + dma_config : ewok.exported.dma.t_dma_user_config + with import, address => to_address (params(1)); + descriptor : unsigned_32 + with import, address => to_address (params(2)); + index : ewok.dma_shared.t_registered_dma_index; + ok : boolean; + begin + + -- Forbidden after end of task initialization + if is_init_done (caller_id) then + goto ret_denied; + end if; + + -- DMA allowed for that task? + if not ewok.perm.ressource_is_granted + (ewok.perm.PERM_RES_DEV_DMA, caller_id) + then + debug.log (debug.WARNING, "init_do_reg_dma(): permission not granted"); + goto ret_denied; + end if; + + -- Ada based sanitation using on types compliance + if not dma_config'valid_scalars + then + debug.log (debug.WARNING, "init_do_reg_dma(): invalid dma_t"); + goto ret_inval; + end if; + + -- Does dma_config'address and descriptor'address are in the caller + -- address space ? + if not ewok.sanitize.is_range_in_data_slot + (to_system_address (dma_config'address), + dma_config'size/8, + caller_id, + mode) + or + not ewok.sanitize.is_word_in_data_slot + (to_system_address (descriptor'address), caller_id, mode) + then + debug.log (debug.WARNING, "init_do_reg_dma(): parameters not in task's memory space"); + goto ret_denied; + end if; + + -- Verify DMA configuration transmitted by the user + if not ewok.dma.sanitize_dma + (dma_config, caller_id, + ewok.exported.dma.t_config_mask'(others => false), mode) + then + debug.log (debug.WARNING, "init_do_reg_dma(): invalid dma configuration"); + goto ret_inval; + end if; + + -- Check if controller/stream are already used + if ewok.dma.dma_is_already_used (dma_config) then + debug.log (debug.WARNING, "init_do_reg_dma(): dma configuration already used"); + goto ret_denied; + end if; + + -- Is there any user descriptor available ? + if TSK.tasks_list(caller_id).num_dma_id < MAX_DMAS_PER_TASK then + TSK.tasks_list(caller_id).num_dma_id := + TSK.tasks_list(caller_id).num_dma_id + 1; + else + goto ret_busy; + end if; + + -- Initialization + ewok.dma.init_stream (dma_config, caller_id, index, ok); + if not ok then + debug.log (debug.WARNING, "init_do_reg_dma(): dma initialization failed"); + goto ret_denied; + end if; + + declare + dma_descriptor : constant unsigned_32 := + TSK.tasks_list(caller_id).num_dma_id; + begin + TSK.tasks_list(caller_id).dma_id(dma_descriptor) := index; + end; + + descriptor := TSK.tasks_list(caller_id).num_dma_id; + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + descriptor := 0; + set_return_value (caller_id, mode, SYS_E_BUSY); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + descriptor := 0; + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + descriptor := 0; + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + end; + + + procedure init_do_reg_dma_shm + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + user_dma_shm : ewok.exported.dma.t_dma_shm_info + with import, address => to_address (params(1)); + granted_id : ewok.tasks_shared.t_task_id; + begin + + -- Forbidden after end of task initialization + if is_init_done (caller_id) then + goto ret_denied; + end if; + + -- Ada based sanitation using on types compliance + if not user_dma_shm'valid_scalars + then + debug.log (debug.WARNING, "init_do_reg_dma_shm(): invalid dma_shm_t"); + goto ret_inval; + end if; + + -- Does user_dma_shm'address is in the caller address space ? + if not ewok.sanitize.is_range_in_data_slot + (to_system_address (user_dma_shm'address), + user_dma_shm'size/8, + caller_id, + mode) + then + debug.log (debug.WARNING, "init_do_reg_dma_shm(): parameters not in task's memory space"); + goto ret_denied; + end if; + + -- Verify DMA shared memory configuration transmitted by the user + if not ewok.dma.sanitize_dma_shm (user_dma_shm, caller_id, mode) + then + debug.log (debug.WARNING, "init_do_reg_dma_shm(): invalid configuration"); + goto ret_inval; + end if; + + granted_id := user_dma_shm.granted_id; + + -- Does the task can share memory with its target task? + if not ewok.perm.dmashm_is_granted (caller_id, granted_id) + then + debug.log (debug.WARNING, "init_do_reg_dma_shm(): not granted"); + goto ret_denied; + end if; + + -- Is there any user descriptor available ? + if TSK.tasks_list(granted_id).num_dma_shms < MAX_DMA_SHM_PER_TASK and + TSK.tasks_list(caller_id).num_dma_shms < MAX_DMA_SHM_PER_TASK + then + TSK.tasks_list(granted_id).num_dma_shms := TSK.tasks_list(granted_id).num_dma_shms + 1; + TSK.tasks_list(caller_id).num_dma_shms := TSK.tasks_list(caller_id).num_dma_shms + 1; + else + debug.log (debug.WARNING, "init_do_reg_dma_shm(): busy"); + goto ret_busy; + end if; + + TSK.tasks_list(granted_id).dma_shm(TSK.tasks_list(granted_id).num_dma_shms) := user_dma_shm; + TSK.tasks_list(caller_id).dma_shm(TSK.tasks_list(caller_id).num_dma_shms) := user_dma_shm; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_BUSY); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + end init_do_reg_dma_shm; + + + procedure sys_cfg_dma_reconf + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + new_dma_config : ewok.exported.dma.t_dma_user_config + with import, address => to_address (params(1)); + config_mask : ewok.exported.dma.t_config_mask + with import, address => params(2)'address; + dma_descriptor : unsigned_32 + with import, address => params(3)'address; + ok : boolean; + begin + + -- Forbidden before end of task initialization + if not is_init_done (caller_id) then + goto ret_denied; + end if; + + -- Ada based sanitation using on types compliance is not easy, + -- as only fields marked by config_mask have a real interpretation + -- These fields are checked in the dma_sanitize_dma() function call + -- bellow + + -- Does new_dma_config'address is in the caller address space ? + if not ewok.sanitize.is_range_in_data_slot + (to_system_address (new_dma_config'address), + new_dma_config'size/8, + caller_id, + mode) + then + debug.log (debug.WARNING, "sys_cfg_dma_reconf(): parameters not in task's memory space"); + goto ret_inval; + end if; + + -- Valid DMA descriptor ? + if dma_descriptor < TSK.tasks_list(caller_id).dma_id'first or + dma_descriptor > TSK.tasks_list(caller_id).num_dma_id + then + debug.log (debug.WARNING, "sys_cfg_dma_reconf(): invalid descriptor"); + goto ret_inval; + end if; + + -- Check if the user tried to change the DMA ctrl/channel/stream + -- parameters + if not ewok.dma.has_same_dma_channel + (TSK.tasks_list(caller_id).dma_id(dma_descriptor), new_dma_config) + then + debug.log (debug.WARNING, "sys_cfg_dma_reconf(): ctrl/channel/stream changed"); + goto ret_inval; + end if; + + -- Verify DMA configuration transmitted by the user + if not ewok.dma.sanitize_dma + (new_dma_config, caller_id, config_mask, mode) + then + debug.log (debug.WARNING, "sys_cfg_dma_reconf(): invalid configuration"); + goto ret_inval; + end if; + + -- Reconfigure the DMA controller + ewok.dma.reconfigure_stream + (new_dma_config, + TSK.tasks_list(caller_id).dma_id(dma_descriptor), + config_mask, + caller_id, + ok); + + if not ok then + debug.log (debug.WARNING, "sys_cfg_dma_reconf(): reconfiguration failed"); + goto ret_inval; + end if; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + end sys_cfg_dma_reconf; + + + procedure sys_cfg_dma_reload + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + dma_descriptor : unsigned_32 + with import, address => params(1)'address; + begin + + -- Forbidden before end of task initialization + if not is_init_done (caller_id) then + goto ret_denied; + end if; + + -- Valid DMA descriptor ? + if dma_descriptor < TSK.tasks_list(caller_id).dma_id'first or + dma_descriptor > TSK.tasks_list(caller_id).num_dma_id + then + debug.log (debug.WARNING, "sys_cfg_dma_reload(): invalid descriptor"); + goto ret_inval; + end if; + + ewok.dma.enable_dma_stream + (TSK.tasks_list(caller_id).dma_id(dma_descriptor)); + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + end sys_cfg_dma_reload; + + + procedure sys_cfg_dma_disable + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + dma_descriptor : unsigned_32 + with import, address => params(1)'address; + begin + + -- Forbidden before end of task initialization + if not is_init_done (caller_id) then + goto ret_denied; + end if; + + -- Valid DMA descriptor ? + if dma_descriptor < TSK.tasks_list(caller_id).dma_id'first or + dma_descriptor > TSK.tasks_list(caller_id).num_dma_id + then + debug.log (debug.WARNING, "sys_cfg_dma_disable(): invalid descriptor"); + goto ret_inval; + end if; + + ewok.dma.disable_dma_stream + (TSK.tasks_list(caller_id).dma_id(dma_descriptor)); + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + end sys_cfg_dma_disable; + + +end ewok.syscalls.dma; diff --git a/Ada/syscalls/ewok-syscalls-dma.ads b/Ada/syscalls/ewok-syscalls-dma.ads new file mode 100644 index 0000000..c310274 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-dma.ads @@ -0,0 +1,55 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; + +package ewok.syscalls.dma + with spark_mode => off +is + + procedure init_do_reg_dma + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + + procedure init_do_reg_dma_shm + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + + procedure sys_cfg_dma_reconf + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + + procedure sys_cfg_dma_reload + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + + procedure sys_cfg_dma_disable + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + + +end ewok.syscalls.dma; diff --git a/Ada/syscalls/ewok-syscalls-gettick.adb b/Ada/syscalls/ewok-syscalls-gettick.adb new file mode 100644 index 0000000..b7a7ab5 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-gettick.adb @@ -0,0 +1,110 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.perm; use ewok.perm; +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.exported.ticks; use ewok.exported.ticks; +with ewok.sanitize; +with debug; +with soc.dwt; + + +package body ewok.syscalls.gettick + with spark_mode => off +is + + procedure sys_gettick + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + value : unsigned_64 + with address => to_address (params(0)); + + precision : ewok.exported.ticks.t_precision + with address => params(1)'address; + begin + + -- + -- Verifying parameters + -- + + if not ewok.sanitize.is_range_in_data_slot + (to_system_address (value'address), 8, caller_id, mode) + then + debug.log (debug.WARNING, "[task" & ewok.tasks_shared.t_task_id'image (caller_id) + & "] sys_gettick: value (" + & system_address'image (to_system_address (value'address)) + & ") is not in caller space"); + goto ret_inval; + end if; + + if not precision'valid then + goto ret_inval; + end if; + + -- Verifying permisions + case precision is + when PRECISION_MILLI_SEC => + if not ewok.perm.ressource_is_granted + (PERM_RES_TIM_GETMILLI, caller_id) + then + goto ret_denied; + end if; + soc.dwt.get_milliseconds (value); + + when PRECISION_MICRO_SEC => + if not ewok.perm.ressource_is_granted + (PERM_RES_TIM_GETMICRO, caller_id) + then + goto ret_denied; + end if; + soc.dwt.get_microseconds (value); + + when PRECISION_CYCLE => + if not ewok.perm.ressource_is_granted + (PERM_RES_TIM_GETCYCLE, caller_id) + then + goto ret_denied; + end if; + soc.dwt.get_cycles (value); + end case; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + end sys_gettick; + +end ewok.syscalls.gettick; + diff --git a/Ada/syscalls/ewok-syscalls-gettick.ads b/Ada/syscalls/ewok-syscalls-gettick.ads new file mode 100644 index 0000000..6754035 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-gettick.ads @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; + +package ewok.syscalls.gettick + with spark_mode => off +is + + procedure sys_gettick + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + +end ewok.syscalls.gettick; diff --git a/Ada/syscalls/ewok-syscalls-init.adb b/Ada/syscalls/ewok-syscalls-init.adb new file mode 100644 index 0000000..67e2629 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-init.adb @@ -0,0 +1,280 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.devices_shared; use ewok.devices_shared; +with ewok.exported.devices; use ewok.exported.devices; +with ewok.devices; +with ewok.sanitize; +with ewok.dma; +with ewok.syscalls.dma; +with ewok.mpu; +with ewok.sched; +with debug; + +package body ewok.syscalls.init + with spark_mode => off +is + + package TSK renames ewok.tasks; + + + procedure init_do_reg_devaccess + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + udev : aliased ewok.exported.devices.t_user_device + with import, address => to_address (params(1)); + descriptor : unsigned_8 range 0 .. ewok.tasks.MAX_DEVS_PER_TASK + with address => to_address (params(2)); + dev_id : ewok.devices_shared.t_device_id; + ok : boolean; + begin + + -- Forbidden after end of task initialization + if TSK.is_init_done (caller_id) then + goto ret_denied; + end if; + + -- Note: The kernel might register some devices using this syscall + if TSK.is_user (caller_id) and then + (not ewok.sanitize.is_range_in_data_slot + (to_system_address (udev'address), + udev'size/8, + caller_id, + mode) + or + not ewok.sanitize.is_word_in_data_slot + (to_system_address (descriptor'address), caller_id, mode)) + then + debug.log (debug.WARNING, + "init_do_reg_devaccess(): udev not in task's memory space"); + goto ret_denied; + end if; + + -- Ada based sanitation using on types compliance + if not udev'valid_scalars + then + debug.log (debug.WARNING, "init_do_reg_devaccess(): invalid udev"); + goto ret_inval; + end if; + + if TSK.is_user (caller_id) and then + not ewok.devices.sanitize_user_defined_device + (udev'unchecked_access, caller_id) + then + debug.log (debug.WARNING, "init_do_reg_devaccess(): invalid udev"); + goto ret_inval; + end if; + + if udev.size > 0 and + udev.map_mode = DEV_MAP_AUTO and + TSK.tasks_list(caller_id).num_devs_mmapped = + ewok.mpu.MPU_MAX_EMPTY_REGIONS + then + debug.log (debug.WARNING, + "init_do_reg_devaccess(): no free region left to map the device"); + goto ret_busy; + end if; + + if TSK.tasks_list(caller_id).num_devs = TSK.MAX_DEVS_PER_TASK then + debug.log (debug.WARNING, + "init_do_reg_devaccess(): no space left to register the device"); + goto ret_busy; + end if; + + -- + -- Registering the device + -- + + ewok.devices.register_device (caller_id, udev'unchecked_access, dev_id, ok); + + if not ok then + debug.log (debug.WARNING, + "init_do_reg_devaccess(): failed to register the device"); + goto ret_denied; + end if; + + TSK.tasks_list(caller_id).num_devs + := TSK.tasks_list(caller_id).num_devs + 1; + + TSK.tasks_list(caller_id).device_id(TSK.tasks_list(caller_id).num_devs) + := dev_id; + + -- Descriptor transmitted to userspace + descriptor := TSK.tasks_list(caller_id).num_devs; + + if udev.size > 0 and udev.map_mode = DEV_MAP_AUTO then + TSK.tasks_list(caller_id).num_devs_mmapped := + TSK.tasks_list(caller_id).num_devs_mmapped + 1; + end if; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_BUSY); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + end init_do_reg_devaccess; + + + procedure init_do_done + (caller_id : in ewok.tasks_shared.t_task_id; + mode : in ewok.tasks_shared.t_task_mode) + is + ok : boolean; + begin + + -- Forbidden after end of task initialization + if TSK.is_init_done (caller_id) then + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end if; + + for i in 1 .. TSK.tasks_list(caller_id).num_devs loop + ewok.devices.enable_device + (TSK.tasks_list(caller_id).device_id(i), ok); + if not ok then + raise program_error; + end if; + end loop; + +#if CONFIG_KERNEL_DMA_ENABLE + for i in 1 .. TSK.tasks_list(caller_id).num_dma_id loop + ewok.dma.enable_dma_irq (TSK.tasks_list(caller_id).dma_id(i)); + end loop; +#end if; + + TSK.tasks_list(caller_id).init_done := true; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + + -- Request a schedule to ensure that the task has its devices mapped + -- afterward + ewok.sched.request_schedule; + end init_do_done; + + + procedure init_do_get_taskid + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + + target_name : TSK.t_task_name + with address => to_address (params(1)); + + target_id : ewok.tasks_shared.t_task_id + with address => to_address (params(2)); + + begin + + -- Forbidden after end of task initialization + if TSK.is_init_done (caller_id) then + goto ret_denied; + end if; + + -- Does &target_id is in the caller address space ? + if not ewok.sanitize.is_word_in_data_slot + (to_system_address (target_id'address), caller_id, mode) + then + goto ret_denied; + end if; + + target_id := TSK.get_task_id (target_name); + +#if CONFIG_KERNEL_DOMAIN + if TSK.get_domain (target_id) /= TSK.get_domain (caller_id) then + target_id := ID_UNUSED; + end if; +#end if; + + if target_id = ID_UNUSED then + goto ret_inval; + end if; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end init_do_get_taskid; + + + procedure sys_init + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + syscall : t_syscalls_init + with import, address => params(0)'address; + begin + + if not syscall'valid then + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end if; + + case syscall is + when INIT_DEVACCESS => init_do_reg_devaccess + (caller_id, params, mode); +#if CONFIG_KERNEL_DMA_ENABLE + when INIT_DMA => ewok.syscalls.dma.init_do_reg_dma + (caller_id, params, mode); + when INIT_DMA_SHM => ewok.syscalls.dma.init_do_reg_dma_shm + (caller_id, params, mode); +#end if; + when INIT_GETTASKID => init_do_get_taskid (caller_id, params, mode); + when INIT_DONE => init_do_done (caller_id, mode); + end case; + + end sys_init; + + +end ewok.syscalls.init; + diff --git a/Ada/syscalls/ewok-syscalls-init.ads b/Ada/syscalls/ewok-syscalls-init.ads new file mode 100644 index 0000000..4fea75b --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-init.ads @@ -0,0 +1,52 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; + +package ewok.syscalls.init + with spark_mode => off +is + + procedure init_do_reg_devaccess + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + with + convention => c, + export => true, + external_name => "init_do_reg_devaccess"; + + procedure init_do_done + (caller_id : in ewok.tasks_shared.t_task_id; + mode : in ewok.tasks_shared.t_task_mode); + + procedure init_do_get_taskid + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + + procedure sys_init + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + +end ewok.syscalls.init; diff --git a/Ada/syscalls/ewok-syscalls-ipc.adb b/Ada/syscalls/ewok-syscalls-ipc.adb new file mode 100644 index 0000000..694bb14 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-ipc.adb @@ -0,0 +1,768 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ada.unchecked_conversion; + +with ewok.ipc; use ewok.ipc; +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.sanitize; +with ewok.perm; +with ewok.sleep; +with ewok.softirq; +with types.c; use types.c; +--with m4.cpu; +with debug; + + +package body ewok.syscalls.ipc + with spark_mode => off +is + + procedure ipc_do_recv + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + blocking : in boolean; + mode : in ewok.tasks_shared.t_task_mode) + is + + ep : ewok.ipc.t_endpoint_access; + sender_a : ewok.tasks.t_task_access; + + ---------------- + -- Parameters -- + ---------------- + + -- Who is the sender ? + expected_sender : ewok.ipc.t_extended_task_id + with address => to_address (params(1)); + + -- Listening to any id ? + listen_any : boolean; + + -- Listening to a specific id ? + id_sender : ewok.tasks_shared.t_task_id; + + + -- Buffer size + size : unsigned_8 + with address => to_address (params(2)); + + -- Input buffer + buf : c_buffer (1 .. unsigned_32 (size)) + with address => to_address (params(3)); + + begin + +-- declare +-- u : unsigned_8 +-- with address => to_address (params(1)); +-- begin +-- debug.log (debug.WARNING, "debug: ipc_do_recv(): task" +-- & ewok.tasks_shared.t_task_id'image (caller_id) +-- & " <- task" +-- & unsigned_8'image (u)); +-- end; + + -------------------------- + -- Verifying parameters -- + -------------------------- + + if mode /= TASK_MODE_MAINTHREAD then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): making IPCs while in ISR mode is not allowed!"); +#end if; + goto ret_denied; + end if; + + if not expected_sender'valid then + debug.panic ("[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): invalid id_sender (" + & unsigned_32'image (params(1)) & ")"); + end if; + + -- Task initialization is complete ? + if not is_init_done (caller_id) then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): initialization not completed"); +#end if; + goto ret_denied; + end if; + + -- Does &size is in the caller address space ? + if not ewok.sanitize.is_word_in_data_slot + (to_system_address (size'address), caller_id, mode) + then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): size (" & unsigned_8'image (size) + & ") is not in caller space"); +#end if; + goto ret_inval; + end if; + + -- Does &expected_sender is in the caller address space ? + if not ewok.sanitize.is_word_in_data_slot + (to_system_address (expected_sender'address), caller_id, mode) + then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): expected_sender (" + & ewok.ipc.t_extended_task_id'image (expected_sender) + & ") is not in caller space"); +#end if; + goto ret_inval; + end if; + + -- Does &buf is in the caller address space ? + if not ewok.sanitize.is_range_in_data_slot + (to_system_address (buf'address), unsigned_32 (size), caller_id, mode) + then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): buffer (" + & system_address'image (to_system_address (buf'address)) + & ") is not in caller space"); +#end if; + goto ret_inval; + end if; + + -- Verifying that the sender is a user application + if expected_sender = ewok.ipc.ANY_APP then + listen_any := true; + else + id_sender := ewok.ipc.to_task_id (expected_sender); + listen_any := false; + end if; + + if not listen_any and then not ewok.tasks.is_user (id_sender) + then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): invalid id_sender (" + & ewok.tasks_shared.t_task_id'image (id_sender) + & ")"); +#end if; + goto ret_inval; + end if; + + if not listen_any then + sender_a := ewok.tasks.get_task (id_sender); + if sender_a = NULL or else + ewok.tasks.get_state(sender_a.all.id, + TASK_MODE_MAINTHREAD) = TASK_STATE_EMPTY + then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): invalid id_sender (" + & ewok.tasks_shared.t_task_id'image (id_sender) + & ") - empty task"); +#end if; + goto ret_inval; + end if; + end if; + + -- A task can't send a message to itself + if not listen_any and then caller_id = id_sender + then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): id_sender (" + & ewok.tasks_shared.t_task_id'image (id_sender) + & ") - same as caller->id"); +#end if; + goto ret_inval; + end if; + + -- + -- Verifying permissions + -- + + if not listen_any then + +#if CONFIG_KERNEL_DOMAIN + if not ewok.perm.is_same_domain (id_sender, caller_id) then + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): sender's (" + & ewok.tasks_shared.t_task_id'image (id_sender) + & ") domain not granted"); + goto ret_denied; + end if; +#end if; + + if not ewok.perm.ipc_is_granted (id_sender, caller_id) then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): not granted to listen task " + & ewok.tasks_shared.t_task_id'image (id_sender)); +#end if; + goto ret_denied; + end if; + + end if; + + ------------------------------ + -- Defining an IPC EndPoint -- + ------------------------------ + + ep := NULL; + + -- Special case: listening to ANY_APP and already have a pending message + if listen_any then + + for i in ewok.tasks.tasks_list(caller_id).ipc_endpoints'range loop + if ewok.tasks.tasks_list(caller_id).ipc_endpoints(i) /= NULL + and then + ewok.tasks.tasks_list(caller_id).ipc_endpoints(i).state = ewok.ipc.WAIT_FOR_RECEIVER + and then + ewok.ipc.to_task_id (ewok.tasks.tasks_list(caller_id).ipc_endpoints(i).to) = + caller_id + then + ep := ewok.tasks.tasks_list(caller_id).ipc_endpoints(i); + exit; + end if; + end loop; + + -- Special case: listening to a given sender and already have a pending + -- message + else + + if ewok.tasks.tasks_list(caller_id).ipc_endpoints(id_sender) /= NULL + and then + ewok.tasks.tasks_list(caller_id).ipc_endpoints(id_sender).state + = ewok.ipc.WAIT_FOR_RECEIVER + and then + ewok.ipc.to_task_id (ewok.tasks.tasks_list(caller_id).ipc_endpoints(id_sender).to) + = caller_id + then + ep := ewok.tasks.tasks_list(caller_id).ipc_endpoints(id_sender); + end if; + + end if; + + ------------------------- + -- Reading the message -- + ------------------------- + + -- + -- No pending message to read: we terminate here + -- + + if ep = NULL then + + -- Waking up idle senders + if not listen_any and then + ewok.tasks.get_state(sender_a.all.id, + TASK_MODE_MAINTHREAD) = TASK_STATE_IDLE + then + ewok.tasks.set_state(sender_a.all.id, + TASK_MODE_MAINTHREAD, + TASK_STATE_RUNNABLE); + end if; + + -- Receiver is blocking until it receives a message or it returns + -- E_SYS_BUSY + if blocking then + ewok.tasks.set_state(caller_id, + TASK_MODE_MAINTHREAD, + TASK_STATE_IPC_RECV_BLOCKED); + return; + else + goto ret_busy; + end if; + + end if; + + -- + -- A message was sent. First, we verify that the caller is granted to + -- read a message sent by the sender in the specific case of a recv(ANY) + -- + + if listen_any and then + not ewok.perm.ipc_is_granted + (ewok.ipc.to_task_id (ep.all.from), caller_id) + then + +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): sender " + & ewok.ipc.t_extended_task_id'image (ep.all.from) + & " not granted"); +#end if; + + set_return_value + (sender_a.all.id, TASK_MODE_MAINTHREAD, SYS_E_DENIED); + ewok.tasks.set_state + (sender_a.all.id, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + + -- Receiver is blocking until it receives a message or it returns + -- E_SYS_BUSY + if blocking then + ewok.tasks.set_state(caller_id, + TASK_MODE_MAINTHREAD, + TASK_STATE_IPC_RECV_BLOCKED); + return; + else + goto ret_busy; + end if; + + end if; + + -- The syscall returns the sender ID + expected_sender := ep.all.from; + id_sender := ewok.ipc.to_task_id (ep.all.from); + + sender_a := ewok.tasks.get_task (id_sender); + + if sender_a = NULL or else + ewok.tasks.get_state(sender_a.all.id, TASK_MODE_MAINTHREAD) = TASK_STATE_EMPTY + + then + debug.panic ("[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_recv(): invalid sender (" + & ewok.tasks_shared.t_task_id'image (id_sender) + & ") - empty task"); + end if; + + -- Copying the message in the receiver's buffer + if ep.all.size > size then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "ipc_do_recv(): IPC message overflows: receiver's (" + & ewok.tasks_shared.t_task_id'image (caller_id) + & ") buffer is too small (" + & unsigned_8'image (ep.all.size) & ">" + & unsigned_8'image (size) & ")"); +#end if; + goto ret_inval; + end if; + + -- Returning the data size + size := ep.all.size; + + -- Copying data + -- Note: we don't use 'first attribute. By convention, array indexes + -- begin with '1' value + buf(1 .. unsigned_32 (size)) := ep.all.data(1 .. unsigned_32 (size)); + + -- The EndPoint is ready for another use + ep.all.state := ewok.ipc.READY; + ep.all.size := 0; + + -- Free sender from it's blocking state + case ewok.tasks.get_state(sender_a.all.id, TASK_MODE_MAINTHREAD) is + + when TASK_STATE_IPC_WAIT_ACK => + set_return_value + (sender_a.all.id, TASK_MODE_MAINTHREAD, SYS_E_DONE); + ewok.tasks.set_state + (sender_a.all.id, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + + when TASK_STATE_IPC_SEND_BLOCKED => + --m4.cpu.disable_irq; + sender_a.all.state := TASK_STATE_SVC_BLOCKED; + ewok.softirq.push_syscall (sender_a.all.id); + ewok.tasks.set_state (ewok.tasks_shared.ID_SOFTIRQ, + TASK_MODE_MAINTHREAD, + TASK_STATE_RUNNABLE); + --m4.cpu.enable_irq; + when others => + null; + end case; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_BUSY); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end ipc_do_recv; + + + procedure ipc_do_send + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + blocking : in boolean; + mode : in ewok.tasks_shared.t_task_mode) + is + + ep : ewok.ipc.t_endpoint_access; + receiver_a : ewok.tasks.t_task_access; + ok : boolean; + + ---------------- + -- Parameters -- + ---------------- + + -- Who is the receiver ? + id_receiver : ewok.tasks_shared.t_task_id + with address => params(1)'address; + + -- Buffer size + size : unsigned_8 + with address => params(2)'address; + + -- Output buffer + buf : c_buffer (1 .. unsigned_32 (size)) + with address => to_address (params(3)); + + begin + +-- debug.log (debug.WARNING, "debug: ipc_do_send(): task" +-- & ewok.tasks_shared.t_task_id'image (caller_id) +-- & " -> task" & unsigned_32'image (params(1))); + + -------------------------- + -- Verifying parameters -- + -------------------------- + + if mode /= TASK_MODE_MAINTHREAD then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_send(): making IPCs while in ISR mode is not allowed!"); +#end if; + goto ret_denied; + end if; + + if not id_receiver'valid then + debug.panic ("[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_send(): invalid id_receiver (" + & unsigned_32'image (params(1)) & ")"); + end if; + + -- Task initialization is complete ? + if not is_init_done (caller_id) then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_send(): initialization not completed"); +#end if; + goto ret_denied; + end if; + + -- Does &buf is in the caller address space ? + if not ewok.sanitize.is_range_in_data_slot + (to_unsigned_32 (buf'address), unsigned_32 (size), caller_id, mode) + then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_send(): buffer (" + & system_address'image (to_system_address (buf'address)) + & ") is not in caller space"); +#end if; + goto ret_inval; + end if; + + -- Verifying that the receiver id corresponds to a user application + if not ewok.tasks.is_user (id_receiver) then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_send(): task " + & unsigned_32'image (params(1)) + & " is not a user task"); +#end if; + goto ret_inval; + end if; + + receiver_a := ewok.tasks.get_task (id_receiver); + + -- Verifying that the receiver is valid + if receiver_a = NULL or else + ewok.tasks.get_state + (receiver_a.all.id, TASK_MODE_MAINTHREAD) = TASK_STATE_EMPTY + then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_send(): invalid id_receiver (" + & ewok.tasks_shared.t_task_id'image (id_receiver) + & ") - empty task"); +#end if; + goto ret_inval; + end if; + + -- A task can't send a message to itself + if caller_id = id_receiver then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_send(): invalid id_receiver (" + & ewok.tasks_shared.t_task_id'image (id_receiver) + & ") - same as caller->id"); +#end if; + goto ret_inval; + end if; + + -- Is size valid ? + if size > ewok.ipc.MAX_IPC_MSG_SIZE then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] invalid size (" & unsigned_8'image (size) & ")"); +#end if; + goto ret_inval; + end if; + + -- + -- Verifying permissions + -- + +#if CONFIG_KERNEL_DOMAIN + if not ewok.perm.is_same_domain (id_receiver, caller_id) then + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_send(): receiver's (" + & ewok.tasks_shared.t_task_id'image (id_receiver) + & ") domain not granted"); + goto ret_denied; + end if; +#end if; + + if not ewok.perm.ipc_is_granted (id_receiver, caller_id) then +#if CONFIG_DEBUG_ADA_IPC + debug.log (debug.WARNING, "[task" + & ewok.tasks_shared.t_task_id'image (caller_id) + & "] ipc_do_send(): receiver " + & ewok.tasks_shared.t_task_id'image (id_receiver) + & " not granted"); +#end if; + goto ret_denied; + end if; + + ------------------------------ + -- Defining an IPC EndPoint -- + ------------------------------ + + ep := NULL; + + -- Creating a new EndPoint between the sender and the receiver + if ewok.tasks.tasks_list(caller_id).ipc_endpoints(id_receiver) = NULL + then + + if receiver_a.all.ipc_endpoints(caller_id) /= NULL then + debug.panic ("ipc_do_send(): EndPoint already defined by the receiver"); + end if; + + ewok.ipc.get_endpoint (ep, ok); + if not ok then + debug.panic ("ipc_do_send(): EndPoint starvation !O_+"); + end if; + + ewok.tasks.tasks_list(caller_id).ipc_endpoints(id_receiver) := ep; + receiver_a.all.ipc_endpoints(caller_id) := ep; + + else + ep := ewok.tasks.tasks_list(caller_id).ipc_endpoints(id_receiver); + end if; + + ----------------------- + -- Sending a message -- + ----------------------- + + -- Wake up idle receivers + if ewok.sleep.is_sleeping (receiver_a.id) then + ewok.sleep.try_waking_up (receiver_a.id); + elsif receiver_a.all.state = TASK_STATE_IDLE then + receiver_a.all.state := TASK_STATE_RUNNABLE; + end if; + + -- The receiver has already a pending message and the endpoint is already + -- in use. + if ep.all.state = ewok.ipc.WAIT_FOR_RECEIVER and + ewok.ipc.to_task_id (ep.all.to) = receiver_a.all.id + then + if blocking then + ewok.tasks.set_state + (receiver_a.all.id, TASK_MODE_MAINTHREAD, TASK_STATE_IPC_SEND_BLOCKED); +#if CONFIG_IPC_SCHED_VIOL + if ewok.tasks.get_state(receiver_a.all.id, TASK_MODE_MAINTHREAD) = TASK_STATE_RUNNABLE or + ewok.tasks.get_tate(receiver_a.all.id, TASK_MODE_MAINTHREAD) = TASK_STATE_IDLE + then + ewok.tasks.set_state + (receiver_a.all.id, TASK_MODE_MAINTHREAD, TASK_STATE_FORCED); + end if; +#end if; + return; + else + goto ret_busy; + end if; + end if; + + if ep.all.state /= ewok.ipc.READY then + debug.panic ("ipc_do_send(): invalid endpoint state"); + end if; + + ep.all.from := ewok.ipc.to_ext_task_id (caller_id); + ep.all.to := ewok.ipc.to_ext_task_id (receiver_a.all.id); + + -- We copy the message in the IPC buffer + -- Note: we don't use 'first attribute. By convention, array indexes + -- begin with '1' value + ep.all.size := size; + ep.all.data(1 .. unsigned_32 (size)) := buf(1 .. unsigned_32 (size)); + + -- Adjusting the EndPoint state + ep.all.state := ewok.ipc.WAIT_FOR_RECEIVER; + + -- If the receiver was blocking, it can be 'freed' from its blocking + -- state. We reinject it so that it can fulfill its syscall + if ewok.tasks.get_state(receiver_a.all.id, TASK_MODE_MAINTHREAD) = TASK_STATE_IPC_RECV_BLOCKED + then + --m4.cpu.disable_irq; + receiver_a.all.state := TASK_STATE_SVC_BLOCKED; + ewok.softirq.push_syscall (receiver_a.all.id); + ewok.tasks.set_state (ID_SOFTIRQ, + TASK_MODE_MAINTHREAD, + TASK_STATE_RUNNABLE); + --m4.cpu.enable_irq; + end if; + + if blocking then + ewok.tasks.tasks_list(caller_id).state := TASK_STATE_IPC_WAIT_ACK; +#if CONFIG_IPC_SCHED_VIOL + if receiver_a.all.state = TASK_STATE_RUNNABLE or + receiver_a.all.state = TASK_STATE_IDLE + then + receiver_a.all.state := TASK_STATE_FORCED; + end if; +#end if; + return; + else + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end if; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_BUSY); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + end ipc_do_send; + + + procedure ipc_do_log + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + -- Message size + size : positive + with address => params(2)'address; + -- Message + msg : string (1 .. size) + with address => to_address (params(3)); + begin + + if not ewok.sanitize.is_word_in_data_slot + (to_system_address (msg'address), + caller_id, + mode) + then + goto ret_inval; + end if; + + if size >= 512 then + goto ret_inval; + end if; + + debug.log (ewok.tasks.tasks_list(caller_id).name & " " & msg, false); + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + end ipc_do_log; + + + procedure sys_ipc + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + syscall : t_syscalls_ipc + with address => params(0)'address; + begin + + if not syscall'valid then + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end if; + + case syscall is + when IPC_LOG => + ipc_do_log (caller_id, params, mode); + when IPC_RECV_SYNC => + ipc_do_recv (caller_id, params, true, mode); + when IPC_SEND_SYNC => + ipc_do_send (caller_id, params, true, mode); + when IPC_RECV_ASYNC => + ipc_do_recv (caller_id, params, false, mode); + when IPC_SEND_ASYNC => + ipc_do_send (caller_id, params, false, mode); + end case; + + end sys_ipc; + + +end ewok.syscalls.ipc; diff --git a/Ada/syscalls/ewok-syscalls-ipc.ads b/Ada/syscalls/ewok-syscalls-ipc.ads new file mode 100644 index 0000000..f0318d3 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-ipc.ads @@ -0,0 +1,53 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok.tasks_shared; + + +package ewok.syscalls.ipc + with spark_mode => off +is + + procedure ipc_do_recv + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + blocking : in boolean; + mode : in ewok.tasks_shared.t_task_mode); + + procedure ipc_do_send + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + blocking : in boolean; + mode : in ewok.tasks_shared.t_task_mode); + + procedure ipc_do_log + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + + procedure sys_ipc + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + +end ewok.syscalls.ipc; diff --git a/Ada/syscalls/ewok-syscalls-lock.adb b/Ada/syscalls/ewok-syscalls-lock.adb new file mode 100644 index 0000000..3ddc282 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-lock.adb @@ -0,0 +1,61 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; + + +package body ewok.syscalls.lock + with spark_mode => off +is + + procedure sys_lock + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + syscall : t_syscalls_lock + with address => params(0)'address; + begin + + if mode = TASK_MODE_ISRTHREAD then + set_return_value (caller_id, mode, SYS_E_DENIED); + return; + end if; + + if not syscall'valid then + set_return_value (caller_id, mode, SYS_E_INVAL); + return; + end if; + + case syscall is + when LOCK_ENTER => + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_LOCKED); + + when LOCK_EXIT => + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + end case; + end sys_lock; + +end ewok.syscalls.lock; diff --git a/Ada/syscalls/ewok-syscalls-lock.ads b/Ada/syscalls/ewok-syscalls-lock.ads new file mode 100644 index 0000000..34db785 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-lock.ads @@ -0,0 +1,37 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; +with ewok.tasks_shared; + +package ewok.syscalls.lock + with spark_mode => off +is + + procedure sys_lock + (caller_id : in ewok.tasks_shared.t_task_id; + params : in t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + with + global => (output => ewok.tasks.tasks_list); + +end ewok.syscalls.lock; diff --git a/Ada/syscalls/ewok-syscalls-reset.adb b/Ada/syscalls/ewok-syscalls-reset.adb new file mode 100644 index 0000000..51e0290 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-reset.adb @@ -0,0 +1,52 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.perm; use ewok.perm; +with debug; +with m4.scb; + +package body ewok.syscalls.reset + with spark_mode => off +is + + procedure sys_reset + (caller_id : in ewok.tasks_shared.t_task_id; + mode : in ewok.tasks_shared.t_task_mode) + is + begin + + if not ewok.perm.ressource_is_granted (PERM_RES_TSK_RESET, caller_id) + then + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end if; + + m4.scb.reset; + + debug.panic ("soc.nvic.reset failed !?!"); + + end sys_reset; + +end ewok.syscalls.reset; diff --git a/Ada/syscalls/ewok-syscalls-reset.ads b/Ada/syscalls/ewok-syscalls-reset.ads new file mode 100644 index 0000000..98db75a --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-reset.ads @@ -0,0 +1,33 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; + +package ewok.syscalls.reset + with spark_mode => off +is + + procedure sys_reset + (caller_id : in ewok.tasks_shared.t_task_id; + mode : in ewok.tasks_shared.t_task_mode); + +end ewok.syscalls.reset; diff --git a/Ada/syscalls/ewok-syscalls-sleep.adb b/Ada/syscalls/ewok-syscalls-sleep.adb new file mode 100644 index 0000000..39edfc5 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-sleep.adb @@ -0,0 +1,73 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks; use ewok.tasks; +with ewok.tasks_shared; use ewok.tasks_shared; +with ewok.sched; +with ewok.sleep; +with ewok.exported.sleep; use ewok.exported.sleep; + +package body ewok.syscalls.sleep + with spark_mode => off +is + + procedure sys_sleep + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode) + is + sleep_time : unsigned_32 + with address => params(0)'address; + + sleep_mode : t_sleep_mode + with address => params(1)'address; + begin + + if mode = TASK_MODE_ISRTHREAD then + goto ret_denied; + end if; + + if not sleep_mode'valid then + goto ret_inval; + end if; + + ewok.sleep.sleeping (caller_id, milliseconds (sleep_time), sleep_mode); + + -- Ok return + set_return_value (caller_id, mode, SYS_E_DONE); + -- Note: sleeping state set by ewok.sleep.sleeping procedure + ewok.sched.request_schedule; + return; + + <> + set_return_value (caller_id, mode, SYS_E_INVAL); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + + <> + set_return_value (caller_id, mode, SYS_E_DENIED); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_RUNNABLE); + return; + end sys_sleep; + +end ewok.syscalls.sleep; + diff --git a/Ada/syscalls/ewok-syscalls-sleep.ads b/Ada/syscalls/ewok-syscalls-sleep.ads new file mode 100644 index 0000000..cc847c2 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-sleep.ads @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ewok.tasks_shared; + +package ewok.syscalls.sleep + with spark_mode => off +is + + procedure sys_sleep + (caller_id : in ewok.tasks_shared.t_task_id; + params : in out t_parameters; + mode : in ewok.tasks_shared.t_task_mode); + +end ewok.syscalls.sleep; diff --git a/Ada/syscalls/ewok-syscalls-yield.adb b/Ada/syscalls/ewok-syscalls-yield.adb new file mode 100644 index 0000000..0bf01e9 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-yield.adb @@ -0,0 +1,49 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok.tasks; use ewok.tasks; +with ewok.sched; + +package body ewok.syscalls.yield + with spark_mode => off +is + + procedure sys_yield + (caller_id : in ewok.tasks_shared.t_task_id; + mode : in ewok.tasks_shared.t_task_mode) + is + begin + + if mode = TASK_MODE_ISRTHREAD then + set_return_value (caller_id, mode, SYS_E_DENIED); + return; + end if; + + set_return_value (caller_id, mode, SYS_E_DONE); + ewok.tasks.set_state (caller_id, mode, TASK_STATE_IDLE); + ewok.sched.request_schedule; + return; + + end sys_yield; + +end ewok.syscalls.yield; diff --git a/Ada/syscalls/ewok-syscalls-yield.ads b/Ada/syscalls/ewok-syscalls-yield.ads new file mode 100644 index 0000000..1e8e475 --- /dev/null +++ b/Ada/syscalls/ewok-syscalls-yield.ads @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with ewok.tasks_shared; use ewok.tasks_shared; + +package ewok.syscalls.yield + with spark_mode => off +is + + procedure sys_yield + (caller_id : in ewok.tasks_shared.t_task_id; + mode : in ewok.tasks_shared.t_task_mode); + +end ewok.syscalls.yield; diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000..540a2d5 --- /dev/null +++ b/Kconfig @@ -0,0 +1,265 @@ +menu "Board Support Package" + +source "kernel/arch/Kconfig" + +endmenu + +config ADAKERNEL + bool "Ada & SPARK kernel implementation" + default n + ---help--- + This option activate the usage of Ada and Spark sources in + replacement of C code for the kernel runtime. This permits + to compile an hardened kernel based on the efficient properties + of the Ada language, mixed with residual C code for libbsp. + +choice + prompt "kernel console USART identifier" + default KERNEL_CONSOLE_USART1 + config KERNEL_CONSOLE_USART1 + bool "kernel uses USART1 for its console" + ---help--- + in Discovery board, BP6/PB7 pins are linked to UART1, if + using motherboard DM-STF4BB, the RS232 connector is linked + to USART6. + config KERNEL_CONSOLE_USART6 + bool "kernel uses USART6 for its console" + ---help--- + in Discovery board, BP6/PB7 pins are linked to UART1, if + using motherboard DM-STF4BB, the RS232 connector is linked + to USART6. +endchoice + +config KERNEL_USART + int + default 1 if KERNEL_CONSOLE_USART1 + default 6 if KERNEL_CONSOLE_USART6 + +config KERNEL_CONSOLE_TXT + bool "Allowing user input text echo on kernel console" + default y + ---help--- + If Y, input chars on the kernel console will be echoed. There + is no specific behavior behind this (no protocol, shell or others), + only a character echo in the ISR. + +config KERNEL_DMA_ENABLE + bool "Enable secure DMA kernel support" + default y + ---help--- + This permits to allow tasks to declare DMA stream usage with + kernel control for address and channel management. If you + say n here, any DMA declaration will return SYS_E_DENIED. + +config KERNEL_GETCYCLES + bool "Kernel support for DWT-based getcycles()" + default y + depends on STM32F4 + select DWT + ---help--- + Add support for sys_getcycles() syscall, which returns a value + in cycles instead of ticks, which is more precise. + +config KERNEL_DOMAIN + bool "Kernel support tasks domains" + default n + ---help--- + If yes, it is possible to set a specific domain for each task (based on + a uint8_t value). Task from a same domain can communicate, tasks from + different domains cannot (no IPC, no shared DMA spaces, get_taskid return + SYS_E_INVAL, etc.). Each task can declare its domain as 'APP_APPNAME_DOMAIN' + in the Kconfig system. If no domain is specific, the task is member of the + default domain 0. Kernel domains has no impact on the scheduling scheme. + +if KERNEL_EXPERT_MODE + +choice + prompt "Syscall execution time and postponing" + default KERNEL_SYSCALLS_WISE_REPARTITION +config KERNEL_SYSCALLS_IN_IRQ + bool "Support for syscalls in handler mode" + ---help--- + Syscalls are executed immediatly instead of being postponed to softirq + making the task locked for some time. They are faster and less costly + but take more time in IRQ mode with IRQ disabled. +config KERNEL_SYSCALLS_WISE_REPARTITION + bool "Support for fast syscalls in handler mode, slow syscalls in softirq" + ---help--- + Syscall requiring reactivity and having a small cost, such as get_cycles(), + are executed in handler mode. All other syscalls are postponed to softirq + thread. This is a reasonable middle choice to ally performance and reactivity. +config KERNEL_SYSCALLS_IN_SOFTIRQ + bool "Support for syscalls in softirq mode" + ---help--- + All syscalls are postponed to softirq thread. User main thread are locked + on syscall return while the syscall is being executed by softirq thread. + This highly reduce CPU time with IRQ disabled but make syscalls being + executed with potential big latency. +endchoice + +endif + +menu "Scheduling schemes" + +choice + prompt "Scheduler behavior" + config SCHED_RR + bool "Round Robin scheduler" + ---help--- + This is a classical Round Robin scheduler. ISR are still + executed with a higher priority than the tasks. + config SCHED_MLQ_RR + bool "Multilevel Queue Round Robin" + ---help--- + This is a basic, multilevel queues scheduling scheme with Round + Robin scheduling for each queue. As priority as fixed, + higher priority tasks *must* yield to let other task's main + thread being executed. + It is efficient for burst-based, high period and high priority + tasks such as smartcard management. + config SCHED_RAND + bool "Random scheduler" + ---help--- + Randomly choose a task in the task list at each schedule + time, using the HW Random number generator. +endchoice + +config SCHED_PERIOD + int "Scheduler period (in milliseconds)" + default 10 + ---help--- + Set the scheduling period duration. Beware, this value has a huge + impact on the overall system behavior. + +if !SCHED_MLQ_RR +# FISR violate the MLQ_RR priority management. FISR is efficient for +# Round-Robbin management for sporadic high reactivity constraints +# When using MLQ_RR, please use priority-based configuration to +# manage reactivity of tasks and ISRs + +config SCHED_SUPPORT_FISR + bool "ISR may force immediate one time main thread execution (perm based)" + default y + ---help--- + If y, the kernel support the TSK_FISR permission and associated + behavior. This permit to tasks with this permission to force one single + immediate schedule of its main thread just after a given ISR which + as been configured with the flag IRQ_ISR_FORCE_MAINTHREAD. + This execution slot can still be preempted by a physical IRQ or another + ISR scheduling. + +endif + +config SCHED_SUPPORT_FIPC + bool "IPC send may force immediate one time target task execution (perm based)" + default n + ---help--- + If y, the kernel support the TSK_FIPC permission and associated behavior. + This permit to a task sending an IPC with reactivity constraint to force + one signe immediate schedule of the target task, if this task is waiting for + this IPC only. This highly reduce IPC latency but is still a scheduling violation. + This execution slot can still be preempted by a physical IRQ or another + ISR scheduling. + +if KERNEL_EXPERT_MODE + +config ISR_REACTIVITY + bool "Optimize for ISR reactivity" + default y + ---help--- + If you say y here, the softirq will force its own scheduling when + an ISR is waiting for schedule, even if there is also syscalls to + execute. ISR are executed faster, but there is more scheduling of + softirq in comparison with standard task's main threads. + +endif + +endmenu + +choice + prompt "Kernel specific optimization flags" + default KERN_OPTIM_NONE + config KERN_OPTIM_NONE + bool "Same optimization as the other parts (see Kernel hacking)" + config KERN_OPTIM_O1 + bool "Optimization with -O1, debug keeped" + config KERN_OPTIM_O2 + bool "Optimization with -O2, debug keeped" + config KERN_OPTIM_O3 + bool "Optimization with -O3, debug keeped" + config KERN_OPTIM_OS + bool "Optimization for size, debug keeped" +endchoice + +config KERN_CFLAGS + string + default "-O1" if KERN_OPTIM_O1 + default "-O2" if KERN_OPTIM_O2 + default "-O3" if KERN_OPTIM_O3 + default "-Os" if KERN_OPTIM_OS + default "" if KERN_OPTIM_NONE + + +menu "Kernel hacking" + +config DBGLEVEL + int "Set debug level" + default 3 + help + Set the debug level for pretty printing at runtime. This respects + the syslog levels standard: + 0: EMERG + 1: ALERT + 2: CRITICAL + 3: ERROR + 4: WARNING + 5: NOTICE + 6: INFORMATIONAL + 7: DEBUG + All debug levels less or equal to the chosen level will be printed. + +config DEBUG + bool "Set debug compile flags" + default n + help + if set, the project will be compiled using debug flags and without + compile-time optimization. + +config KERNEL_SCHED_DEBUG + bool "Activate scheduler debugging" + default n + help + If set, the scheduler will store in a ring buffer all thread execution + using the following structure: + [ id | timestamp (us) | mode (ISR,MR) ] + The ringbuffer is never printed-out to avoid any time overhead. Yet it + can be dumped by gdb at anytime + +if KERNEL_SCHED_DEBUG + +config KERNEL_SCHED_DEBUG_BUFSIZE + int "Scheduling buffer size" + default 1000 + help + Set the ring buffer base address. Beware, you must set a writeable address + in RAM where no content is being stored) + + + +endif + +config KERNEL_EXPERT_MODE + bool "Configure EwoK in expert mode" + default n + ---help--- + Make complex options visible. Beware when modifying + these options. They may have a great impact on the + kernel behavior and make the overall system unstable!!! + + + +endmenu + +config KERNEL_EWOK + bool + default y diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6cd8284 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 The Wookey project team + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a111d58 --- /dev/null +++ b/Makefile @@ -0,0 +1,205 @@ +APP_NAME ?= kernel +DIR_NAME = kernel + +PROJ_FILES = ../ +BIN_NAME = $(APP_NAME).bin +HEX_NAME = $(APP_NAME).hex +ELF_NAME = $(APP_NAME).elf + + +IMAGE_TYPE = IMAGE_TYPE0 +VERSION = 1 +############################# + +-include $(PROJ_FILES)/Makefile.conf +-include $(PROJ_FILES)/Makefile.gen + +# use an app-specific build dir +APP_BUILD_DIR = $(BUILD_DIR)/$(DIR_NAME) + +CFLAGS += $(EXTRA_CFLAGS) +CFLAGS += $(DEBUG_CFLAGS) -Wconversion +CFLAGS += -I. -Isyscalls -Igenerated -I$(CORE_DIR) -Iarch +CFLAGS += -MMD -MP +CFLAGS += $(KERN_CFLAGS) + +CLANG_CFLAGS := -I. -Isyscalls -Igenerated -I$(CORE_DIR) -Iarch -Iarch/core/$(CONFIG_ARCH) -Iarch/socs/$(CONFIG_SOCNAME) -Iarch/boards/$(CONFIG_BOARDNAME) -Iarch/boards + +# if no specific ldscript is specified, using default one, if the SDK want to relink successively with +# varous ldscripts, this variable has to be passed to the Makefile commandline +EXTRA_LDFLAGS ?= -Tkernel.ld + +LDFLAGS += $(EXTRA_LDFLAGS) -L$(APP_BUILD_DIR) $(AFLAGS) -fno-builtin -nostdlib -nostartfiles -Xlinker + +# --unresolved-symbols=ignore-in-object-files +LD_LIBS += -lbsp -L$(BUILD_DIR)/kernel/libbsp + +ifeq ($(CONFIG_ADAKERNEL),y) +LD_LIBS = -lkernel -L$(APP_BUILD_DIR)/Ada/lib +LD_LIBS += -lbsp -L$(BUILD_DIR)/kernel/libbsp +LD_LIBS += -labsp -L$(BUILD_DIR)/kernel/libbsp/Ada/lib +LD_LIBS += -lgnat -L$(BUILD_DIR)/kernel/libgnat +endif + +BUILD_DIR ?= $(PROJ_FILE)build + +SRC = $(wildcard *.c) $(wildcard syscalls/*.c) +OBJ := $(patsubst %.c,$(APP_BUILD_DIR)/%.o,$(SRC)) + +ifeq ($(CONFIG_ADAKERNEL),y) +#ada sources files +# all files in Ada dir will replace C equivalent +ASRC_DIR = Ada +ASRC = $(wildcard $(ASRC_DIR)/*.adb) $(wildcard $(ASRC_DIR)/syscalls/*.adb) +ALIB = $(APP_BUILD_DIR)/Ada/lib/libkernel.a +ADIR = $(APP_BUILD_DIR)/Ada/lib + +# deleting C files having their Ada equivalent from the C/obj list +ADACEQ = $(patsubst Ada/ewok-%.adb,%.c,$(ASRC)) +ADACEQ += $(patsubst Ada/syscalls/ewok-%.adb,syscalls/%.c,$(ASRC)) +SRC_TMP = $(filter-out $(ADACEQ),$(SRC)) +SRC := $(SRC_TMP) +OBJ := $(patsubst %.c,$(APP_BUILD_DIR)/%.o,$(SRC)) + +endif + +#Rust sources files +RSSRC_DIR= rust/src +RSRC= $(wildcard $(RSRCDIR)/*.rs) +ROBJ = $(patsubst %.rs,$(APP_BUILD_DIR)/%.o,$(RSRC)) + +SOC_DIR := $(PROJ_FILES)/kernel/arch/socs/$(SOC)/ +SOC_SRC := startup_$(SOC).s +SOC_OBJ := $(patsubst %.s,$(APP_BUILD_DIR)/%.o,$(SOC_SRC)) + +CORE_DIR := $(PROJ_FILES)/kernel/arch/cores/$(ARCH)/ +CORE_SRC := $(core-kernel-y) +CORE_OBJ := $(patsubst %.c,$(APP_BUILD_DIR)/core/%.o,$(CORE_SRC)) + +#test sources files +TESTSSRC_DIR = tests +TESTSSRC = tests.c tests_cryp.c tests_dma.c tests_queue.c tests_sd.c tests_systick.c +TESTSOBJ = $(patsubst %.c,$(APP_BUILD_DIR)/%.o,$(TESTSSRC)) +TESTSDEP = $(TESTSSOBJ:.o=.d) + +OUT_DIRS = $(dir $(KERNEL_OBJ)) $(dir $(AALI)) $(dir $(ROBJ)) $(dir $(ALIB)) + +LDSCRIPT_NAME = $(APP_BUILD_DIR)/$(APP_NAME).ld + +# file to (dist)clean +# objects and compilation related +TODEL_CLEAN += $(OBJ) $(ALDIR) $(ALIB) $(ROBJ) $(DEP) $(TESTSDEP) $(LDSCRIPT_NAME) +# targets +TODEL_DISTCLEAN += $(APP_BUILD_DIR) + +.PHONY: kernel __clean __distclean + +ifeq ($(CONFIG_ADAKERNEL),y) +all: $(APP_BUILD_DIR) libgnat libbsp kernel +else +all: $(APP_BUILD_DIR) libbsp kernel +endif + + +show: + @echo + @echo "\t\tAPP_BUILD_DIR\t=> " $(APP_BUILD_DIR) + @echo + @echo "C sources files:" + @echo "\t\tKERNEL_ASRC\t=> $(ASRC)" + @echo "\t\tKERNEL_SRC\t=> " $(SRC) + @echo "\t\tKERNEL_OBJ\t=> " $(OBJ) + @echo + @echo "\t\tBUILD_DIR\t=> " $(BUILD_DIR) + @echo "\t\tAPP_BUILD_DIR\t=> " $(APP_BUILD_DIR) + @echo + @echo "Rust sources files:" + @echo "\t" $(RSRC) + @echo "\t\t=> " $(ROBJ) + +libbsp: + $(Q)$(MAKE) -C arch clean + $(Q)$(MAKE) -C arch EXTRA_CFLAGS="-DKERNEL" + $(Q)$(MAKE) -C arch EXTRA_CFLAGS="-DLOADER" + +libgnat: + $(Q)$(MAKE) -C Ada/libgnat all + +kernel: $(APP_BUILD_DIR)/$(ELF_NAME) $(APP_BUILD_DIR)/$(HEX_NAME) + +############################################################# +# build targets (driver, core, SoC, Board... and local) +# App C sources files +# kernel C sources files + +ifeq ($(CONFIG_ADAKERNEL),y) +$(ADIR): + $(call cmd,mkdir) + +$(ALIB): $(ADIR) libkernel + +libkernel: libkernel.gpr + $(call cmd,ada_lib) + +endif + +sanitize: $(SRC) + clang -target armv7-m -mfloat-abi=hard -mcpu=cortex-m4 $(CLANG_CFLAGS) --analyze $(SRC) + +$(APP_BUILD_DIR)/%.o: %.c + $(call if_changed,cc_o_c) + +$(APP_BUILD_DIR)/%.o: $(SOC_DIR)/$(SOC_SRC) + $(call if_changed,cc_o_c) + +# Core C sources files +$(APP_BUILD_DIR)/core/%.o: $(CORE_DIR)/%.c + $(call if_changed,cc_o_c) + +# Test sources files +$(APP_BUILD_DIR)/tests/%.o: $(TESTSSRC_DIR)/%.c + $(call if_changed,cc_o_c) + +# RUST FILES +$(ROBJ): $(RSRC) + $(call if_changed,rc_o_rs) + +# LDSCRIPT. All are built in one time +$(LDSCRIPT_NAME): $(OBJ) $(ROBJ) $(SOBJ) $(SOC_OBJ) $(CORE_OBJ) $(ALIB) + $(call if_changed,k_ldscript) + +# ELF +$(APP_BUILD_DIR)/$(ELF_NAME): $(LDSCRIPT_NAME) + $(call if_changed,link_o_target) + +# HEX +$(APP_BUILD_DIR)/$(HEX_NAME): $(APP_BUILD_DIR)/$(ELF_NAME) + $(call if_changed,objcopy_ihex) + +# BIN +$(APP_BUILD_DIR)/$(BIN_NAME): $(APP_BUILD_DIR)/$(ELF_NAME) + $(call if_changed,objcopy_bin) + +$(APP_BUILD_DIR): + $(call cmd,mkdir) + +# TEST TARGETS +tests_suite: CFLAGS += -Itests/ -DTESTS +tests_suite: $(TESTSOBJ) $(ROBJ) $(OBJ) $(SOBJ) $(DRVOBJ) + +tests: clean tests_suite + $(CC) $(LDFLAGS) -o $(APP_NAME).elf $(ROBJ) $(SOBJ) $(OBJ) $(DRVOBJ) $(TESTSOBJ) + $(GDB) -x gdbfile_run $(APP_NAME).elf + +ifeq ($(CONFIG_ADAKERNEL),y) +__clean: libkernel.gpr + $(call cmd,ada_clean) + +__distclean: libkernel.gpr + $(call cmd,ada_distclean) +endif + + +-include $(DEP) +-include $(DRVDEP) +-include $(TESTSDEP) diff --git a/Makefile.objs b/Makefile.objs new file mode 100644 index 0000000..6675de1 --- /dev/null +++ b/Makefile.objs @@ -0,0 +1,16 @@ +KERNEL_DIR := $(PROJ_FILES)/kernel + +CFLAGS += -I$(KERNEL_DIR) + + +#kernel-y := + +#kernel-y += helpers.c +#kernel-y += syscalls.c +#kernel-y += task.c +#kernel-y += debug.c + +# the kernel start point +#kernel-y += init.c + +#kernel-fwx-y += queue.c diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..2b56af7 --- /dev/null +++ b/NOTICE @@ -0,0 +1,13 @@ +EwoK secure embedded micro-kernel +Copyright 2018 The Wookey team project. + +This product includes software developed at the French Network and +Information Security Agency (https://www.ssi.gouv.fr), in the +Hardware & Software architecture security laboratory. + +This sofware has been written by the Wookey team, including: + - Ryad Benadjila + - Arnauld Michelizza + - Mathieu Renard + - Philippe Thierry + - Philippe Trebuchet diff --git a/arch/Ada/config.def b/arch/Ada/config.def new file mode 120000 index 0000000..358d2d7 --- /dev/null +++ b/arch/Ada/config.def @@ -0,0 +1 @@ +../../../kernel/Ada/generated/config.def \ No newline at end of file diff --git a/arch/Ada/types-c.adb b/arch/Ada/types-c.adb new file mode 100644 index 0000000..c717f8c --- /dev/null +++ b/arch/Ada/types-c.adb @@ -0,0 +1,44 @@ + +package body types.c + with SPARK_Mode => Off +is + + function len (s : c_string) return natural + is + len : natural := 0; + begin + for i in s'range loop + exit when s(i) = nul; + len := len + 1; + end loop; + return len; + end len; + + + procedure to_ada + (dst : out string; + src : in c_string) + is + begin + for i in src'range loop + exit when src(i) = nul; + dst(i) := src(i); + end loop; + end to_ada; + + + procedure to_c + (dst : out c_string; + src : in string) + is + len : natural := 0; + begin + for i in src'range loop + dst(i) := src(i); + len := len + 1; + end loop; + dst(len) := nul; + end to_c; + + +end types.c; diff --git a/arch/Ada/types-c.ads b/arch/Ada/types-c.ads new file mode 100644 index 0000000..0f2b209 --- /dev/null +++ b/arch/Ada/types-c.ads @@ -0,0 +1,39 @@ + +package types.c + with SPARK_Mode => Off +is + + type t_retval is (SUCCESS, FAILURE) with size => 8; + for t_retval use (SUCCESS => 0, FAILURE => 1); + + -- + -- C string + -- + + type c_string is array (positive range <>) of aliased character; + for c_string'component_size use character'size; + + -- C_string length (without nul character) + function len (s : c_string) return natural; + + -- String conversion + procedure to_c + (dst : out c_string; src : in string); + + procedure to_ada + (dst : out string; src : in c_string); + + -- + -- C buffer + -- + + subtype c_buffer is byte_array; -- alias + + -- + -- Boolean + -- + + type bool is new boolean with size => 8; + for bool use (true => 1, false => 0); + +end types.c; diff --git a/arch/Ada/types.adb b/arch/Ada/types.adb new file mode 100644 index 0000000..5996fe5 --- /dev/null +++ b/arch/Ada/types.adb @@ -0,0 +1,35 @@ + +package body types + with SPARK_Mode => Off +is + + function to_bit + (u : unsigned_8) return types.bit + is + pragma warnings (off); + function conv is new ada.unchecked_conversion + (unsigned_8, bit); + pragma warnings (on); + begin + if u > 1 then + raise program_error; + end if; + return conv (u); + end to_bit; + + + function to_bit + (u : unsigned_32) return types.bit + is + pragma warnings (off); + function conv is new ada.unchecked_conversion + (unsigned_32, bit); + pragma warnings (on); + begin + if u > 1 then + raise program_error; + end if; + return conv (u); + end to_bit; + +end types; diff --git a/arch/Ada/types.ads b/arch/Ada/types.ads new file mode 100644 index 0000000..c0c4ee4 --- /dev/null +++ b/arch/Ada/types.ads @@ -0,0 +1,105 @@ +-- Here are the general restriction on Ada implementation. +-- Some are automatically added when activated SPARK mode in SPARK modules +-- no RTE double stacking +pragma restrictions (no_secondary_stack); +-- no elaboration code must be required at start +pragma restrictions (no_elaboration_code); +-- ... and no finalization (cleaning of elaboration) +pragma restrictions (no_finalization); +-- no exception should arise +pragma restrictions (no_exception_handlers); +-- no recursion call +pragma restrictions (no_recursion); +-- no wide chars +pragma restrictions (no_wide_characters); + + +with system; +with ada.unchecked_conversion; +with interfaces; use interfaces; + +package types + with SPARK_Mode => On +is + + KBYTE : constant := 2 ** 10; + MBYTE : constant := 2 ** 20; + GBYTE : constant := 2 ** 30; + + subtype byte is unsigned_8; + subtype short is unsigned_16; + subtype word is unsigned_32; + + subtype milliseconds is unsigned_64; + subtype microseconds is unsigned_64; + + subtype system_address is unsigned_32; + + function to_address is new ada.unchecked_conversion + (system_address, system.address); + + function to_system_address is new ada.unchecked_conversion + (system.address, system_address); + + function to_word is new ada.unchecked_conversion + (system.address, word); + + function to_unsigned_32 is new ada.unchecked_conversion + (system.address, unsigned_32); + + -- + -- u8, u16 vers u32 + -- + + pragma warnings (off); + + function to_unsigned_32 is new ada.unchecked_conversion + (unsigned_8, unsigned_32); + + function to_unsigned_32 is new ada.unchecked_conversion + (unsigned_16, unsigned_32); + + pragma warnings (on); + + type byte_array is array (unsigned_32 range <>) of byte; + for byte_array'component_size use byte'size; + + type short_array is array (unsigned_32 range <>) of short; + for short_array'component_size use short'size; + + type word_array is array (unsigned_32 range <>) of word; + for word_array'component_size use word'size; + + type unsigned_8_array is new byte_array; + type unsigned_16_array is new short_array; + type unsigned_32_array is new word_array; + + + nul : constant character := character'First; + + + type bit is mod 2**1 with size => 1; + type bits_2 is mod 2**2 with size => 2; + type bits_3 is mod 2**3 with size => 3; + type bits_4 is mod 2**4 with size => 4; + type bits_5 is mod 2**5 with size => 5; + type bits_6 is mod 2**6 with size => 6; + type bits_7 is mod 2**7 with size => 7; + + type bits_9 is mod 2**9 with size => 9; + type bits_10 is mod 2**10 with size => 10; + + type bits_24 is mod 2**24 with size => 24; + + type bits_27 is mod 2**27 with size => 27; + + type bool is new boolean with size => 1; + for bool use (true => 1, false => 0); + + function to_bit + (u : unsigned_8) return types.bit; + + function to_bit + (u : unsigned_32) return types.bit; + +end types; diff --git a/arch/Ada/unsafe_types.ads b/arch/Ada/unsafe_types.ads new file mode 100644 index 0000000..a73fd85 --- /dev/null +++ b/arch/Ada/unsafe_types.ads @@ -0,0 +1,13 @@ +pragma restrictions (no_secondary_stack); +pragma restrictions (no_elaboration_code); +pragma restrictions (no_finalization); +pragma restrictions (no_exception_handlers); + +-- these types are not SPARK compliant. They should not be used in SPARK code +package unsafe_types + with SPARK_Mode => Off -- access types forbidden in SPARK +is + + type string_access is access all string; + +end unsafe_types; diff --git a/arch/Kconfig b/arch/Kconfig new file mode 100644 index 0000000..62bed10 --- /dev/null +++ b/arch/Kconfig @@ -0,0 +1,181 @@ +# This is the arch-specific / board-specific configuration file. +# This file describes all the configuration menu "Target configuration". +# + +menu "Board setup" + +choice + prompt "Target board" + config DISCO407 + bool "Support for 32F429IDISCOVERY board" + select STACK_PROT_FLAG + select STM32F407 + help + Compile for the Discovery 32F407I board. + No Cryp support, 1MB flash bank. + config DISCO429 + bool "Support for 32F407IDISCOVERY board" + select STACK_PROT_FLAG + select STM32F429 + help + Compile for the Discovery 32F429I board. + Cryp support, 1MB flash bank. + config WOOKEY + bool "Support for WOOKEY board" + select STACK_PROT_FLAG + select STM32F439 + help + Compile for the Disco board. +endchoice + +if WOOKEY +source "kernel/arch/boards/wookey/Kconfig" +endif + +if DISCO407 +source "kernel/arch/boards/32f407discovery/Kconfig" +endif + +if DISCO429 +source "kernel/arch/boards/32f429discovery/Kconfig" +endif + +endmenu + +menu "SoC and Core setup" + +# most of kernel code is generic to multiple SoC familly, such as STM32F4 in this +# case. When there is a specificity (for e.g. flash layout), please use STM32F429 or +# STM32F439 config unit to differenciate +config STM32F4 + bool + default n + +choice + prompt "Target SoC" +config STM32F407 + bool "Support for the STMicro STM32F407 Cortex-M4 based SoC" + select STM32F4_SPI + select ARCH_ARMV7M + select ARCH_CORTEX_M4 + select STM32F4 +config STM32F429 + bool "Support for the STMicro STM32F429 Cortex-M4 based SoC" + select STM32F4_SPI + select ARCH_ARMV7M + select ARCH_CORTEX_M4 + select STM32F4 +config STM32F439 + bool "Support for the STMicro STM32F439 Cortex-M4 based SoC" + select STM32F4_SPI + select ARCH_ARMV7M + select ARCH_CORTEX_M4 + select STM32F4 +endchoice + +config FPU_ENABLE + bool "Enable Hardware Floating point unit (FPU)" + default n + help + Enable the hardware FPU support. Caution: no FPU context save + is supported by now. + +choice + prompt "FPU access rights" + depends on FPU_ENABLE +config FPU_ENABLE_ALL + bool "Allow FPU for all (privilegied and unprivilegied)" + help + Any task can use the hardware floating point unit. +config FPU_ENABLE_PRIVILEGIED + bool "Allow FPU for privilegied only" + help + Only privilegied (i.e. supervisor) task can use hardware + floating point unit. +endchoice + +choice + prompt "FPU context management" + depends on FPU_ENABLE +config FPU_NOSAVE + bool "No context saving support" + help + No context save. FPU must be used only in unpreemptive part of the code. +config FPU_LAZY + bool "Lazy saving (EXPERIMENTAL)" + help + Lazy context save. FPU can be used in preemptive mode but with reduced + register set. +endchoice + + +config CORE_FREQUENCY + int "Target core frequency" + depends on STM32F4 || STM32F2 + default 168000 + help + Specify the Cortex-M core frequency + +endmenu + +# hidden config, selected by others +# This configurations are not visible to user and are automaticaly set at configuration +# time, depending on the choices above. +# all these generates Makefile helper variables + +config ARCH_ARMV7M + bool + default n + +config ARCH_CORTEX_M4 + bool + default n + +config ARCH_CORTEX_M3 + bool + default n + +config ARCH + string + default "armv7-m" if STM32F4 || STM32F2 + +config ADA_ARCH + string + depends on ADAKERNEL + default "arm-eabi" if ARCH_ARMV7M + +config ADA_PROFILE + string + depends on ADAKERNEL + default "zfp-stm32f4" if STM32F4 || STM32F2 + default "zfp-rpi2" if RPI2 + +config BOARDNAME + string + default "wookey" if WOOKEY + default "32f407discovery" if DISCO407 + default "32f429discovery" if DISCO429 + +config SOCNAME + string + default "stm32f429" if STM32F429 + default "stm32f439" if STM32F439 + default "stm32f407" if STM32F407 + +config CORENAME + string + default "cortex-m4" if STM32F4 + default "cortex-m3" if STM32F2 + +# define the max number of task slots +config MAXTASKS + int + default 8 if STM32F4 + default 8 if STM32F2 + +config AFLAGS + string + default "-mlittle-endian -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fPIC -fpie" if STM32F4 + default "-mlittle-endian -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fPIC -fpie" if STM32F2 + + diff --git a/arch/Makefile b/arch/Makefile new file mode 100644 index 0000000..f0e61b5 --- /dev/null +++ b/arch/Makefile @@ -0,0 +1,190 @@ +LIB_NAME ?= libbsp + +PROJ_FILES = ../../ +LIB_FULL_NAME = $(LIB_NAME).a + +VERSION = 1 +############################# + +-include $(PROJ_FILES)/Makefile.conf +-include $(PROJ_FILES)/Makefile.gen + +# use an app-specific build dir +ifeq ($(EXTRA_CFLAGS),-DKERNEL) +APP_BUILD_DIR = $(BUILD_DIR)/kernel/$(LIB_NAME) +else +APP_BUILD_DIR = $(BUILD_DIR)/loader/$(LIB_NAME) +endif + +CFLAGS += $(EXTRA_CFLAGS) +CFLAGS += $(DEBUG_CFLAGS) +CFLAGS += -I. +CFLAGS += -Isocs/$(CONFIG_SOCNAME) +CFLAGS += -Icores/$(CONFIG_ARCH) +CFLAGS += -I.. +CFLAGS += -ffreestanding +CFLAGS += -MMD -MP + +# Needed to optimize libc.c builtins +CFLAGS += -O3 + +LDFLAGS += -fno-builtin -nostdlib -nostartfiles +LD_LIBS += + +ifeq ($(CONFIG_ADAKERNEL),y) +# libabsp is not linked here, but via libkernel (using libkernel.gpr) and directly in the +# ldr Makefile. +# The goal is to link directly libkernel and libbsp (Ada & Ada) to keep type checking and +# Ada to Ada calls validation without passing by C laxism +# LD_LIBS += -labsp -L$(APP_BUILD_DIR)/Ada/lib +endif + +BUILD_DIR ?= $(PROJ_FILES)build + +SRC_DIR = . +SRC = $(wildcard $(SRC_DIR)/*.c) +OBJ = $(patsubst %.c,$(APP_BUILD_DIR)/%.o,$(SRC)) +DEP = $(OBJ:.o=.d) + +CORE_SRC = $(core-bsp-y) +CORE_OBJ := $(patsubst %.c,$(APP_BUILD_DIR)/core/%.o,$(CORE_SRC)) +CORE_DEP := $(CORE_OBJ:.o=.d) + +ifeq ($(CONFIG_ADAKERNEL),y) +# substitute Ada sources to C sources when they exists (Mix Ada/C libbsp) +CORE_ASRC = $(core-ada-bsp-y) + +ADACEQ = $(patsubst Ada/%.adb,%.c,$(core-ada-bsp-y)) +SRC_TMP = $(filter-out $(ADACEQ),$(core-bsp-y)) +CORE_SRC := $(SRC_TMP) +CORE_OBJ := $(patsubst %.c,$(APP_BUILD_DIR)/core/%.o,$(CORE_SRC)) +CORE_DEP := $(CORE_OBJ:.o=.d) +endif + + +SOC_SRC = $(socdrv-bsp-y) +SOC_OBJ := $(patsubst %.c,$(APP_BUILD_DIR)/soc/%.o,$(SOC_SRC)) +SOC_OBJ := $(patsubst %.s,$(APP_BUILD_DIR)/soc/%.o,$(SOC_OBJ)) +SOC_DEP := $(SOC_OBJ:.o=.d) + +ifeq ($(CONFIG_ADAKERNEL),y) +# substitute Ada sources to C sources when they exists (Mix Ada/C libbsp) +SOC_ASRC = $(socdrv-ada-bsp-y) + +ADACEQ = $(patsubst Ada/%.adb,%.c,$(socdrv-ada-bsp-y)) +SRC_TMP = $(filter-out $(ADACEQ),$(socdrv-bsp-y)) +SOC_SRC := $(SRC_TMP) +SOC_OBJ := $(patsubst %.c,$(APP_BUILD_DIR)/soc/%.o,$(SOC_SRC)) +SOC_DEP := $(SOC_OBJ:.o=.d) +endif + +ifeq ($(CONFIG_ADAKERNEL),y) +# to finish with Ada, declare the location of the Ada lib +ALIB = $(APP_BUILD_DIR)/Ada/lib/libabsp.a +ADIR = $(APP_BUILD_DIR)/Ada/lib +endif + +#C sources files +BOARD_SRC = $(board-bsp-y) +BOARD_OBJ = $(patsubst %.c,$(APP_BUILD_DIR)/board/%.o,$(BOARD_SRC)) +BOARD_DEP = $(BOARD_OBJ:.o=.d) + +#Rust sources files +RSSRC_DIR= rust/src +RSRC= $(wildcard $(RSRCDIR)/*.rs) +ROBJ = $(patsubst %.rs,$(APP_BUILD_DIR)/%.o,$(RSRC)) + +#ada sources files +ASRC_DIR = ada/src +ASRC= $(wildcard $(ASRC_DIR)/*.adb) +AOBJ = $(patsubst %.adb,$(APP_BUILD_DIR)/%.o,$(ASRC)) + +OUT_DIRS = $(dir $(OBJ)) $(dir $(BOARD_OBJ)) $(dir $(SOC_OBJ)) $(dir $(CORE_OBJ)) $(dir $(AOBJ)) $(dir $(ROBJ)) + +# file to (dist)clean +# objects and compilation related +TODEL_CLEAN += $(OBJ) $(ROBJ) $(SOC_OBJ) $(BOARD_OBJ) $(CORE_OBJ) $(DEP) $(TESTSDEP) $(SOC_DEP) $(BOARD_DEP) $(CORE_DEP) +# targets +TODEL_DISTCLEAN += $(APP_BUILD_DIR) + +.PHONY: app __clean __distclean + +default: all + +all: $(APP_BUILD_DIR) lib + +show: + @echo + @echo "\tAPP_BUILD_DIR\t=> " $(APP_BUILD_DIR) + @echo + @echo "C sources files:" + @echo "\tSRC_DIR\t\t=> " $(SRC_DIR) + @echo "\tSRC\t\t=> " $(SRC) + @echo "\tOBJ\t\t=> " $(OBJ) + @echo + @echo "\tCORE_DIR\t=> " $(CORE_DIR) + @echo "\tCORE_SRC\t=> " $(CORE_SRC) + @echo "\tCORE_ASRC\t=> " $(CORE_ASRC) + @echo "\tCORE_OBJ\t=> " $(CORE_OBJ) + @echo + @echo "\tSOC_DIR\t=> " $(SOC_DIR) + @echo "\tSOC_SRC\t=> " $(SOC_SRC) + @echo "\tSOC_ASRC\t=> " $(SOC_ASRC) + @echo "\tSOC_OBJ\t=> " $(SOC_OBJ) + @echo + +lib: $(APP_BUILD_DIR)/$(LIB_FULL_NAME) + +############################################################# +# build targets (driver, core, SoC, Board... and local) +# App C sources files + +ifeq ($(CONFIG_ADAKERNEL),y) +$(ADIR): + $(call cmd,mkdir) + +$(ALIB): libabsp $(ADIR) + $(call cmd,ada_lib) + +libabsp: libabsp.gpr + +endif + + +$(APP_BUILD_DIR)/%.o: %.c + $(call if_changed,cc_o_c) + +# Core C sources files +$(APP_BUILD_DIR)/core/%.o: $(CORE_DIR)/%.c + $(call if_changed,cc_o_c) + +# SoC C sources files +$(APP_BUILD_DIR)/soc/%.o: $(SOC_DIR)/%.c + $(call if_changed,cc_o_c) + +# SoC ASM sources files +$(APP_BUILD_DIR)/soc/%.o: $(SOC_DIR)/%.s + $(call if_changed,cc_o_c) + +# Board C sources files +$(APP_BUILD_DIR)/board/%.o: $(BOARD_DIR)/%.c + $(call if_changed,cc_o_c) + +# lib +$(APP_BUILD_DIR)/$(LIB_FULL_NAME): $(OBJ) $(AOBJ) $(ROBJ) $(SOC_OBJ) $(BOARD_OBJ) $(CORE_OBJ) $(ALIB) + $(call if_changed,mklib) + $(call if_changed,ranlib) + +$(APP_BUILD_DIR): + $(call cmd,mkdir) + +ifeq ($(CONFIG_ADAKERNEL),y) +__clean: libabsp.gpr + $(call cmd,ada_clean) + +__distclean: libabsp.gpr + $(call cmd,ada_distclean) +endif + +-include $(DEP) +-include $(TESTSDEP) diff --git a/arch/README.md b/arch/README.md new file mode 100644 index 0000000..65cbf54 --- /dev/null +++ b/arch/README.md @@ -0,0 +1,34 @@ +About this directory +==================== + +All arch-specific content should be written here. + +The difference with drivers & periphericals is that this part is the ASP +(Architecture Support Package), which implements the basics of the target +triplet (board-soc-core). It should not contain neither a given external +nor complex IP support (e.g. Ethernel controler, USB controler, etc.), +such IP being potentially usable in various boards based on various SoC. + +We keep here what is the lonely property of a given: + - boards: e.g. led position + - Socs: e.g. memory layout + - cores: generic support (MPU, FPU...) + +Any IP (commercial Intelectual Property - that can be a part of various SoC) +support has to be written in the drivers/ dir + +The boards dir contains one dir per target board. The directory name should +correspond to the name given in the KCONFIG CONFIG_BOARDNAME config option. + +The socs dir contains (by now) a flat directory for all SoC layout header files. +These files describe the memory layout for each SoC. + +the cores dir contains one directory per core, using a core named that should +correspond to the name given in the KCONFIG CONFIG_ARCH config option (e.g. +armv7-m) It contains all the core specific implementations (initialization functions +for GIC, MPU, FPU, TZ, etc.) + +the function names should be generic enough to be the same between each +arch_specific support (e.g. irq_enable, FPU_IRQHandler, etc.). heach arch +header should propose the same set of function to avoid modification in the +arch-independent code. diff --git a/arch/auto.cgpr b/arch/auto.cgpr new file mode 100644 index 0000000..50a6677 --- /dev/null +++ b/arch/auto.cgpr @@ -0,0 +1,17 @@ +-- This gpr configuration file was generated by gprconfig +-- using this command line: +-- /usr/bin/gprconfig --batch -o /home/phil/Travail/Goodusb/goodusb-soft/kernel/arch/auto.cgpr --target=arm-eabi -q --config=ada,,zfp-stm32f4 + +configuration project Default is + for Target use "arm-eabi"; + for Archive_Builder use ("ar", "cr"); + for Archive_Builder_Append_Option use ("q"); + for Archive_Indexer use ("ranlib"); + for Archive_Suffix use ".a"; + + package Clean is + -- Remove the files generated by gnatinspect (in the context of GPS) + for Artifacts_In_Object_Dir use Clean'Artifacts_In_Object_Dir + & ("gnatinspect.*"); + end Clean; +end Default; diff --git a/arch/boards/32f407discovery/Kconfig b/arch/boards/32f407discovery/Kconfig new file mode 100644 index 0000000..019c14d --- /dev/null +++ b/arch/boards/32f407discovery/Kconfig @@ -0,0 +1,3 @@ +config RAM_SLOT_SIZE + int + default 16384 diff --git a/arch/boards/32f407discovery/Makefile.objs b/arch/boards/32f407discovery/Makefile.objs new file mode 100644 index 0000000..e69de29 diff --git a/arch/boards/32f407discovery/buttons.h b/arch/boards/32f407discovery/buttons.h new file mode 100644 index 0000000..eafcd86 --- /dev/null +++ b/arch/boards/32f407discovery/buttons.h @@ -0,0 +1,29 @@ +/* \file buttons.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef DISCOVERY_BUTTON_H_ +# define DISCOVERY_BUTTON_H_ + + +# define D_BUTTON_PIN 0 + +#endif /* !DISCOVERY_BUTTON_H_ */ diff --git a/arch/boards/32f407discovery/disco.h b/arch/boards/32f407discovery/disco.h new file mode 100644 index 0000000..225a8c8 --- /dev/null +++ b/arch/boards/32f407discovery/disco.h @@ -0,0 +1,33 @@ +/* \file disco.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _DISCO_H +#define _DISCO_H + + #if defined(STM32F4XX) + #include "stm32f4xx.h" + #elif defined(STM32F41X) + #include "stm32f41x.h" + #else + #error "You must define a target mcu" + +#endif /*!_DISCO_H */ diff --git a/arch/boards/32f407discovery/leds.h b/arch/boards/32f407discovery/leds.h new file mode 100644 index 0000000..28a4c6d --- /dev/null +++ b/arch/boards/32f407discovery/leds.h @@ -0,0 +1,39 @@ +/* \file leds.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef LEDS_H_ +# define LEDS_H_ + + +# define LED3_PIN 13 +# define LED4_PIN 12 +# define LED5_PIN 14 +# define LED6_PIN 15 + + +#define PROD_LED_STATUS LED3_PIN +#define PROD_LED_ACTIVITY LED4_PIN + + +enum led {LED3 = LED3_PIN, LED4 = LED4_PIN, LED5 = LED5_PIN, LED6 = LED6_PIN}; + +#endif /* !LEDS_H_ */ diff --git a/arch/boards/32f407discovery/params.h b/arch/boards/32f407discovery/params.h new file mode 100644 index 0000000..d238eed --- /dev/null +++ b/arch/boards/32f407discovery/params.h @@ -0,0 +1,72 @@ +/* \file params.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef PARAM_H_ +# define PARAM_H_ + +#include "autoconf.h" +/* + * BLOCK_SIZE - Size of block on GoodUSB + * + * This size should depend on the size of SD blocks. The minimum size is 512. + * Increasing BLOCK_SIZE should force to decrease BIG_POOL_SIZE. + * + * The only tested value is 512. + */ +# define BLOCK_SIZE 512 + +/* + * Malloc + */ +/* FIXME: pool size must be a multiple of 32 */ +# define SMALL_POOL_SIZE CONFIG_ALLOC_POOL_SMALL +# define SMALL_POOL_BLOCK_SIZE 16 + +# define MEDIUM_POOL_SIZE CONFIG_ALLOC_POOL_MEDIUM +# define MEDIUM_POOL_BLOCK_SIZE 64 + +# define BIG_POOL_SIZE CONFIG_ALLOC_POOL_BIG +# define BIG_POOL_BLOCK_SIZE BLOCK_SIZE + +# define MALLOC_POOL_PROMOTION 0 + + +/* + * Manager + */ +# define USB_TO_CRYPTO_QUEUE_SIZE 10 +# define CRYPTO_TO_SD_QUEUE_SIZE 10 +# define SD_COMMANDS_QUEUE_SIZE 10 +# define SD_TO_CRYPTO_QUEUE_SIZE 10 +/* This queue stores 64 bytes packets so it should be at greater or equal to + * SD_TO_CRYPTO_QUEUE_SIZE. + */ +# define CRYPTO_TO_USB_QUEUE_SIZE 128 + + +/* + * logs + */ +# define DUMP_STATS 1 +# define DUMP_STATS_FREQ 1 + +#endif /* PARAM_H_ */ diff --git a/arch/boards/32f407discovery/product.h b/arch/boards/32f407discovery/product.h new file mode 100644 index 0000000..4c9699b --- /dev/null +++ b/arch/boards/32f407discovery/product.h @@ -0,0 +1,55 @@ +/* \file products.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef PRODUCT_H +# define PRODUCT_H +#include "soc-rcc.h" + +#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ + +//#define PROD_ENABLE_HSE + +#define PROD_ENABLE_PLL 1 + + +#define PROD_PLL_M 16 +#define PROD_PLL_N 336 +#define PROD_PLL_P 2 +#define PROD_PLL_Q 7 + +#define PROD_HCLK RCC_CFGR_HPRE_DIV1 +#define PROD_PCLK2 RCC_CFGR_HPRE2_DIV2 +#define PROD_PCLK1 RCC_CFGR_HPRE1_DIV4 + +#define PROD_CLOCK_SYS //FIXME + +#define PROD_CLOCK_APB1 42000000 // MHz +#define PROD_CLOCK_APB2 84000000 // MHz +#define PROD_CONSOLE_USART 1 + +#define PROD_CORE_FREQUENCY 168000 + +#define PROD_MAX_USB_ENDPOINTS 3 /* uint8_t */ + + +#endif /* PRODUCT_H */ diff --git a/arch/boards/32f429discovery/Kconfig b/arch/boards/32f429discovery/Kconfig new file mode 100644 index 0000000..019c14d --- /dev/null +++ b/arch/boards/32f429discovery/Kconfig @@ -0,0 +1,3 @@ +config RAM_SLOT_SIZE + int + default 16384 diff --git a/arch/boards/32f429discovery/Makefile.objs b/arch/boards/32f429discovery/Makefile.objs new file mode 100644 index 0000000..e69de29 diff --git a/arch/boards/32f429discovery/buttons.h b/arch/boards/32f429discovery/buttons.h new file mode 100644 index 0000000..eafcd86 --- /dev/null +++ b/arch/boards/32f429discovery/buttons.h @@ -0,0 +1,29 @@ +/* \file buttons.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef DISCOVERY_BUTTON_H_ +# define DISCOVERY_BUTTON_H_ + + +# define D_BUTTON_PIN 0 + +#endif /* !DISCOVERY_BUTTON_H_ */ diff --git a/arch/boards/32f429discovery/disco.h b/arch/boards/32f429discovery/disco.h new file mode 100644 index 0000000..225a8c8 --- /dev/null +++ b/arch/boards/32f429discovery/disco.h @@ -0,0 +1,33 @@ +/* \file disco.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _DISCO_H +#define _DISCO_H + + #if defined(STM32F4XX) + #include "stm32f4xx.h" + #elif defined(STM32F41X) + #include "stm32f41x.h" + #else + #error "You must define a target mcu" + +#endif /*!_DISCO_H */ diff --git a/arch/boards/32f429discovery/leds.h b/arch/boards/32f429discovery/leds.h new file mode 100644 index 0000000..28a4c6d --- /dev/null +++ b/arch/boards/32f429discovery/leds.h @@ -0,0 +1,39 @@ +/* \file leds.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef LEDS_H_ +# define LEDS_H_ + + +# define LED3_PIN 13 +# define LED4_PIN 12 +# define LED5_PIN 14 +# define LED6_PIN 15 + + +#define PROD_LED_STATUS LED3_PIN +#define PROD_LED_ACTIVITY LED4_PIN + + +enum led {LED3 = LED3_PIN, LED4 = LED4_PIN, LED5 = LED5_PIN, LED6 = LED6_PIN}; + +#endif /* !LEDS_H_ */ diff --git a/arch/boards/32f429discovery/params.h b/arch/boards/32f429discovery/params.h new file mode 100644 index 0000000..d238eed --- /dev/null +++ b/arch/boards/32f429discovery/params.h @@ -0,0 +1,72 @@ +/* \file params.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef PARAM_H_ +# define PARAM_H_ + +#include "autoconf.h" +/* + * BLOCK_SIZE - Size of block on GoodUSB + * + * This size should depend on the size of SD blocks. The minimum size is 512. + * Increasing BLOCK_SIZE should force to decrease BIG_POOL_SIZE. + * + * The only tested value is 512. + */ +# define BLOCK_SIZE 512 + +/* + * Malloc + */ +/* FIXME: pool size must be a multiple of 32 */ +# define SMALL_POOL_SIZE CONFIG_ALLOC_POOL_SMALL +# define SMALL_POOL_BLOCK_SIZE 16 + +# define MEDIUM_POOL_SIZE CONFIG_ALLOC_POOL_MEDIUM +# define MEDIUM_POOL_BLOCK_SIZE 64 + +# define BIG_POOL_SIZE CONFIG_ALLOC_POOL_BIG +# define BIG_POOL_BLOCK_SIZE BLOCK_SIZE + +# define MALLOC_POOL_PROMOTION 0 + + +/* + * Manager + */ +# define USB_TO_CRYPTO_QUEUE_SIZE 10 +# define CRYPTO_TO_SD_QUEUE_SIZE 10 +# define SD_COMMANDS_QUEUE_SIZE 10 +# define SD_TO_CRYPTO_QUEUE_SIZE 10 +/* This queue stores 64 bytes packets so it should be at greater or equal to + * SD_TO_CRYPTO_QUEUE_SIZE. + */ +# define CRYPTO_TO_USB_QUEUE_SIZE 128 + + +/* + * logs + */ +# define DUMP_STATS 1 +# define DUMP_STATS_FREQ 1 + +#endif /* PARAM_H_ */ diff --git a/arch/boards/32f429discovery/product.h b/arch/boards/32f429discovery/product.h new file mode 100644 index 0000000..4c9699b --- /dev/null +++ b/arch/boards/32f429discovery/product.h @@ -0,0 +1,55 @@ +/* \file products.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef PRODUCT_H +# define PRODUCT_H +#include "soc-rcc.h" + +#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ + +//#define PROD_ENABLE_HSE + +#define PROD_ENABLE_PLL 1 + + +#define PROD_PLL_M 16 +#define PROD_PLL_N 336 +#define PROD_PLL_P 2 +#define PROD_PLL_Q 7 + +#define PROD_HCLK RCC_CFGR_HPRE_DIV1 +#define PROD_PCLK2 RCC_CFGR_HPRE2_DIV2 +#define PROD_PCLK1 RCC_CFGR_HPRE1_DIV4 + +#define PROD_CLOCK_SYS //FIXME + +#define PROD_CLOCK_APB1 42000000 // MHz +#define PROD_CLOCK_APB2 84000000 // MHz +#define PROD_CONSOLE_USART 1 + +#define PROD_CORE_FREQUENCY 168000 + +#define PROD_MAX_USB_ENDPOINTS 3 /* uint8_t */ + + +#endif /* PRODUCT_H */ diff --git a/arch/boards/Makefile.objs b/arch/boards/Makefile.objs new file mode 100644 index 0000000..e8464bd --- /dev/null +++ b/arch/boards/Makefile.objs @@ -0,0 +1,14 @@ +BOARD_DIR = $(PROJ_FILES)/kernel/arch/boards/$(BOARD) + +CFLAGS += -I$(BOARD_DIR) +CFLAGS += -I$(BOARD_DIR)/.. + +board-bsp-y := + +# per-board drivers +ifneq ($(BOARD),) +include $(PROJ_FILES)kernel/arch/boards/$(BOARD)/Makefile.objs +endif + +# generic, the "../" is relative to BOARD_DIR, see apps Makefile +board-bsp-y += ../shared.c diff --git a/arch/boards/boards.h b/arch/boards/boards.h new file mode 100644 index 0000000..c433da7 --- /dev/null +++ b/arch/boards/boards.h @@ -0,0 +1,34 @@ +/* \file boards.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _BOARDS_H +#define _BOARDS_H + #if defined(CONFIG_WOOKEY) + #include "wookey/wookey.h" + #elif defined(CONFIG_DISCO407) + #include "32f407discovery/disco.h" + #elif defined(CONFIG_DISCO429) + #include "32f439discovery/disco.h" + #else + #error "You must define a board type" + #endif +#endif /* _BOARDS_H */ diff --git a/arch/boards/shared.c b/arch/boards/shared.c new file mode 100644 index 0000000..32bb934 --- /dev/null +++ b/arch/boards/shared.c @@ -0,0 +1,54 @@ +/* \file shared.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*! + * \file shared.c + * + * This file handle the SHR section structure. This content is out of + * the basic layout and is shared beetween the kernel and the loader + * for bootloading information such as flip/flop state + */ +#include "debug.h" +#include "soc-init.h" +#include "soc-layout.h" +#include "shared.h" +//#include "keys.h" + +__attribute__((section(".shared"))) + const shr_vars_t shared_vars = { + .default_app_index = 0, /* default boot to FW1 */ + .apps = { + { .entry_point = (app_entry_t)FW1_START, .version = 0x00000001, .boot_status = BOOT_OK }, +#ifdef CONFIG_FIRMWARE_DFU + { .entry_point = (app_entry_t)DFU1_START, .version = 0x00000001, .boot_status = BOOT_OK }, +#endif +#ifdef CONFIG_FIRMWARE_DUALBANK + { .entry_point = (app_entry_t)FW2_START, .version = 0x00000001, .boot_status = BOOT_OK }, +#endif + }, + //.siglen = DFU_SIGLEN, /* default siglen */ + .siglen = 0x0, /* default siglen */ + //.sig = DFU_SIG, + .sig = { 0x0 }, + } ; + diff --git a/arch/boards/shared.h b/arch/boards/shared.h new file mode 100644 index 0000000..83ae879 --- /dev/null +++ b/arch/boards/shared.h @@ -0,0 +1,57 @@ +/* \file shared.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _SHARED_H +#define _SHARED_H + +#include "autoconf.h" + +#define MAX_APP_INDEX 3 +#define APP_INDEX_FW1 0 +#define APP_INDEX_DFU 1 +#define APP_INDEX_FW2 2 + + +#define BOOT_OK 0x0000FFFF +#define BOOT_KO 0xFFFF0000 +#define BOOT_CK 0x00FF00FF + + +typedef int (* app_entry_t)(void); + +typedef struct __packed { + app_entry_t entry_point; + uint32_t version; + uint32_t boot_status; + // const char sig[]; +} app_t; + + +typedef struct __packed { + uint32_t default_app_index; + app_t apps[MAX_APP_INDEX]; + const char kernel_msg[24][82]; + uint32_t siglen; + char sig[]; +} shr_vars_t; + +#endif diff --git a/arch/boards/wookey/Kconfig b/arch/boards/wookey/Kconfig new file mode 100644 index 0000000..019c14d --- /dev/null +++ b/arch/boards/wookey/Kconfig @@ -0,0 +1,3 @@ +config RAM_SLOT_SIZE + int + default 16384 diff --git a/arch/boards/wookey/Makefile.objs b/arch/boards/wookey/Makefile.objs new file mode 100644 index 0000000..e69de29 diff --git a/arch/boards/wookey/buttons.h b/arch/boards/wookey/buttons.h new file mode 100644 index 0000000..f73dd8c --- /dev/null +++ b/arch/boards/wookey/buttons.h @@ -0,0 +1,28 @@ +/* \file button,h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef BUTTON_H_ +# define BUTTON_H_ + +# define D_BUTTON_PIN 4 + +#endif /* !BUTTON_H_ */ diff --git a/arch/boards/wookey/leds.h b/arch/boards/wookey/leds.h new file mode 100644 index 0000000..bd9d11d --- /dev/null +++ b/arch/boards/wookey/leds.h @@ -0,0 +1,34 @@ +/* \file leds.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef LEDS_H_ +#define LEDS_H_ + +#define LED0_PIN 4 +#define LED1_PIN 5 + +#define PROD_LED_STATUS LED0_PIN +#define PROD_LED_ACTIVITY LED1_PIN + +enum led {LED0 = LED0_PIN, LED1 = LED1_PIN }; + +#endif /* !LEDS_H_ */ diff --git a/arch/boards/wookey/params.h b/arch/boards/wookey/params.h new file mode 100644 index 0000000..0ee26d8 --- /dev/null +++ b/arch/boards/wookey/params.h @@ -0,0 +1,72 @@ +/* \file params.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef PARAM_H_ +# define PARAM_H_ + +/* + * BLOCK_SIZE - Size of block on GoodUSB + * + * This size should depend on the size of SD blocks. The minimum size is 512. + * Increasing BLOCK_SIZE should force to decrease BIG_POOL_SIZE. + * + * The only tested value is 512. + */ +# define BLOCK_SIZE 512 + + +/* + * Malloc + */ +/* FIXME: pool size must be a multiple of 32 */ +# define SMALL_POOL_SIZE 1024 +# define SMALL_POOL_BLOCK_SIZE 16 + +# define MEDIUM_POOL_SIZE 512 +# define MEDIUM_POOL_BLOCK_SIZE 64 + +# define BIG_POOL_SIZE 128 +# define BIG_POOL_BLOCK_SIZE BLOCK_SIZE + +# define MALLOC_POOL_PROMOTION 0 + + +/* + * Manager + */ +# define USB_TO_CRYPTO_QUEUE_SIZE 10 +# define CRYPTO_TO_SD_QUEUE_SIZE 10 +# define SD_COMMANDS_QUEUE_SIZE 10 +# define SD_TO_CRYPTO_QUEUE_SIZE 10 +/* This queue stores 64 bytes packets so it should be at greater or equal to + * SD_TO_CRYPTO_QUEUE_SIZE. + */ +# define CRYPTO_TO_USB_QUEUE_SIZE 128 + + +/* + * logs + */ +# define DUMP_STATS 1 +# define DUMP_STATS_FREQ 1 + +#endif /*!PARAM_H_ */ diff --git a/arch/boards/wookey/product.h b/arch/boards/wookey/product.h new file mode 100644 index 0000000..8f0b0f7 --- /dev/null +++ b/arch/boards/wookey/product.h @@ -0,0 +1,54 @@ +/* \file product.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef PRODUCT_H +# define PRODUCT_H +#include "soc-rcc.h" +#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ + +#define STM32F429 + +//#define PROD_ENABLE_HSE +#define PROD_ENABLE_PLL 1 + + +#define PROD_PLL_M 16 +#define PROD_PLL_N 336 +#define PROD_PLL_P 2 +#define PROD_PLL_Q 7 + +#define PROD_HCLK RCC_CFGR_HPRE_DIV1 +#define PROD_PCLK2 RCC_CFGR_HPRE2_DIV2 +#define PROD_PCLK1 RCC_CFGR_HPRE1_DIV4 + +#define PROD_CLOCK_APB1 42000000 // MHz +#define PROD_CLOCK_APB2 84000000 // MHz +#define PROD_CONSOLE_USART 1 + +#define PROD_CORE_FREQUENCY 168000 + +#define PROD_CRYPTO_HARD 1 + +#define PROD_MAX_USB_ENDPOINTS 3 /* uint8_t */ + +#endif /*!PRODUCT_H */ diff --git a/arch/cores/armv7-m/Ada/config.def b/arch/cores/armv7-m/Ada/config.def new file mode 120000 index 0000000..2f78398 --- /dev/null +++ b/arch/cores/armv7-m/Ada/config.def @@ -0,0 +1 @@ +../../../../Ada/generated/config.def \ No newline at end of file diff --git a/arch/cores/armv7-m/Ada/m4-cpu-instructions.adb b/arch/cores/armv7-m/Ada/m4-cpu-instructions.adb new file mode 100644 index 0000000..aa36162 --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-cpu-instructions.adb @@ -0,0 +1,96 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with system.machine_code; + +package body m4.cpu.instructions + with spark_mode => off +is + + + procedure ISB + is + begin + system.machine_code.asm ("isb", volatile => true); + end ISB; + + + procedure DSB + is + begin + system.machine_code.asm ("dsb", volatile => true); + end DSB; + + + procedure DMB + is + begin + system.machine_code.asm ("dmb", volatile => true); + end DMB; + + + procedure full_memory_barrier + is + begin + system.machine_code.asm + ("dsb" & ascii.lf & + "isb", + volatile => true); + end full_memory_barrier; + + + procedure REV16 (value : in out unsigned_32) + is + begin + system.machine_code.asm + ("rev16 %0, %1", + inputs => unsigned_32'asm_input ("r", value), + outputs => unsigned_32'asm_output ("=r", value), + volatile => true); + end REV16; + + + procedure REV (value : in out unsigned_32) + is + begin + system.machine_code.asm + ("rev %0, %1", + inputs => unsigned_32'asm_input ("r", value), + outputs => unsigned_32'asm_output ("=r", value), + volatile => true); + end REV; + + + procedure BKPT + is + begin + system.machine_code.asm ("bkpt", volatile => true); + end BKPT; + + + procedure WFI + is + begin + system.machine_code.asm ("wfi", volatile => true); + end WFI; + +end m4.cpu.instructions; diff --git a/arch/cores/armv7-m/Ada/m4-cpu-instructions.ads b/arch/cores/armv7-m/Ada/m4-cpu-instructions.ads new file mode 100644 index 0000000..04a7a68 --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-cpu-instructions.ads @@ -0,0 +1,64 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package m4.cpu.instructions + with spark_mode => on +is + + type t_svc_instruction is record + svc_num : unsigned_8; + opcode : unsigned_8 := 16#DF#; + end record + with size => 16; + + procedure ISB + with inline; + + procedure DSB + with inline; + + procedure DMB + with inline; + + -- Full Memory barrier (D+I) + -- Force data and instruction synchronisation barrier. + -- (privileged mode) + procedure full_memory_barrier + with inline; + + procedure REV (value : in out unsigned_32) + with inline; + + procedure REV16 (value : in out unsigned_32) + with inline; + + procedure BKPT + with inline; + + procedure WFI + with inline; + + procedure wait_for_interrupt renames WFI; + + +end m4.cpu.instructions; diff --git a/arch/cores/armv7-m/Ada/m4-cpu.adb b/arch/cores/armv7-m/Ada/m4-cpu.adb new file mode 100644 index 0000000..0f9ebd4 --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-cpu.adb @@ -0,0 +1,185 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with system.machine_code; + +package body m4.cpu + with spark_mode => off +is + + procedure enable_irq + is + begin + system.machine_code.asm + ("cpsie i; isb", + clobber => "memory", + volatile => true); + end enable_irq; + + + procedure disable_irq + is + begin + system.machine_code.asm + ("cpsid i", + clobber => "memory", + volatile => true); + end disable_irq; + + + function get_control_register return t_control_register + is + cr : t_control_register; + begin + system.machine_code.asm + ("mrs %0, control", + outputs => t_control_register'asm_output ("=r", cr), + volatile => true); + return cr; + end get_control_register; + + + procedure set_control_register (cr : t_control_register) + is + begin + system.machine_code.asm + ("msr control, %0", + inputs => t_control_register'asm_input ("r", cr), + volatile => true); + end set_control_register; + + + function get_ipsr_register return t_ipsr_register + is + ipsr : t_ipsr_register; + begin + system.machine_code.asm + ("mrs %0, ipsr", + outputs => t_ipsr_register'asm_output ("=r", ipsr), + volatile => true); + return ipsr; + end get_ipsr_register; + + + function get_apsr_register return t_apsr_register + is + apsr : t_apsr_register; + begin + system.machine_code.asm + ("mrs %0, apsr", + outputs => t_apsr_register'asm_output ("=r", apsr), + volatile => true); + return apsr; + end get_apsr_register; + + + function get_epsr_register return t_epsr_register + is + epsr : t_epsr_register; + begin + system.machine_code.asm + ("mrs %0, epsr", + outputs => t_epsr_register'asm_output ("=r", epsr), + volatile => true); + return epsr; + end get_epsr_register; + + + function get_lr_register return unsigned_32 + is + val : unsigned_32; + begin + system.machine_code.asm + ("mov %0, lr", + outputs => unsigned_32'asm_output ("=r", val), + volatile => true); + return val; + end get_lr_register; + + + function get_psp_register return system_address + is + addr : system_address; + begin + system.machine_code.asm + ("mrs %0, psp", + outputs => system_address'asm_output ("=r", addr), + volatile => true); + return addr; + end get_psp_register; + + + procedure set_psp_register (addr : system_address) + is + begin + system.machine_code.asm + ("msr psp, %0", + inputs => system_address'asm_input ("r", addr), + volatile => true); + end set_psp_register; + + + function get_msp_register return system_address + is + addr : system_address; + begin + system.machine_code.asm + ("mrs %0, msp", + outputs => system_address'asm_output ("=r", addr), + volatile => true); + return addr; + end get_msp_register; + + + procedure set_msp_register (addr : system_address) + is + begin + system.machine_code.asm + ("msr msp, %0", + inputs => system_address'asm_input ("r", addr), + volatile => true); + end set_msp_register; + + + function get_primask_register return unsigned_32 + is + mask : unsigned_32; + begin + system.machine_code.asm + ("mrs %0, primask", + outputs => unsigned_32'asm_output ("=r", mask), + volatile => true); + return mask; + end get_primask_register; + + + procedure set_primask_register (mask : unsigned_32) + is + begin + system.machine_code.asm + ("msr primask, %0", + inputs => unsigned_32'asm_input ("r", mask), + volatile => true); + end set_primask_register; + + +end m4.cpu; diff --git a/arch/cores/armv7-m/Ada/m4-cpu.ads b/arch/cores/armv7-m/Ada/m4-cpu.ads new file mode 100644 index 0000000..9ca1e48 --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-cpu.ads @@ -0,0 +1,217 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +pragma Restrictions (No_Elaboration_Code); +with ada.unchecked_conversion; + +package m4.cpu + with spark_mode => on +is + + ------------- + -- Globals -- + ------------- + + EXC_THREAD_MODE : constant unsigned_32 := 16#FFFF_FFFD#; + EXC_KERN_MODE : constant unsigned_32 := 16#FFFF_FFF9#; + EXC_HANDLER_MODE : constant unsigned_32 := 16#FFFF_FFF1#; + + --------------- + -- Registers -- + --------------- + + -- + -- CONTROL register + -- + + type t_SPSEL is (MSP, PSP) with size => 1; + for t_SPSEL use (MSP => 0, PSP => 1); + + type t_PRIV is (PRIVILEGED, UNPRIVILEGED) with size => 1; + for t_PRIV use (PRIVILEGED => 0, UNPRIVILEGED => 1); + + type t_control_register is record + nPRIV : t_PRIV; -- Thread mode is privileged (0), unprivileged (1) + SPSEL : t_SPSEL; -- Current stack pointer + end record + with size => 32; + + for t_control_register use record + nPRIV at 0 range 0 .. 0; + SPSEL at 0 range 1 .. 1; + end record; + + -- + -- PSR register that aggregates (A)(I)(E)PSR registers + -- + + type t_PSR_register is record + ISR_NUMBER : unsigned_8; + ICI_IT_lo : bits_6; + GE : bits_4; + Thumb : bit; + ICI_IT_hi : bits_2; + DSP_overflow : bit; -- Q + Overflow : bit; -- V + Carry : bit; + Zero : bit; + Negative : bit; + end record + with size => 32; + + for t_PSR_register use record + ISR_NUMBER at 0 range 0 .. 7; + ICI_IT_lo at 0 range 10 .. 15; + GE at 0 range 16 .. 19; + Thumb at 0 range 24 .. 24; + ICI_IT_hi at 0 range 25 .. 26; + DSP_overflow at 0 range 27 .. 27; + Overflow at 0 range 28 .. 28; + Carry at 0 range 29 .. 29; + Zero at 0 range 30 .. 30; + Negative at 0 range 31 .. 31; + end record; + + function to_unsigned_32 is new ada.unchecked_conversion + (t_PSR_register, unsigned_32); + + -- + -- APSR register + -- + + type t_APSR_register is record + GE : bits_4; + DSP_overflow : bit; + Overflow : bit; + Carry : bit; + Zero : bit; + Negative : bit; + end record + with size => 32; + + for t_APSR_register use record + GE at 0 range 16 .. 19; + DSP_overflow at 0 range 27 .. 27; + Overflow at 0 range 28 .. 28; + Carry at 0 range 29 .. 29; + Zero at 0 range 30 .. 30; + Negative at 0 range 31 .. 31; + end record; + + function to_PSR_register is new ada.unchecked_conversion + (t_APSR_register, t_PSR_register); + + -- + -- IPSR register + -- + + type t_IPSR_register is record + ISR_NUMBER : unsigned_8; + end record + with size => 32; + + function to_PSR_register is new ada.unchecked_conversion + (t_IPSR_register, t_PSR_register); + + -- + -- EPSR register + -- + + type t_EPSR_register is record + ICI_IT_lo : bits_6; + Thumb : bit; + ICI_IT_hi : bits_2; + end record + with size => 32; + + for t_EPSR_register use record + ICI_IT_lo at 0 range 10 .. 15; + Thumb at 0 range 24 .. 24; + ICI_IT_hi at 0 range 25 .. 26; + end record; + + function to_PSR_register is new ada.unchecked_conversion + (t_EPSR_register, t_PSR_register); + + --------------- + -- Functions -- + --------------- + + -- Enable IRQs by clearing the I-bit in the CPSR. + -- (privileged mode) + procedure enable_irq + with inline; + + -- Disable IRQs by setting the I-bit in the CPSR. + -- (privileged mode) + procedure disable_irq + with inline; + + -- Get the Control register. + function get_control_register return t_control_register + with inline; + + -- Set the Control register. + procedure set_control_register (cr : in t_control_register) + with inline; + + -- Get the IPSR register. + function get_ipsr_register return t_ipsr_register + with inline; + + -- Get the APSR register. + function get_apsr_register return t_apsr_register + with inline; + + -- Get the EPSR register. + function get_epsr_register return t_epsr_register + with inline; + + -- Get the LR register + function get_lr_register return unsigned_32 + with inline; + + -- Get the process stack pointer (PSP) + function get_psp_register return system_address + with inline; + + -- Set the process stack pointer (PSP) + procedure set_psp_register (addr : in system_address) + with inline; + + -- Get the main stack pointer (MSP) + function get_msp_register return system_address + with inline; + + -- Set the main stack pointer (MSP) + procedure set_msp_register (addr : system_address) + with inline; + + -- Get the priority mask value + function get_primask_register return unsigned_32 + with inline; + + -- Set the priority mask value + procedure set_primask_register (mask : in unsigned_32) + with inline; + +end m4.cpu; diff --git a/arch/cores/armv7-m/Ada/m4-layout.ads b/arch/cores/armv7-m/Ada/m4-layout.ads new file mode 100644 index 0000000..c40a837 --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-layout.ads @@ -0,0 +1,41 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with system; use system; + +package m4.layout + with spark_mode => on +is + + -------------------- + -- Base addresses -- + -------------------- + + SCB_BASE : constant address := system'to_address (16#E000_E008#); + SYS_TIMER_BASE : constant address := system'to_address (16#E000_E010#); + NVIC_BASE : constant address := system'to_address (16#E000_E100#); + SCB_BASE2 : constant address := system'to_address (16#E000_ED00#); + MPU_BASE : constant address := system'to_address (16#E000_ED90#); + NVIC_BASE2 : constant address := system'to_address (16#E000_EF00#); + FPU_BASE : constant address := system'to_address (16#E000_EF30#); + +end m4.layout; diff --git a/arch/cores/armv7-m/Ada/m4-mpu.adb b/arch/cores/armv7-m/Ada/m4-mpu.adb new file mode 100644 index 0000000..baab16e --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-mpu.adb @@ -0,0 +1,126 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with m4.scb; use m4.scb; + +package body m4.mpu + with spark_mode => on +is + + function address_to_bits_27 (addr : system_address) + return bits_27 + is + pragma warnings (off); + function to_bits_27 is + new ada.unchecked_conversion (unsigned_32, bits_27); + pragma warnings (on); + begin + return to_bits_27 (shift_right (addr, 5)); + end address_to_bits_27; + + + procedure is_mpu_available + (success : out boolean) + is + begin + if to_unsigned_32 (MPU.TYPER) = 0 then + success := false; + else + success := true; + end if; + end is_mpu_available; + + + procedure enable is + begin + MPU.CTRL.ENABLE := true; + end enable; + + + procedure disable is + begin + MPU.CTRL.ENABLE := false; + end disable; + + + procedure init + is + begin + -- Enable privileged software access to default memory map + m4.mpu.MPU.CTRL.PRIVDEFENA := true; + + -- Enable the memory fault exception + m4.scb.SCB.SHCSR.MEMFAULTENA := true; + end init; + + + procedure configure_region + (region : in t_region_config) + is + begin + + -- Selects which memory region is referenced + MPU.RNR.REGION := region.region_number; + + -- Defines the base address of the MPU region + MPU.RBAR := + (VALID => false, + REGION => 0, + ADDR => address_to_bits_27 (region.addr)); + + -- Defines the region size and memory attributes + MPU.RASR := + (ENABLE => true, + SIZE => region.size, + SRD => 0, + B => region.b, + C => false, + S => region.S, + TEX => 0, + AP => region.access_perm, + XN => region.xn); + + end configure_region; + + + procedure disable_region + (region_number : in t_region_number) + is + begin + MPU.RNR.REGION := region_number; + MPU.RASR.ENABLE := false; + end disable_region; + + + procedure update_subregion_mask + (region : in t_region_config) + is + begin + -- Selects which memory region is referenced + MPU.RNR.REGION := region.region_number; + + -- Defines the region size and memory attributes + MPU.RASR.SRD := region.subregion_mask; + + end update_subregion_mask; + +end m4.mpu; diff --git a/arch/cores/armv7-m/Ada/m4-mpu.ads b/arch/cores/armv7-m/Ada/m4-mpu.ads new file mode 100644 index 0000000..5a42a01 --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-mpu.ads @@ -0,0 +1,313 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ada.unchecked_conversion; + +with m4.layout; +with m4.scb; + +package m4.mpu + with spark_mode => on +is + + ------------ + -- Config -- + ------------ + subtype t_region_number is unsigned_8 range 0 .. 7; + subtype t_region_size is bits_5 range 4 .. 31; + + type t_region_config is record + region_number : t_region_number; + addr : system_address; + size : t_region_size; + access_perm : bits_3; + xn : bool; + b : bool; + s : bool; + subregion_mask : unsigned_8; -- 0: sub-region enabled, 1: disabled + end record; + + REGION_SIZE_32B : constant t_region_size := 4; + REGION_SIZE_64B : constant t_region_size := 5; + REGION_SIZE_128B : constant t_region_size := 6; + REGION_SIZE_256B : constant t_region_size := 7; + REGION_SIZE_512B : constant t_region_size := 8; + REGION_SIZE_1KB : constant t_region_size := 9; + REGION_SIZE_2KB : constant t_region_size := 10; + REGION_SIZE_4KB : constant t_region_size := 11; + REGION_SIZE_8KB : constant t_region_size := 12; + REGION_SIZE_16KB : constant t_region_size := 13; + REGION_SIZE_32KB : constant t_region_size := 14; + REGION_SIZE_64KB : constant t_region_size := 15; + REGION_SIZE_128KB : constant t_region_size := 16; + REGION_SIZE_256KB : constant t_region_size := 17; + REGION_SIZE_512KB : constant t_region_size := 18; + REGION_SIZE_1MB : constant t_region_size := 19; + REGION_SIZE_2MB : constant t_region_size := 20; + REGION_SIZE_4MB : constant t_region_size := 21; + REGION_SIZE_8MB : constant t_region_size := 22; + REGION_SIZE_16MB : constant t_region_size := 23; + REGION_SIZE_32MB : constant t_region_size := 24; + REGION_SIZE_64MB : constant t_region_size := 25; + REGION_SIZE_128MB : constant t_region_size := 26; + REGION_SIZE_256MB : constant t_region_size := 27; + REGION_SIZE_512MB : constant t_region_size := 28; + REGION_SIZE_1GB : constant t_region_size := 29; + REGION_SIZE_2GB : constant t_region_size := 30; + REGION_SIZE_4GB : constant t_region_size := 31; + + -- Access Permissions + -- Note: Describes privileged and user access. + -- For example, REGION_AP_RW_NO means + -- - privileged : read/write access + -- - user : no access + + REGION_AP_NO_NO : constant bits_3 := 2#000#; + REGION_AP_RW_NO : constant bits_3 := 2#001#; + REGION_AP_RW_RO : constant bits_3 := 2#010#; + REGION_AP_RW_RW : constant bits_3 := 2#011#; + REGION_AP_UNUSED : constant bits_3 := 2#100#; + REGION_AP_RO_NO : constant bits_3 := 2#101#; + REGION_AP_RO_RO : constant bits_3 := 2#110#; + REGION_AP_RO_RO2 : constant bits_3 := 2#111#; + + --------------- + -- Functions -- + --------------- + + procedure is_mpu_available + (success : out boolean) + with + Global => (In_Out => MPU); + + procedure enable + with + global => (in_out => (MPU)); + + procedure disable + with + global => (in_out => (MPU)); + + procedure disable_region + (region_number : in t_region_number) + with + global => (in_out => (MPU)); + + -- Only used by SPARK prover + function region_not_rwx(region : t_region_config) return boolean + is (region.xn = true or + region.access_perm = REGION_AP_RO_RO or + region.access_perm = REGION_AP_NO_NO) + with ghost; + + procedure init + with + global => (in_out => (MPU, m4.scb.SCB)); + + -- That function is only used by SPARK prover + function get_region_size_mask (size : t_region_size) return unsigned_32 + is (2**(natural (size) + 1) - 1) + with ghost; + + procedure configure_region + (region : in t_region_config) + with + global => (in_out => (MPU)), + pre => + (region.region_number in 0 .. 7 + and + (region.addr and 2#11111#) = 0 + and + region.size >= 4 + and + (region.addr and get_region_size_mask(region.size)) = 0) + and region_not_rwx (region); + + procedure update_subregion_mask + (region : in t_region_config) + with + global => (in_out => (MPU)), + pre => + (region.region_number < 8 + and + (region.addr and 2#11111#) = 0 + and + region.size >= 4 + and + (region.addr and get_region_size_mask(region.size)) = 0) + and region_not_rwx (region); + + + ----------------------- + -- MPU Type Register -- + ----------------------- + + type t_MPU_TYPE is record + SEPARAT : bool := true; -- Support for separate instruction and date memory maps + DREGION : unsigned_8 := 8; -- Number of supported MPU data regions + IREGION : unsigned_8 := 0; -- Number of supported MPU instruction regions + end record + with size => 32; + + for t_MPU_TYPE use + record + SEPARAT at 0 range 0 .. 0; + DREGION at 0 range 8 .. 15; + IREGION at 0 range 16 .. 23; + end record; + + function to_unsigned_32 is new ada.unchecked_conversion + (t_MPU_TYPE, unsigned_32); + + -------------------------- + -- MPU Control Register -- + -------------------------- + + type t_MPU_CTRL is record + ENABLE : bool; -- Enables the MPU + HFNMIENA : bool; -- Enables the operation of MPU during hard fault, + -- NMI, and FAULTMASK handlers + PRIVDEFENA : bool; -- Enables privileged software access to the default + -- memory map + end record + with size => 32; + + for t_MPU_CTRL use record + ENABLE at 0 range 0 .. 0; + HFNMIENA at 0 range 1 .. 1; + PRIVDEFENA at 0 range 2 .. 2; + end record; + + -------------------------------- + -- MPU Region Number Register -- + -------------------------------- + + type t_MPU_RNR is record + REGION : unsigned_8 range 0 .. 7; -- Indicates the region referenced by + -- MPU_RBAR and MPU_RASR + end record + with size => 32; + + for t_MPU_RNR use record + REGION at 0 range 0 .. 7; + end record; + + -------------------------------------- + -- MPU Region Base Address Register -- + -------------------------------------- + + -- + -- Defines the base address of the MPU region selected by the MPU_RNR + -- + + type t_MPU_RBAR is record + REGION : bits_4 range 0 .. 7; + VALID : bool; + ADDR : bits_27; + end record + with size => 32; + + for t_MPU_RBAR use record + REGION at 0 range 0 .. 3; + VALID at 0 range 4 .. 4; + ADDR at 0 range 5 .. 31; + end record; + + function address_to_bits_27 (addr : system_address) + return bits_27 + with pre => (addr and 2#11111#) = 0; + + -------------------------------------------- + -- MPU Region Attribute and Size Register -- + -------------------------------------------- + + type t_MPU_RASR is record + ENABLE : bool; -- Enable region + SIZE : t_region_size; + SRD : unsigned_8; -- Subregion disable bits (0 = enabled, 1 = disabled) + B : bool; + C : bool; + S : bool; -- Shareable + TEX : bits_3; -- Memory attributes + AP : bits_3; -- Permissions + XN : bool; -- Instruction fetches disabled + end record + with size => 32; + + for t_MPU_RASR use record + ENABLE at 0 range 0 .. 0; + SIZE at 0 range 1 .. 5; + SRD at 0 range 8 .. 15; + B at 0 range 16 .. 16; + C at 0 range 17 .. 17; + S at 0 range 18 .. 18; + TEX at 0 range 19 .. 21; + AP at 0 range 24 .. 26; + XN at 0 range 28 .. 28; + end record; + + function to_MPU_RASR is new ada.unchecked_conversion + (unsigned_32, t_MPU_RASR); + + -------------------- + -- MPU peripheral -- + -------------------- + + type t_MPU_peripheral is record + TYPER : t_MPU_TYPE; + CTRL : t_MPU_CTRL; + RNR : t_MPU_RNR; + RBAR : t_MPU_RBAR; + RASR : t_MPU_RASR; + RBAR_A1 : t_MPU_RBAR; + RASR_A1 : t_MPU_RASR; + RBAR_A2 : t_MPU_RBAR; + RASR_A2 : t_MPU_RASR; + RBAR_A3 : t_MPU_RBAR; + RASR_A3 : t_MPU_RASR; + end record; + + for t_MPU_peripheral use record + TYPER at 16#00# range 0 .. 31; + CTRL at 16#04# range 0 .. 31; + RNR at 16#08# range 0 .. 31; + RBAR at 16#0C# range 0 .. 31; + RASR at 16#10# range 0 .. 31; + RBAR_A1 at 16#14# range 0 .. 31; + RASR_A1 at 16#18# range 0 .. 31; + RBAR_A2 at 16#1C# range 0 .. 31; + RASR_A2 at 16#20# range 0 .. 31; + RBAR_A3 at 16#24# range 0 .. 31; + RASR_A3 at 16#28# range 0 .. 31; + end record; + + ---------------- + -- Peripheral -- + ---------------- + + MPU : t_MPU_peripheral + with + import, + volatile, + address => m4.layout.MPU_base; + +end m4.mpu; diff --git a/arch/cores/armv7-m/Ada/m4-scb.adb b/arch/cores/armv7-m/Ada/m4-scb.adb new file mode 100644 index 0000000..5f79fa4 --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-scb.adb @@ -0,0 +1,44 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with m4.cpu.instructions; + +package body m4.scb + with spark_mode => on +is + + procedure reset + is + aircr_value : t_SCB_AIRCR; + begin + aircr_value := SCB.AIRCR; + aircr_value.VECTKEY := 16#5FA#; + aircr_value.SYSRESETREQ := 1; + m4.cpu.instructions.DSB; + SCB.AIRCR := aircr_value; + m4.cpu.instructions.DSB; + loop + null; -- Wait until reset + end loop; + end reset; + +end m4.scb; diff --git a/arch/cores/armv7-m/Ada/m4-scb.ads b/arch/cores/armv7-m/Ada/m4-scb.ads new file mode 100644 index 0000000..578513a --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-scb.ads @@ -0,0 +1,347 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ada.unchecked_conversion; +with m4.layout; + +package m4.scb + with spark_mode => on +is + + ------------------------------------------ + -- Interrupt Control and State Register -- + ------------------------------------------ + + type t_SCB_ICSR is record + VECTACTIVE : bits_9; + RETTOBASE : bit; + VECTPENDING : bits_10; + ISRPENDING : boolean; + PENDSTCLR : bit; + PENDSTSET : bit; + PENDSVCLR : bit; + PENDSVSET : bit; + NMIPENDSET : bit; + end record + with size => 32; + + for t_SCB_ICSR use record + VECTACTIVE at 0 range 0 .. 8; + RETTOBASE at 0 range 11 .. 11; + VECTPENDING at 0 range 12 .. 21; + ISRPENDING at 0 range 22 .. 22; + PENDSTCLR at 0 range 25 .. 25; + PENDSTSET at 0 range 26 .. 26; + PENDSVCLR at 0 range 27 .. 27; + PENDSVSET at 0 range 28 .. 28; + NMIPENDSET at 0 range 31 .. 31; + end record; + + ------------------------------------------------------ + -- Application interrupt and reset control register -- + ------------------------------------------------------ + + type t_SCB_AIRCR is record + VECTKEY : unsigned_16; + ENDIANESS : bit; + reserved_11_14 : bits_4; + PRIGROUP : bits_3; + reserved_3_7 : bits_5; + SYSRESETREQ : bit; + VECTCLRACTIVE : bit; + VECTRESET : bit; + end record + with size => 32; + + for t_SCB_AIRCR use record + VECTKEY at 0 range 16 .. 31; + ENDIANESS at 0 range 15 .. 15; + reserved_11_14 at 0 range 11 .. 14; + PRIGROUP at 0 range 8 .. 10; + reserved_3_7 at 0 range 3 .. 7; + SYSRESETREQ at 0 range 2 .. 2; + VECTCLRACTIVE at 0 range 1 .. 1; + VECTRESET at 0 range 0 .. 0; + end record; + + ---------------------------------------------- + -- Configuration and control register (CCR) -- + ---------------------------------------------- + + -- The CCR controls entry to Thread mode + type t_SCB_CCR is record + NONBASETHRDENA : boolean; -- If true, processor can enter Thread mode + -- from any level under the control of an + -- EXC_RETURN + USERSETMPEND : boolean; + UNALIGN_TRP : boolean; + DIV_0_TRP : boolean; + BFHFNMIGN : boolean; + STKALIGN : boolean; + end record + with size => 32; + + for t_SCB_CCR use record + NONBASETHRDENA at 0 range 0 .. 0; + USERSETMPEND at 0 range 1 .. 1; + UNALIGN_TRP at 0 range 3 .. 3; + DIV_0_TRP at 0 range 4 .. 4; + BFHFNMIGN at 0 range 8 .. 8; + STKALIGN at 0 range 9 .. 9; + end record; + + ----------------------------------------------- + -- System handler priority registers (SHPRx) -- + ----------------------------------------------- + + type t_priority is record + reserved : bits_4; + priority : bits_4; + end record + with pack, size => 8; + + -- SHPR1 + + type t_SCB_SHPR1 is record + mem_fault : t_priority; + bus_fault : t_priority; + usage_fault : t_priority; + end record + with size => 32; + + for t_SCB_SHPR1 use record + mem_fault at 0 range 0 .. 7; + bus_fault at 0 range 8 .. 15; + usage_fault at 0 range 16 .. 23; + end record; + + -- SHPR2 + + type t_SCB_SHPR2 is record + svc_call : t_priority; + end record + with size => 32; + + for t_SCB_SHPR2 use record + svc_call at 0 range 24 .. 31; + end record; + + -- SHPR3 + + type t_SCB_SHPR3 is record + pendsv : t_priority; + systick : t_priority; + end record + with size => 32; + + for t_SCB_SHPR3 use record + pendsv at 0 range 16 .. 23; + systick at 0 range 24 .. 31; + end record; + + ----------------------------------------------- + -- System Handler Control and State Register -- + ----------------------------------------------- + + type t_SCB_SHCSR is record + MEMFAULTACT : boolean; -- MemManage exception active + BUSFAULTACT : boolean; -- BusFault exception active + reserved_3 : bit; + USGFAULTACT : boolean; -- UsageFault exception active + reserved_4_6 : bits_3; + SVCALLACT : boolean; -- SVCall active + MONITORACT : boolean; -- Debug monitor active + reserved_9 : bit; + PENDSVACT : boolean; -- PendSV exception active + SYSTICKACT : boolean; -- SysTick exception active + USGFAULTPENDED : boolean; -- UsageFault pending + MEMFAULTPENDED : boolean; -- MemManage pending + BUSFAULTPENDED : boolean; -- BusFault pending + SVCALLPENDED : boolean; -- SVCall pending + MEMFAULTENA : boolean; -- MemManage enable + BUSFAULTENA : boolean; -- BusFault enable + USGFAULTENA : boolean; -- UsageFault enable + end record + with size => 32; + + for t_SCB_SHCSR use record + MEMFAULTACT at 0 range 0 .. 0; + BUSFAULTACT at 0 range 1 .. 1; + reserved_3 at 0 range 2 .. 2; + USGFAULTACT at 0 range 3 .. 3; + reserved_4_6 at 0 range 4 .. 6; + SVCALLACT at 0 range 7 .. 7; + MONITORACT at 0 range 8 .. 8; + reserved_9 at 0 range 9 .. 9; + PENDSVACT at 0 range 10 .. 10; + SYSTICKACT at 0 range 11 .. 11; + USGFAULTPENDED at 0 range 12 .. 12; + MEMFAULTPENDED at 0 range 13 .. 13; + BUSFAULTPENDED at 0 range 14 .. 14; + SVCALLPENDED at 0 range 15 .. 15; + MEMFAULTENA at 0 range 16 .. 16; + BUSFAULTENA at 0 range 17 .. 17; + USGFAULTENA at 0 range 18 .. 18; + end record; + + ---------------------------------------- + -- Configurable Fault Status Register -- + ---------------------------------------- + + -- + -- Memory Management Fault Status Register + -- + + type t_MMFSR is record + IACCVIOL : boolean; + DACCVIOL : boolean; + reserved_2 : bit; + MUNSTKERR : boolean; + MSTKERR : boolean; + MLSPERR : boolean; + reserved_6 : bit; + MMARVALID : boolean; + end record + with size => 8; + pragma pack (t_MMFSR); + + -- + -- Bus Fault Status Register + -- + + type t_BFSR is record + IBUSERR : boolean; + PRECISERR : boolean; + IMPRECISERR : boolean; + UNSTKERR : boolean; + STKERR : boolean; + LSPERR : boolean; + reserved_6 : bit; + BFARVALID : boolean; + end record + with size => 8; + pragma pack (t_BFSR); + + -- + -- Usage Fault Status Register + -- + + type t_UFSR is record + UNDEFINSTR : boolean; + INVSTATE : boolean; + INVPC : boolean; + NOCP : boolean; + UNALIGNED : boolean; + DIVBYZERO : boolean; + end record + with size => 16; + + for t_UFSR use record + UNDEFINSTR at 0 range 0 .. 0; + INVSTATE at 0 range 1 .. 1; + INVPC at 0 range 2 .. 2; + NOCP at 0 range 3 .. 3; + UNALIGNED at 0 range 8 .. 8; + DIVBYZERO at 0 range 9 .. 9; + end record; + + type t_SCB_CFSR is record + MMFSR : t_MMFSR; + BFSR : t_BFSR; + UFSR : t_UFSR; + end record + with size => 32; + + function to_unsigned_32 is new ada.unchecked_conversion + (t_SCB_CFSR, unsigned_32); + + -------------------------------- + -- Hard fault status register -- + -------------------------------- + + type t_SCB_HFSR is record + VECTTBL : boolean; -- Vector table hard fault + FORCED : boolean; -- Forced hard fault + DEBUG_VT : bit; -- Reserved for Debug use + end record + with size => 32; + + for t_SCB_HFSR use record + VECTTBL at 0 range 1 .. 1; + FORCED at 0 range 30 .. 30; + DEBUG_VT at 0 range 31 .. 31; + end record; + + -------------------------------------- + -- MemManage Fault Address Register -- + -------------------------------------- + + type t_SCB_MMFAR is record + ADDRESS : system_address; + end record + with size => 32; + + -------------------- + -- SCB peripheral -- + -------------------- + + -- /!\ ACTLR register is not in the same record + + type t_SCB_peripheral is record + ICSR : t_SCB_ICSR; + AIRCR : t_SCB_AIRCR; + CCR : t_SCB_CCR; + SHPR1 : t_SCB_SHPR1; + SHPR2 : t_SCB_SHPR2; + SHPR3 : t_SCB_SHPR3; + SHCSR : t_SCB_SHCSR; + CFSR : t_SCB_CFSR; + HFSR : t_SCB_HFSR; + MMFAR : t_SCB_MMFAR; + end record; + + for t_SCB_peripheral use record + ICSR at 16#04# range 0 .. 31; + AIRCR at 16#0C# range 0 .. 31; + CCR at 16#14# range 0 .. 31; + SHPR1 at 16#18# range 0 .. 31; + SHPR2 at 16#1C# range 0 .. 31; + SHPR3 at 16#20# range 0 .. 31; + SHCSR at 16#24# range 0 .. 31; + CFSR at 16#28# range 0 .. 31; + HFSR at 16#2C# range 0 .. 31; + MMFAR at 16#34# range 0 .. 31; + end record; + + ----------------- + -- Peripherals -- + ----------------- + + SCB : t_SCB_peripheral + with + import, + volatile, + address => m4.layout.SCB_base2; + + procedure reset; + +end m4.scb; diff --git a/arch/cores/armv7-m/Ada/m4-systick.adb b/arch/cores/armv7-m/Ada/m4-systick.adb new file mode 100644 index 0000000..3e7514c --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-systick.adb @@ -0,0 +1,95 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package body m4.systick + with spark_mode => on +is + + procedure init + is + begin + SYSTICK.LOAD.RELOAD := bits_24 + (MAIN_CLOCK_FREQUENCY / TICKS_PER_SECOND); + SYSTICK.VAL.CURRENT := 0; + SYSTICK.CTRL := (ENABLE => true, + TICKINT => true, + CLKSOURCE => PROCESSOR_CLOCK, + COUNTFLAG => 0); + end init; + + + procedure increment + is + current : constant t_tick := ticks; + begin + ticks := current + 1; + end increment; + + + function get_ticks return unsigned_64 + is + current : constant t_tick := ticks; + begin + return unsigned_64 (current); + end get_ticks; + + + function to_milliseconds (t : t_tick) + return milliseconds + is + begin + return t * (1000 / TICKS_PER_SECOND); + end to_milliseconds; + + + function to_microseconds (t : t_tick) + return microseconds + is + begin + return t * (1000000 / TICKS_PER_SECOND); + end to_microseconds; + + + function to_ticks (ms : milliseconds) return t_tick + is + begin + return ms * TICKS_PER_SECOND / 1000; + end to_ticks; + + + function get_milliseconds return milliseconds + is + current : constant t_tick := ticks; + begin + return to_milliseconds (current); + end get_milliseconds; + + + function get_microseconds return microseconds + is + current : constant t_tick := ticks; + begin + return to_microseconds (current); + end get_microseconds; + +end m4.systick; diff --git a/arch/cores/armv7-m/Ada/m4-systick.ads b/arch/cores/armv7-m/Ada/m4-systick.ads new file mode 100644 index 0000000..49fc381 --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4-systick.ads @@ -0,0 +1,170 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with m4.layout; + +package m4.systick + with spark_mode => on +is + + -- FIXME - Should be defined in arch/boards + MAIN_CLOCK_FREQUENCY : constant := 168_000_000; + TICKS_PER_SECOND : constant := 1000; + + subtype t_tick is unsigned_64; + + ---------------------------------------------------- + -- SysTick control and status register (STK_CTRL) -- + ---------------------------------------------------- + + type t_clock_type is + (EXT_CLOCK, PROCESSOR_CLOCK) + with size => 1; + + for t_clock_type use + (EXT_CLOCK => 0, PROCESSOR_CLOCK => 1); + + type t_STK_CTRL is record + ENABLE : boolean; -- Enables the counter + TICKINT : boolean; -- Enables exception request + CLKSOURCE : t_clock_type; + COUNTFLAG : bit; + end record + with size => 32, volatile_full_access; + + for t_STK_CTRL use record + ENABLE at 0 range 0 .. 0; + TICKINT at 0 range 1 .. 1; + CLKSOURCE at 0 range 2 .. 2; + COUNTFLAG at 0 range 16 .. 16; + end record; + + ---------------------------------------------- + -- SysTick reload value register (STK_LOAD) -- + ---------------------------------------------- + + -- Note: To generate a timer with a period of N processor clock + -- cycles, use a RELOAD value of N-1. + + type t_STK_LOAD is record + RELOAD : bits_24; + end record + with size => 32, volatile_full_access; + + ---------------------------------------------- + -- SysTick current value register (STK_VAL) -- + ---------------------------------------------- + + type t_STK_VAL is record + CURRENT : bits_24; + end record + with size => 32, volatile_full_access; + + ---------------------------------------------------- + -- SysTick calibration value register (STK_CALIB) -- + ---------------------------------------------------- + + type t_STK_CALIB is record + TENMS : bits_24; + SKEW : bit; + NOREF : bit; + end record + with size => 32, volatile_full_access; + + for t_STK_CALIB use record + TENMS at 0 range 0 .. 23; + SKEW at 0 range 30 .. 30; + NOREF at 0 range 31 .. 31; + end record; + + ---------------- + -- Peripheral -- + ---------------- + + type t_SYSTICK_peripheral is record + CTRL : t_STK_CTRL; + LOAD : t_STK_LOAD; + VAL : t_STK_VAL; + CALIB : t_STK_CALIB; + end record + with volatile; + + for t_SYSTICK_peripheral use record + CTRL at 16#00# range 0 .. 31; + LOAD at 16#04# range 0 .. 31; + VAL at 16#08# range 0 .. 31; + CALIB at 16#0C# range 0 .. 31; + end record; + + SYSTICK : t_SYSTICK_peripheral + with + import, + volatile, + address => m4.layout.SYS_TIMER_base; + + --------------- + -- Functions -- + --------------- + + -- Initialize the systick module + procedure init + with + convention => c, + export => true, + external_name => "core_systick_init"; + + -- Get the number of milliseconds elapsed since booting + function get_ticks return unsigned_64 + with + volatile_function, + convention => c, + export => true, + external_name => "core_systick_get_ticks"; + + function get_milliseconds return milliseconds + with + volatile_function; + + + function get_microseconds return microseconds + with + volatile_function; + + function to_ticks (ms : milliseconds) return t_tick + with inline; + + function to_milliseconds (t : t_tick) return milliseconds + with inline; + + function to_microseconds (t : t_tick) return microseconds + with inline; + + -- Note: default Systick IRQ handler is defined in package + -- ewok.interrupts.handler and call 'increment' procedure + procedure increment; + +private + + ticks : t_tick + with volatile, async_writers; + +end m4.systick; diff --git a/arch/cores/armv7-m/Ada/m4.ads b/arch/cores/armv7-m/Ada/m4.ads new file mode 100644 index 0000000..87b12a2 --- /dev/null +++ b/arch/cores/armv7-m/Ada/m4.ads @@ -0,0 +1,37 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +pragma Restrictions (No_Elaboration_Code); + +pragma warnings (Off, "use clause for package"); +-- distribute interfaces and types to child packages + +with interfaces; use interfaces; +pragma unreferenced (interfaces); + +with types; use types; +pragma unreferenced (types); + +pragma warnings (On, "use clause for package"); + +Package m4 is +end m4; diff --git a/arch/cores/armv7-m/Makefile.objs b/arch/cores/armv7-m/Makefile.objs new file mode 100644 index 0000000..7a6cbd0 --- /dev/null +++ b/arch/cores/armv7-m/Makefile.objs @@ -0,0 +1,25 @@ +CORE_DIR = $(PROJ_FILES)/kernel/arch/cores/$(ARCH) + +CFLAGS += -I$(CORE_DIR) + +# core content is only in BSP by now (not in userspace drivers) +core-bsp-y := + +# mandatory +core-bsp-y += m4-mpu.c +core-bsp-y += m4-systick.c + +# configurable + +# per app +# no need for FPU for loader +core-bsp-$(CONFIG_FPU_ENABLE) += m4-fpu.c + +core-ada-bsp-y := +ifeq ($(CONFIG_ADAKERNEL),y) +# for Ada equivalent + +core-ada-bsp-y += Ada/m4-mpu.adb +core-ada-bsp-y += Ada/m4-systick.adb + +endif diff --git a/arch/cores/armv7-m/m4-core.h b/arch/cores/armv7-m/m4-core.h new file mode 100644 index 0000000..e75af0e --- /dev/null +++ b/arch/cores/armv7-m/m4-core.h @@ -0,0 +1,48 @@ +/* \file m4-core.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef M4_CORE_ +#define M4_CORE_ + +#define MAIN_CLOCK_FREQUENCY 168000000 +#define MAIN_CLOCK_FREQUENCY_MS 168000 +#define MAIN_CLOCK_FREQUENCY_US 168 + +#define INITIAL_STACK 0x1000b000 + +#define INT_STACK_BASE KERN_STACK_BASE - 8192 /* same for FIQ & IRQ by now */ +#define ABT_STACK_BASE INT_STACK_BASE - 4096 +#define SYS_STACK_BASE ABT_STACK_BASE - 4096 +#define UDF_STACK_BASE SYS_STACK_BASE - 4096 + +#define MODE_CLEAR 0xffffffe0 + +static inline void core_processor_init_modes(void) +{ + /* + * init msp for kernel, this is needed in order to make IT return to SVC mode + * in thread mode (LR=0xFFFFFFF9) working (loading the good msp value from the SPSR) + */ + asm volatile ("msr msp, %0\n\t"::"r" (INITIAL_STACK):); +} + +#endif /*!M4_CORE_ */ diff --git a/arch/cores/armv7-m/m4-cpu.h b/arch/cores/armv7-m/m4-cpu.h new file mode 100644 index 0000000..95c566d --- /dev/null +++ b/arch/cores/armv7-m/m4-cpu.h @@ -0,0 +1,203 @@ +/* \file m4-cpu.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef M4_CPU +#define M4_CPU + +#include "types.h" + +__INLINE __attribute__ ((always_inline)) +void core_write_psp(void *ptr) +{ + asm volatile ("MSR psp, %0\n\t"::"r" (ptr)); +} + +__INLINE __attribute__ ((always_inline)) +void core_write_msp(void *ptr) +{ + asm volatile ("MSR msp, %0\n\t"::"r" (ptr)); +} + +__INLINE __attribute__ ((always_inline)) +void *core_read_psp(void) +{ + void *result = NULL; + asm volatile ("MRS %0, psp\n\t":"=r" (result)); + return (result); +} + +__INLINE __attribute__ ((always_inline)) +void *core_read_msp(void) +{ + void *result = NULL; + asm volatile ("MRS %0, msp\n\t":"=r" (result)); + return (result); +} + +__INLINE __attribute__ ((always_inline)) +void enable_irq(void) +{ + __ASM volatile ("cpsie i; isb":::"memory"); +} + +__INLINE __attribute__ ((always_inline)) +void disable_irq(void) +{ + __ASM volatile ("cpsid i":::"memory"); + +} + +__INLINE __attribute__ ((always_inline)) +void full_memory_barrier(void) +{ + __ASM volatile ("dsb; isb":::); +} + +__INLINE __attribute__ ((always_inline)) +uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control":"=r" (result)); + return (result); +} + +__INLINE __attribute__ ((always_inline)) +void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0"::"r" (control)); +} + +__INLINE __attribute__ ((always_inline)) +uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr":"=r" (result)); + return (result); +} + +__INLINE __attribute__ ((always_inline)) +uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr":"=r" (result)); + return (result); +} + +__INLINE __attribute__ ((always_inline)) +uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr":"=r" (result)); + return (result); +} + +__INLINE __attribute__ ((always_inline)) +uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask":"=r" (result)); + return (result); +} + +__INLINE __attribute__ ((always_inline)) +void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0"::"r" (priMask)); +} + +__INLINE void wait_for_interrupt(void) +{ + asm volatile ("wfi"); +} + +#if defined(__CC_ARM) +/* No Operation */ +#define __NOP __nop +/* Instruction Synchronization Barrier */ +#define __ISB() __isb(0xF) +/* Data Synchronization Barrier */ +#define __DSB() __dsb(0xF) +/* Data Memory Barrier */ +#define __DMB() __dmb(0xF) +/* Reverse byte order (32 bit) */ +#define __REV __rev +/* Reverse byte order (16 bit) */ +static __INLINE __ASM uint32_t __REV16(uint32_t value) +{ +rev16 r0, r0 bx lr} +/* Breakpoint */ +#define __BKPT __bkpt +#elif defined(__GNUC__) + +static inline __attribute__ ((always_inline)) +void __NOP(void) +{ + __asm__ volatile ("nop"); +} + +static inline __attribute__ ((always_inline)) +void __ISB(void) +{ + __asm__ volatile ("isb"); +} + +static inline __attribute__ ((always_inline)) +void __DSB(void) +{ + __asm__ volatile ("dsb"); +} + +static inline __attribute__ ((always_inline)) +void __DMB(void) +{ + __asm__ volatile ("dmb"); +} + +static inline __attribute__ ((always_inline)) +uint32_t __REV(uint32_t value) +{ + uint32_t result; + __asm__ volatile ("rev %0, %1":"=r" (result):"r"(value)); + return result; +} + +static inline __attribute__ ((always_inline)) +uint32_t __REV16(uint32_t value) +{ + uint32_t result; + __asm__ volatile ("rev16 %0, %1":"=r" (result):"r"(value)); + return result; +} + +static inline __attribute__ ((always_inline)) +void __BKPT(void) +{ + __asm__ volatile ("bkpt"); +} +#endif + +#endif /*!M4_CPU */ diff --git a/arch/cores/armv7-m/m4-fpu.c b/arch/cores/armv7-m/m4-fpu.c new file mode 100644 index 0000000..3f718dd --- /dev/null +++ b/arch/cores/armv7-m/m4-fpu.c @@ -0,0 +1,125 @@ +/* \file m4-fpu.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "soc-core.h" +#include "soc-irq.h" +#include "autoconf.h" + +#ifdef CONFIG_FPU_ENABLE_ALL +#define FPU_ACCESS_MODE 0xF +#elif defined CONFIG_FPU_ENABLE_PRIVILEGIED +#define FPU_ACCESS_MODE 0x5 +#endif + +#if (__FPU_PRESENT == 1) + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register + \return the current register value + */ +static inline uint32_t get_fpscr(void) +{ + register uint32_t regfpscr = 0; + asm volatile ("vmrs %0, fpscr ":"=r" (regfpscr)); + return (regfpscr); +} + +/** + \brief Set FPSCR + \details Assigns the parameter to the Floating Point Status/Control register + \param Floating Point Status/Control value to set + */ +static inline void set_fpscr(uint32_t fpscr) +{ + asm volatile ("vmsr fpscr, %0 "::"r" (fpscr)); +} + +/* + * This fpu Exception flag handler doesn't support FPU context save/restore, which means + * that an ISR (or a preemptive task) can't use the FPU. + * TODO: A support for save/restore mode need to be added here. Only Lazy (FIXME: to test) is + * written here + */ + +#ifdef CONFIG_FPU_NOSAVE +static inline void fpu_handler(void) +{ + uint32_t fpscr_val = get_fpscr(); + + //{ check exception flags... something to check? } + // Clear all exception flags... just clearning by now + fpscr_val &= (uint32_t) ~ 0x8F; + set_fpscr(fpscr_val); +} +#endif + +#ifdef CONFIG_FPU_LAZY +static inline void fpu_handler(void) +{ + register uint32_t reg_val = 0; + register uint32_t fpscr_val = get_fpscr(); // dummy + struct FPU *fpuregs = FPU_SYSREG_BASE; + + // update the location of the unpopulated fp register space in the exception stack + reg_val = *(volatile uint32_t *)(FPU->FPCAR + 0x40); + //{ check exception flags } + fpscr_val &= (uint32_t) ~ 0x8F; + *(__IO uint32_t *) (FPU->FPCAR + 0x40) = reg_val; + full_memory_barrier(); +} +#endif + +/* + Case of full FPU context saving: + + TODO: for scheduling time: the scheduler must check if the FPSCR flags is set. If yes, + the FPU context (reg S0-S32 + SCR or S16-S32 + SCR in case of lazy) must be pushed in + the caller stack. Before scheduling the next task, the scheduler must check if there is + an FPU context in the stack. If yes, this context must be restored. +*/ + +void fpu_enable(void) +{ +#if CONFIG_FPU_ENABLE + uint32_t r_cpacr = CPACR_BASE; + uint32_t value = read_reg_value(&r_cpacr); + +#if CONFIG_FPU_LAZY + struct FPU *fpuregs = FPU_SYSREG_BASE; + + /* activate LSPEN for Lazy auto saving */ + fpuregs->FPCCR |= FPU_FPCCR_LSPEN_Msk; +#endif + /* register FPU IRQ handler */ + irq_handler_set(FPU_IRQ, fpu_handler, 0, ID_DEV_UNUSED); + /* Enable CP10 & CP 11 */ + value |= (FPU_ACCESS_MODE << 20); + + write_reg_value(&r_cpacr, value); + full_memory_barrier(); +#endif +} + + +#endif diff --git a/arch/cores/armv7-m/m4-fpu.h b/arch/cores/armv7-m/m4-fpu.h new file mode 100644 index 0000000..2246988 --- /dev/null +++ b/arch/cores/armv7-m/m4-fpu.h @@ -0,0 +1,83 @@ +/* \file m4-fpu.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef M4_FPU_H_ +#define M4_FPU_H_ + +#define FPU_SYSREG_BASE 0xE000EF30 + +/* Floating-Point Context Control Register */ +#define FPU_FPCCR_ASPEN_Pos 31 /*!< FPCCR: ASPEN bit Position */ +#define FPU_FPCCR_ASPEN_Msk (1UL << FPU_FPCCR_ASPEN_Pos) /*!< FPCCR: ASPEN bit Mask */ + +#define FPU_FPCCR_LSPEN_Pos 30 /*!< FPCCR: LSPEN Position */ +#define FPU_FPCCR_LSPEN_Msk (1UL << FPU_FPCCR_LSPEN_Pos) /*!< FPCCR: LSPEN bit Mask */ + +#define FPU_FPCCR_MONRDY_Pos 8 /*!< FPCCR: MONRDY Position */ +#define FPU_FPCCR_MONRDY_Msk (1UL << FPU_FPCCR_MONRDY_Pos) /*!< FPCCR: MONRDY bit Mask */ + +#define FPU_FPCCR_BFRDY_Pos 6 /*!< FPCCR: BFRDY Position */ +#define FPU_FPCCR_BFRDY_Msk (1UL << FPU_FPCCR_BFRDY_Pos) /*!< FPCCR: BFRDY bit Mask */ + +#define FPU_FPCCR_MMRDY_Pos 5 /*!< FPCCR: MMRDY Position */ +#define FPU_FPCCR_MMRDY_Msk (1UL << FPU_FPCCR_MMRDY_Pos) /*!< FPCCR: MMRDY bit Mask */ + +#define FPU_FPCCR_HFRDY_Pos 4 /*!< FPCCR: HFRDY Position */ +#define FPU_FPCCR_HFRDY_Msk (1UL << FPU_FPCCR_HFRDY_Pos) /*!< FPCCR: HFRDY bit Mask */ + +#define FPU_FPCCR_THREAD_Pos 3 /*!< FPCCR: processor mode bit Position */ +#define FPU_FPCCR_THREAD_Msk (1UL << FPU_FPCCR_THREAD_Pos) /*!< FPCCR: processor mode active bit Mask */ + +#define FPU_FPCCR_USER_Pos 1 /*!< FPCCR: privilege level bit Position */ +#define FPU_FPCCR_USER_Msk (1UL << FPU_FPCCR_USER_Pos) /*!< FPCCR: privilege level bit Mask */ + +#define FPU_FPCCR_LSPACT_Pos 0 /*!< FPCCR: Lazy state preservation active bit Position */ +#define FPU_FPCCR_LSPACT_Msk (1UL << FPU_FPCCR_LSPACT_Pos) /*!< FPCCR: Lazy state preservation active bit Mask */ + +/* Floating-Point Context Address Register */ +#define FPU_FPCAR_ADDRESS_Pos 3 /*!< FPCAR: ADDRESS bit Position */ +#define FPU_FPCAR_ADDRESS_Msk (0x1FFFFFFFUL << FPU_FPCAR_ADDRESS_Pos) /*!< FPCAR: ADDRESS bit Mask */ + +/* Floating-Point Default Status Control Register */ +#define FPU_FPDSCR_AHP_Pos 26 /*!< FPDSCR: AHP bit Position */ +#define FPU_FPDSCR_AHP_Msk (1UL << FPU_FPDSCR_AHP_Pos) /*!< FPDSCR: AHP bit Mask */ + +#define FPU_FPDSCR_DN_Pos 25 /*!< FPDSCR: DN bit Position */ +#define FPU_FPDSCR_DN_Msk (1UL << FPU_FPDSCR_DN_Pos) /*!< FPDSCR: DN bit Mask */ + +#define FPU_FPDSCR_FZ_Pos 24 /*!< FPDSCR: FZ bit Position */ +#define FPU_FPDSCR_FZ_Msk (1UL << FPU_FPDSCR_FZ_Pos) /*!< FPDSCR: FZ bit Mask */ + +#define FPU_FPDSCR_RMode_Pos 22 /*!< FPDSCR: RMode bit Position */ +#define FPU_FPDSCR_RMode_Msk (3UL << FPU_FPDSCR_RMode_Pos) /*!< FPDSCR: RMode bit Mask */ + +/* FPU sysregs structure */ +struct FPU { + uint32_t reserved[1]; + volatile uint32_t FPCCR; + volatile uint32_t FPCAR; + volatile uint32_t FPDSCR; +} __attribute__ ((packed)); + +void fpu_enable(void); + +#endif /*!M4_FPU_H_ */ diff --git a/arch/cores/armv7-m/m4-mpu-regions.h b/arch/cores/armv7-m/m4-mpu-regions.h new file mode 100644 index 0000000..b40eb7e --- /dev/null +++ b/arch/cores/armv7-m/m4-mpu-regions.h @@ -0,0 +1,80 @@ +/* \file m4-mpu-regions.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef M4_MPU_REGIONS +# define M4_MPU_REGIONS + +/* MPU access permission attributes */ + +/* This section describes the MPU access permission attributes. The access permission bits +* TEX C B S AP and XN of the MPU_RASR register control access to the corresponding +* memory region. If an access is made to an area of memory without the required +* permissions then the MPU generates a permission fault. +*/ +#define MPU_REGION_XN ((uint32_t) 0x01) /* Instruction access disable bit */ +#define MPU_REGION_NO_NO ((uint32_t) 0x00) /* All access => permissions fault */ +#define MPU_REGION_RW_NO ((uint32_t) 0x01) /* Access from privileged soft only */ +#define MPU_REGION_RW_RO ((uint32_t) 0x02) /* Write by user mode app => permissions fault */ +#define MPU_REGION_RW_RW ((uint32_t) 0x03) /* Full access for every one */ +#define MPU_REGION_UK_UK ((uint32_t) 0x04) /* Reserved */ +#define MPU_REGION_RO_NO ((uint32_t) 0x05) /* Read by privileged soft only */ +#define MPU_REGION_RO_RO ((uint32_t) 0x06) /* Read only for every one */ +//#define #define MPU_REGION_RO_RO = ((uint32_t) 0x07) /* Read only for every one */ +/* SIZE field values */ + +#define MPU_PERMISSION_NO ((uint32_t) 0x00) +#define MPU_PERMISSION_YES ((uint32_t) 0x01) + +/* The SIZE field defines the size of the MPU memory region specified by the MPU_RNR register as follows: +* (Region size in bytes) = 2(SIZE+1) +* The smallest permitted region size is 32B corresponding to a SIZE value of 4 +*/ +#define MPU_REGION_SIZE_32b 4 +#define MPU_REGION_SIZE_64b 5 +#define MPU_REGION_SIZE_128b 6 +#define MPU_REGION_SIZE_256b 7 +#define MPU_REGION_SIZE_512b 8 +#define MPU_REGION_SIZE_1Kb 9 +#define MPU_REGION_SIZE_2Kb 10 +#define MPU_REGION_SIZE_4Kb 11 +#define MPU_REGION_SIZE_8Kb 12 +#define MPU_REGION_SIZE_16Kb 13 +#define MPU_REGION_SIZE_32Kb 14 +#define MPU_REGION_SIZE_64Kb 15 +#define MPU_REGION_SIZE_128Kb 16 +#define MPU_REGION_SIZE_256Kb 17 +#define MPU_REGION_SIZE_512Kb 18 +#define MPU_REGION_SIZE_1Mb 19 +#define MPU_REGION_SIZE_2Mb 20 +#define MPU_REGION_SIZE_4Mb 21 +#define MPU_REGION_SIZE_8Mb 22 +#define MPU_REGION_SIZE_16Mb 23 +#define MPU_REGION_SIZE_32Mb 24 +#define MPU_REGION_SIZE_64Mb 25 +#define MPU_REGION_SIZE_128Mb 26 +#define MPU_REGION_SIZE_256Mb 27 +#define MPU_REGION_SIZE_512Mb 28 +#define MPU_REGION_SIZE_1Gb 29 +#define MPU_REGION_SIZE_2Gb 30 +#define MPU_REGION_SIZE_4Gb 31 + +#endif/*!M4_MPU_REGIONS*/ diff --git a/arch/cores/armv7-m/m4-mpu.c b/arch/cores/armv7-m/m4-mpu.c new file mode 100644 index 0000000..15a0628 --- /dev/null +++ b/arch/cores/armv7-m/m4-mpu.c @@ -0,0 +1,206 @@ +/* m4-mpu.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** @file m4-mpu.c + * Handles MPU utilization. + * + * See PM0214 (DocID022708 Rev 5) + * and AN4838 (DocID029037 Rev 1) + */ + +#include "autoconf.h" +#include "product.h" +#include "debug.h" + +/* + * TODO: maybe we should rename "soc_scb.h", as the Kconfig system only include the correct SoC path. + * the 'stm32f4xx_ prefix should be kept only for IP drivers hosted in SoC dir, not for SoC global + * description headers. + */ +#include "soc-scb.h" +#include "m4-mpu.h" + +uint8_t core_mpu_update_subregion_mask(region_config * region) +{ + uint32_t reg = 0; + + /* Configure region */ + set_reg_value(r_CORTEX_M_MPU_RNR, region->region_number, + MPU_RNBR_REGION_Msk, MPU_RNBR_REGION_Pos); + // and update its subregion here (reconfigure RASR) + // the least mask bit mask the first subregion (8 bits for 8 subregions) + set_reg_value(®, region->access_perm, MPU_RASR_AP_Msk, MPU_RASR_AP_Pos); + set_reg_value(®, region->xn, MPU_RASR_XN_Msk, MPU_RASR_XN_Pos); + set_reg_value(®, region->b, MPU_RASR_B_Msk, MPU_RASR_B_Pos); + set_reg_value(®, region->s, MPU_RASR_S_Msk, MPU_RASR_S_Pos); + set_reg_value(®, region->mask, MPU_RASR_SRD_Msk, MPU_RASR_SRD_Pos); + + set_reg_value(®, region->size, MPU_RASR_SIZE_Msk, MPU_RASR_SIZE_Pos); + + set_reg_value(®, 1, MPU_RASR_EN_Msk, MPU_RASR_EN_Pos); + write_reg_value(r_CORTEX_M_MPU_RASR, reg); + + return 0; +} + +/* Disable/Enable MPU */ +void core_mpu_enable(uint8_t enable) +{ + set_reg_value(r_CORTEX_M_MPU_CTRL, enable, MPU_CTRL_ENABLE_Msk, + MPU_CTRL_ENABLE_Pos); +} + +void core_mpu_init(uint8_t privdefenable, void *mpu_Handler + __attribute__ ((unused))) +{ + /* Disable MPU */ + core_mpu_enable(0); + + /* Disable/Enable privileged software access to default memory map */ + set_reg_value(r_CORTEX_M_MPU_CTRL, privdefenable, + MPU_CTRL_PRIVDEFENA_Msk, MPU_CTRL_PRIVDEFENA_Pos); + + /* Enable the memory fault exception */ + set_reg_value(r_CORTEX_M_SCB_SHCSR, 1, SCB_SHCSR_MEMFAULTENA_Msk, + SCB_SHCSR_MEMFAULTENA_Pos); +} + +/* + * disable a given region + */ +uint8_t core_mpu_region_disable(uint8_t region_number) +{ + uint32_t reg = 0; + + if (region_number > MPU_LAST_REGION) { + return 1; + } + /* select the region number */ + set_reg_value(r_CORTEX_M_MPU_RNR, region_number, + MPU_RNBR_REGION_Msk, MPU_RNBR_REGION_Pos); + + /* disable the region */ + set_reg_value(®, 0, MPU_RASR_EN_Msk, MPU_RASR_EN_Pos); + write_reg_value(r_CORTEX_M_MPU_RASR, reg); + + return 0; +} + +/* + * Configure the access and execution rights using Cortex-M3 MPU regions. + */ +uint8_t core_mpu_region_config(region_config * region) +{ + uint32_t reg = 0; + + /* + * If the region size is configured to 4 GB, in the MPU_RASR register, + * there is no valid ADDR field. In this case, the region occupies the + * complete memory map, and the base address is 0x00000000. + * ADDR[31:N]: Region base address field with the value of N depends on the + * region size. + * N = Log2(Region size in bytes) + * The base address is aligned to the size of the region. + * + if (region->size == MPU_REGION_SIZE_4Gb) { + if (region->addr != 0) + return -1; + } + } + else if (region->addr % (1 << (region->size+1))) { + return -1; + } + */ + + /* Configure region */ + set_reg_value(r_CORTEX_M_MPU_RNR, region->region_number, + MPU_RNBR_REGION_Msk, MPU_RNBR_REGION_Pos); + + /* + * In case of valid = 0, MPU_RNR register not changed, + * Updates the base address for the region specified in the MPU_RNR + * then the value of the REGION field is ignored. + */ + set_reg_value(®, ((region->addr) >> MPU_RBAR_ADDR_Pos), + MPU_RBAR_ADDR_Msk, MPU_RBAR_ADDR_Pos); + set_reg_value(®, 0, MPU_RBAR_VALID_Msk, MPU_RBAR_VALID_Pos); + write_reg_value(r_CORTEX_M_MPU_RBAR, reg); + + reg = 0; + + /* + * Only Access permissions for privileged and unprivileged software are defined. + * Others attributs (TEX, C, B, and S) will be defined later. + */ + set_reg_value(®, region->access_perm, MPU_RASR_AP_Msk, MPU_RASR_AP_Pos); + set_reg_value(®, region->xn, MPU_RASR_XN_Msk, MPU_RASR_XN_Pos); + set_reg_value(®, region->b, MPU_RASR_B_Msk, MPU_RASR_B_Pos); + set_reg_value(®, region->s, MPU_RASR_S_Msk, MPU_RASR_S_Pos); + //set_reg_value( ®, region->mask, MPU_RASR_SRD_Msk, MPU_RASR_SRD_Pos); + set_reg_value(®, 0, MPU_RASR_SRD_Msk, MPU_RASR_SRD_Pos); + + set_reg_value(®, region->size, MPU_RASR_SIZE_Msk, MPU_RASR_SIZE_Pos); + + set_reg_value(®, 1, MPU_RASR_EN_Msk, MPU_RASR_EN_Pos); + write_reg_value(r_CORTEX_M_MPU_RASR, reg); + + return 0; +} + +uint8_t core_mpu_bytes_to_region_size (uint32_t bytes) +{ + switch (bytes) { + case 32: return MPU_REGION_SIZE_32b; + case 64: return MPU_REGION_SIZE_64b; + case 128: return MPU_REGION_SIZE_128b; + case 256: return MPU_REGION_SIZE_256b; + case 512: return MPU_REGION_SIZE_512b; + case 1*KBYTE: return MPU_REGION_SIZE_1Kb; + case 2*KBYTE: return MPU_REGION_SIZE_2Kb; + case 4*KBYTE: return MPU_REGION_SIZE_4Kb; + case 8*KBYTE: return MPU_REGION_SIZE_8Kb; + case 16*KBYTE: return MPU_REGION_SIZE_16Kb; + case 32*KBYTE: return MPU_REGION_SIZE_32Kb; + case 64*KBYTE: return MPU_REGION_SIZE_64Kb; + case 128*KBYTE: return MPU_REGION_SIZE_128Kb; + case 256*KBYTE: return MPU_REGION_SIZE_256Kb; + case 512*KBYTE: return MPU_REGION_SIZE_512Kb; + case 1*MBYTE: return MPU_REGION_SIZE_1Mb; + case 2*MBYTE: return MPU_REGION_SIZE_2Mb; + case 4*MBYTE: return MPU_REGION_SIZE_4Mb; + case 8*MBYTE: return MPU_REGION_SIZE_8Mb; + case 16*MBYTE: return MPU_REGION_SIZE_16Mb; + case 32*MBYTE: return MPU_REGION_SIZE_32Mb; + case 64*MBYTE: return MPU_REGION_SIZE_64Mb; + case 128*MBYTE: return MPU_REGION_SIZE_128Mb; + case 256*MBYTE: return MPU_REGION_SIZE_256Mb; + case 512*MBYTE: return MPU_REGION_SIZE_512Mb; + case 1*GBYTE: return MPU_REGION_SIZE_1Gb; + case 2147483648UL: return MPU_REGION_SIZE_2Gb; + //FIXME + // case 4294967296UL: return MPU_REGION_SIZE_4Gb; + default: + panic("core_mpu_bytes_to_region_size(): invalid size (%d)", bytes); + return 0; + } +} diff --git a/arch/cores/armv7-m/m4-mpu.h b/arch/cores/armv7-m/m4-mpu.h new file mode 100644 index 0000000..c654cb1 --- /dev/null +++ b/arch/cores/armv7-m/m4-mpu.h @@ -0,0 +1,180 @@ +/* \file m4-mpu.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _M4_MPU_H +#define _M4_MPU_H +#include "product.h" + +#include "soc-core.h" +#include "soc-layout.h" + +/* MPU region fields are based on values defined in m4-mpu-regions.h header */ +#include "m4-mpu-regions.h" + +#define MPU_LAST_REGION 7 + +/* The MPU divides the memory map into a number of regions and defines the location size + * access permissions and memory attributes of each region. It supports: + * • Independent attribute settings for each region + * • Overlapping regions + * • Export of memory attributes to the system. + * + * The memory attributes affect the behavior of memory accesses to the region. The CortexM4 + * MPU defines: + * • Eight separate memory regions 0-7 + * • A background region. + * When memory regions overlap a memory access is affected by the attributes of the region + * with the highest number. For example the attributes for region 7 take precedence over the + * attributes of any region that overlaps region 7. + * The background region has the same memory access attributes as the default memory + * map but is accessible from privileged software only. + * + * The Cortex-M4 MPU memory map is unified. This means instruction accesses and data + * accesses have same region settings. + * + * If a program accesses a memory location that is prohibited by the MPU the processor + * generates a memory management fault. This causes a fault exception and might cause + * termination of the process in an OS environment. + * + * In an OS environment the kernel can update the MPU region setting dynamically based on + * the process to be executed. Typically an embedded OS uses the MPU for memory + * protection. + */ + +// FIXME Where should this flag be declared ? +#define __MPU_PRESENT 1 + +/* Following definitions are valid only for Cortex-M4 */ +#if (__MPU_PRESENT == 1) +#define r_CORTEX_M_MPU_TYPER REG_ADDR(MPU_BASE + 0x00) +#define r_CORTEX_M_MPU_CTRL REG_ADDR(MPU_BASE + 0x04) +#define r_CORTEX_M_MPU_RNR REG_ADDR(MPU_BASE + 0x08) +#define r_CORTEX_M_MPU_RBAR REG_ADDR(MPU_BASE + 0x0C) +#define r_CORTEX_M_MPU_RASR REG_ADDR(MPU_BASE + 0x10) +#define r_CORTEX_M_MPU_RBAR_A1 REG_ADDR(MPU_BASE + 0x14) /* Alias of MPU_RBAR register */ +#define r_CORTEX_M_MPU_RASR_A1 REG_ADDR(MPU_BASE + 0x18) /* Alias of MPU_RASR register */ +#define r_CORTEX_M_MPU_RBAR_A2 REG_ADDR(MPU_BASE + 0x1C) /* Alias of MPU_RBAR register */ +#define r_CORTEX_M_MPU_RASR_A2 REG_ADDR(MPU_BASE + 0x20) /* Alias of MPU_RASR register */ +#define r_CORTEX_M_MPU_RBAR_A3 REG_ADDR(MPU_BASE + 0x1C) /* Alias of MPU_RBAR register */ +#define r_CORTEX_M_MPU_RASR_A3 REG_ADDR(MPU_BASE + 0x20) /* Alias of MPU_RASR register */ + +/* MPU type register (MPU_TYPER) */ +#define MPU_TYPER_IREGION_Pos 16 +#define MPU_TYPER_IREGION_Msk ((uint32_t) 0xFF << MPU_TYPE_IREGION_Pos) + +#define MPU_TYPER_DREGION_Pos 8 +#define MPU_TYPER_DREGION_Msk ((uint32_t) 0xFF << MPU_TYPE_DREGION_Pos) + +#define MPU_TYPER_SEPARATE_Pos 0 +#define MPU_TYPER_SEPARATE_Msk ((uint32_t) 0x01 << MPU_TYPE_SEPARATE_Pos) + +/* MPU control register (MPU_CTRL) */ +#define MPU_CTRL_PRIVDEFENA_Pos 2 +#define MPU_CTRL_PRIVDEFENA_Msk ((uint32_t) 0x01 << MPU_CTRL_PRIVDEFENA_Pos) + +#define MPU_CTRL_HFNMIENA_Pos 1 +#define MPU_CTRL_HFNMIENA_Msk ((uint32_t) 0x01 << MPU_CTRL_HFNMIENA_Pos) + +#define MPU_CTRL_ENABLE_Pos 0 +#define MPU_CTRL_ENABLE_Msk ((uint32_t) 0x01 << MPU_CTRL_ENABLE_Pos) + +/* MPU region number register (MPU_RNR) */ +#define MPU_RNBR_REGION_Pos 0 +#define MPU_RNBR_REGION_Msk ((uint32_t) 0xFF << MPU_RNBR_REGION_Pos) + +/* MPU region base address register (MPU_RBAR) */ +#define MPU_RBAR_ADDR_Pos 5 +#define MPU_RBAR_ADDR_Msk ((uint32_t) 0x7FFFFFF << MPU_RBAR_ADDR_Pos) + +#define MPU_RBAR_VALID_Pos 4 +#define MPU_RBAR_VALID_Msk ((uint32_t) 0x01 << MPU_RBAR_VALID_Pos) + +#define MPU_RBAR_REGION_Pos 0 +#define MPU_RBAR_REGION_Msk ((uint32_t) 0xF << MPU_RBAR_REGION_Pos) + +/* MPU region attribute and size register (MPU_RASR) */ +#define MPU_RASR_XN_Pos 28 +#define MPU_RASR_XN_Msk ((uint32_t) 0x1 << MPU_RASR_XN_Pos) + +#define MPU_RASR_AP_Pos 24 +#define MPU_RASR_AP_Msk ((uint32_t) 0x07 << MPU_RASR_AP_Pos) + +#define MPU_RASR_TEX_Pos 19 +#define MPU_RASR_TEX_Msk ((uint32_t) 0x07 << MPU_RASR_TEX_Pos) + +#define MPU_RASR_S_Pos 18 +#define MPU_RASR_S_Msk ((uint32_t) 0x01 << MPU_RASR_S_Pos) + +#define MPU_RASR_C_Pos 17 +#define MPU_RASR_C_Msk ((uint32_t) 0x01 << MPU_RASR_C_Pos) + +#define MPU_RASR_B_Pos 16 +#define MPU_RASR_B_Msk ((uint32_t) 0x01 << MPU_RASR_B_Pos) + +#define MPU_RASR_SRD_Pos 8 +#define MPU_RASR_SRD_Msk ((uint32_t) 0xFF << MPU_RASR_SRD_Pos) + +#define MPU_RASR_SIZE_Pos 1 +#define MPU_RASR_SIZE_Msk ((uint32_t) 0x3F << MPU_RASR_SIZE_Pos) + +#define MPU_RASR_EN_Pos 0 +#define MPU_RASR_EN_Msk ((uint32_t) 0x01 << MPU_RASR_EN_Pos) + +#define MPU_RASR_PERM_ATTRS(AP, TEX, C, B, S) \ + ((AP << MPU_RASR_AP_Pos) |\ + (TEX << MPU_RASR_TEX_Pos) |\ + (C << MPU_RASR_C_Pos) |\ + (B << MPU_RASR_B_Pos) |\ + (S << MPU_RASR_S_Pos)) + +/* */ + +typedef struct region_config_t { + unsigned int region_number; + unsigned long int addr; + unsigned int size; + unsigned long int access_perm; + unsigned int xn; + unsigned int b; + unsigned int s; + uint8_t mask; +} region_config; + +void core_mpu_init(uint8_t privdefenable, void *mpu_Handler); + +void core_mpu_enable(uint8_t enable); + +uint8_t core_mpu_region_disable(uint8_t region_number); + +uint8_t core_mpu_region_config(region_config * region); + +uint8_t core_mpu_update_subregion_mask(region_config * region); + +uint8_t core_mpu_bytes_to_region_size (uint32_t bytes); + +/*XXX : Useful ? */ +void core_MemManage_Handler(void); + +//void HardFault_Handler(void); + +#endif +#endif /* _STM32F4XX_MPU_H */ diff --git a/arch/cores/armv7-m/m4-svc.h b/arch/cores/armv7-m/m4-svc.h new file mode 100644 index 0000000..3a75f2b --- /dev/null +++ b/arch/cores/armv7-m/m4-svc.h @@ -0,0 +1,52 @@ +/* \file m4-svc.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _M4_SVC_H +#define _M4_SVC_H + +#include "cortex_m_functions.h" + +#define SVC_UNPRIVILEGED 0x00 +#define SVC_PRIVILEGED 0x01 + +#define SVC_MAIN 0x00 /* Main stack */ +#define SVC_PROCESS 0x02 /* Process stack */ + +#define SVC_SYSCALL 0x42 /* syscall */ + +/* Set Process Stack Pointer value */ +#define __SVC_SetPSP(psp) __set_PSP((uint32_t)(psp)) + +/* Select Process Stack as Thread mode Stack */ +#define __SVC_SetCONTROL(control) __set_CONTROL(control) + +#if defined ( __CC_ARM ) +void __svc(1) __SVC(uint8_t svc_number); + +#elif defined ( __GNUC__ ) +#define __SVC(code) asm volatile ("SVC %[immediate]"::[immediate] "I" (code)) +extern void __SVC_1(uint8_t svc_number); + +#endif /* __CC_ARM */ + +#endif /* _M4_SVC_H */ diff --git a/arch/cores/armv7-m/m4-systick-regs.h b/arch/cores/armv7-m/m4-systick-regs.h new file mode 100644 index 0000000..c26d452 --- /dev/null +++ b/arch/cores/armv7-m/m4-systick-regs.h @@ -0,0 +1,111 @@ +/* \file m4-systick-regs.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef CORTEX_M4_SYSTICK_REGS_H +#define CORTEX_M4_SYSTICK_REGS_H + +#include "soc-core.h" + +/* The processor has a 24-bit system timer, SysTick, that counts down from the reload value to + * zero, reloads (wraps to) the value in the STK_LOAD register on the next clock edge, then + * counts down on subsequent clocks. + * When the processor is halted for debugging the counter does not decrement. + * + * The SysTick counter runs on the processor clock. If this clock signal is stopped for low + * power mode, the SysTick counter stops. + * Ensure software uses aligned word accesses to access the SysTick registers. + * + * The SysTick counter reload and current value are undefined at reset, + * the correct initialization sequence for the SysTick counter is: + * 1. Program reload value. + * 2. Clear current value. + * 3. Program Control and Status register. + */ + +/*** System timer registers ***/ +/* (RW Privileged) SysTick control and status register (STK_CTRL) */ +#define r_CORTEX_M_STK_CTRL REG_ADDR(SysTick_BASE + (uint32_t)0x00) +/* (RW Privileged) SysTick reload value register (STK_LOAD) */ +#define r_CORTEX_M_STK_LOAD REG_ADDR(SysTick_BASE + (uint32_t)0x04) +/* (RW Privileged) SysTick current value register (STK_VAL) */ +#define r_CORTEX_M_STK_VAL REG_ADDR(SysTick_BASE + (uint32_t)0x08) +/* (RO Privileged) SysTick calibration value register (STK_CALIB) */ +#define r_CORTEX_M_STK_CALIB REG_ADDR(SysTick_BASE + (uint32_t)0x0C) + +/*** SysTick control and status register (STK_CTRL) ***/ +/* Bit 16 COUNTFLAG: Returns 1 if timer counted to 0 since last time this was + * read. + */ +#define STK_COUNTFLAG_Pos 16 +#define STK_COUNTFLAG_Msk ((uint32_t)0x01 << STK_COUNTFLAG_Pos) +/* Bit 2 CLKSOURCE: Clock source selection*/ +#define STK_CLKSOURCE_Pos 2 +#define STK_CLKSOURCE_Msk ((uint32_t)0x01 << STK_CLKSOURCE_Pos) +/* Bit 1 TICKINT: SysTick exception request enable*/ +#define STK_TICKINT_Pos 1 +#define STK_TICKINT_Msk ((uint32_t)0x01 << STK_TICKINT_Pos) +/* Bit 0 ENABLE: Counter enable*/ +#define STK_ENABLE_Pos 0 +#define STK_ENABLE_Msk ((uint32_t)0x01 << STK_ENABLE_Pos) + +/*** SysTick reload value register (STK_LOAD) ***/ +/* Bits 23:0 RELOAD: RELOAD value The LOAD register specifies the start value + * to load into the STK_VAL register when the counter is enabled and when it + * reaches 0. + */ +#define STK_RELOAD_Pos 0 +#define STK_RELOAD_Msk ((uint32_t)0xffffff << STK_RELOAD_Pos) + +/*** SysTick current value register (STK_VAL) ***/ +/* Bits 23:0 CURRENT: Current counter value. The VAL register contains the + * current value of the SysTick counter. Reads return the current value of the + * SysTick counter. A write of any value clears the field to 0, and also + * clears the COUNTFLAG bit in the STK_CTRL register to 0. + */ +#define STK_CURRENT_Pos 0 +#define STK_CURRENT_Msk ((uint32_t)0xffffff << STK_CURRENT_Pos) + +/*** SysTick calibration value register (STK_CALIB) ***/ +/* Bit 31 NOREF: NOREF flag. Reads as zero. Indicates that a separate reference + * clock is provided. The frequency of this clock is HCLK/8. + */ +#define STK_NOREF_Pos 31 +#define STK_NOREF_Msk ((uint32_t)0x01 << STK_NOREF_Pos) +/* Bit 30 SKEW: SKEW flag: Indicates whether the TENMS value is exact. Reads as + * one. Calibration value for the 1 ms inexact timing is not known because + * TENMS is not known. This can affect the suitability of SysTick as a software + * real time clock. + */ +#define STK_SKEW_Pos 30 +#define STK_SKEW_Msk ((uint32_t)0x01 << STK_SKEW_Pos) +/* Bits 23:0 TENMS[23:0]: Calibration value. Indicates the calibration value + * when the SysTick counter runs on HCLK max/8 as external clock. The value is + * product dependent, please refer to the Product Reference Manual, SysTick + * Calibration Value section. When HCLK is programmed at the maximum frequency, + * the SysTick period is 1ms. If calibration information is not known, + * calculate the calibration value required from the frequency of the processor + * clock or external clock. + */ +#define STK_TENMS_Pos 0 +#define STK_TENMS_Msk ((uint32_t)0xffffff << STK_TENMS_Pos) + +#endif /* CORTEX_M4_SYSTICK_REGS_H */ diff --git a/arch/cores/armv7-m/m4-systick.c b/arch/cores/armv7-m/m4-systick.c new file mode 100644 index 0000000..e9001d6 --- /dev/null +++ b/arch/cores/armv7-m/m4-systick.c @@ -0,0 +1,59 @@ +/* \file m4-systick.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "m4-systick.h" +#include "m4-systick-regs.h" +#include "regutils.h" +#include "product.h" + +volatile unsigned long long ticks; + +void core_systick_init(void) +{ + set_reg(r_CORTEX_M_STK_LOAD, PROD_CORE_FREQUENCY, STK_RELOAD); + set_reg(r_CORTEX_M_STK_VAL, 0, STK_CURRENT); + set_reg_bits(r_CORTEX_M_STK_CTRL, + STK_CLKSOURCE_Msk | STK_TICKINT_Msk | STK_ENABLE_Msk); +} + +void core_systick_delay(uint32_t delay) +{ + unsigned long long start = ticks; + while (start + delay > ticks) + continue; +} + +unsigned long long core_systick_get_ticks(void) +{ + return ticks; +} + +unsigned long long core_ms_to_ticks(unsigned long long ms) +{ + return ms * TICKS_PER_SECOND / 1000; +} + +stack_frame_t *core_systick_handler(stack_frame_t * stack_frame) +{ + ticks++; + return stack_frame; +} diff --git a/arch/cores/armv7-m/m4-systick.h b/arch/cores/armv7-m/m4-systick.h new file mode 100644 index 0000000..6a783cf --- /dev/null +++ b/arch/cores/armv7-m/m4-systick.h @@ -0,0 +1,54 @@ +/* m4-systick.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef CORTEX_M4_SYSTICK_H +#define CORTEX_M4_SYSTICK_H + +#include "types.h" +#include "soc-interrupts.h" + +/* FIXME */ +#define TICKS_PER_SECOND 1000 + +/** + * systick_init - Initialize the systick module + */ +void core_systick_init(void); + +/** + * delay + * @ms: Number of milliseconds to wait + */ +void core_systick_delay(uint32_t delay); + +/** + * get_ticks - Get the number of ticks elapsed since the card boot + * Return: Number of ticks. + */ +unsigned long long core_systick_get_ticks(void); + +unsigned long long core_ms_to_ticks(unsigned long long ms); + +/* ticks counter function, to be called by systick IRQ handler */ +stack_frame_t *core_systick_handler(stack_frame_t * stack_frame); + +#endif /* CORTEX_M4_SYSTICK_H */ diff --git a/arch/cores/armv7-m/types.h b/arch/cores/armv7-m/types.h new file mode 100644 index 0000000..394555e --- /dev/null +++ b/arch/cores/armv7-m/types.h @@ -0,0 +1,66 @@ +/* \file arch/types.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_TYPES_H +#define SOC_TYPES_H + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long int uint64_t; +/* fully typed log buffer size */ +typedef uint8_t logsize_t; + +typedef enum {false = 0, true = 1} bool; +typedef enum {SUCCESS, FAILURE} retval_t; + +#define KBYTE 1024 +#define MBYTE 1048576 +#define GBYTE 1073741824 + +#define NULL ((void *)0) + +/* 32bits targets specific */ +typedef uint32_t physaddr_t; +typedef uint8_t svcnum_t; + +#if defined(__CC_ARM) +# define __ASM __asm /* asm keyword for ARM Compiler */ +# define __INLINE static __inline /* inline keyword for ARM Compiler */ +# define __ISR_HANDLER /* [PTH] todo: find the way to deactivate localy frame pointer or use rx, x<4 for it */ +# define __NAKED /* [PTH] todo: find the way to set the function naked (without pre/postamble) */ +# define __UNUSED /* [PTH] todo: find the way to set a function/var unused */ +# define __WEAK /* [PTH] todo: find the way to set a function/var weak */ +#elif defined(__GNUC__) +# define __ASM __asm /* asm keyword for GNU Compiler */ +# define __INLINE static inline +# define __ISR_HANDLER __attribute__((optimize("-fomit-frame-pointer"))) +# define __NAKED __attribute__((naked)) +# define __UNUSED __attribute__((unused)) +# define __WEAK __attribute__((weak)) +# define __packed __attribute__((__packed__)) +#endif + +#endif diff --git a/arch/debug.c b/arch/debug.c new file mode 100644 index 0000000..4d81a23 --- /dev/null +++ b/arch/debug.c @@ -0,0 +1,226 @@ +/* \file debug.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include + +#include "autoconf.h" +#include "debug.h" +#include "libc.h" +#include "product.h" +#include "soc-usart.h" + +#define BUF_SIZE 512 +#define BUF_MAX (BUF_SIZE - 1) +#define PUT_CHAR(c) \ + ring_buffer.buf[ring_buffer.end++] = c; \ + ring_buffer.end %= BUF_MAX; \ + if (ring_buffer.end == ring_buffer.start) { \ + ring_buffer.start++; \ + ring_buffer.start %= BUF_MAX; \ + } + +volatile int logging = CONFIG_KERNEL_CONSOLE_TXT; + +cb_usart_getc_t console_getc = NULL; +cb_usart_putc_t console_putc = NULL; + +static struct { + uint32_t start; + uint32_t end; + char buf[BUF_SIZE]; +} ring_buffer; + +void init_ring_buffer(void) +{ + int i = 0; + ring_buffer.end = 0; + ring_buffer.start = ring_buffer.end; + + for (i = 0; i < BUF_SIZE; i++) { + ring_buffer.buf[i] = '\0'; + } +} + +void cb_console_data_received(void) +{ + char c; + if (console_getc == NULL) { + panic("Error: console_getc not initialized!"); + } + + c = console_getc(); + +#if 0 + if (c != ' ' && c != 'p') { + dbg_flush(); + return; + } +#endif + + if (logging && console_putc) { + if (c == '\r') { + console_putc('\r'); + console_putc('\n'); + } else { + console_putc(c); + } + } +} + +static usart_config_t console_config = { 0 }; + +void debug_console_init(void) +{ + /* Configure the USART in UART mode */ + console_config.usart = CONFIG_KERNEL_USART; + console_config.baudrate = 115200; + console_config.word_length = USART_CR1_M_8; + console_config.stop_bits = USART_CR2_STOP_1BIT; + console_config.parity = USART_CR1_PCE_DIS; + console_config.hw_flow_control = USART_CR3_CTSE_CTS_DIS | USART_CR3_RTSE_RTS_DIS; + console_config.options_cr1 = USART_CR1_TE_EN | USART_CR1_RE_EN | USART_CR1_UE_EN; + console_config.callback_data_received = cb_console_data_received; + console_config.callback_usart_getc_ptr = &console_getc; + console_config.callback_usart_putc_ptr = &console_putc; + + /* Initialize the USART related to the console */ + soc_usart_init(&console_config); + init_ring_buffer(); + dbg_log("[USART%d initialized for console output, baudrate=%d]\n", + console_config.usart, console_config.baudrate); + dbg_flush(); +} + +static void write_digit(uint8_t digit) +{ + if (digit < 0xa) + digit += '0'; + else + digit += 'a' - 0xa; + PUT_CHAR(digit); +} + +static void itoa(unsigned long long value, uint8_t base) +{ + if (value / base == 0) { + write_digit(value % base); + } else { + itoa(value / base, base); + write_digit(value % base); + } +} + +static void copy_string(char *str, uint32_t len) +{ + uint32_t size = + len < (BUF_MAX - ring_buffer.end) ? len : BUF_MAX - ring_buffer.end; + strncpy(ring_buffer.buf + ring_buffer.end, str, size); + uint32_t dist = ring_buffer.start - ring_buffer.end; + if (ring_buffer.end < ring_buffer.start && dist < size) { + ring_buffer.start += size - dist + 1; + ring_buffer.start %= BUF_MAX; + } + ring_buffer.end += size; + ring_buffer.end %= BUF_MAX; + if (len - size) + copy_string(str + size, len - size); +} + +void dbg_flush(void) +{ + if (console_putc == NULL) { + panic("Error: console_putc not initialized"); + } + while (ring_buffer.start != ring_buffer.end) { + console_putc(ring_buffer.buf[ring_buffer.start++]); + ring_buffer.start %= BUF_MAX; + } +} + +static void print(const char *fmt, va_list args) +{ + uint32_t i = 0; + char *string; + + for (i = 0; fmt[i]; i++) { + if (fmt[i] == '%') { + i++; + switch (fmt[i]) { + case 'd': + itoa(va_arg(args, uint32_t), 10); + break; + case 'x': + PUT_CHAR('0'); + PUT_CHAR('x'); + itoa(va_arg(args, uint32_t), 16); + break; + case '%': + PUT_CHAR('%'); + break; + case 's': + string = va_arg(args, char *); + copy_string(string, strlen(string)); + break; + case 'l': + if (fmt[i + 1] == 'l' && fmt[i + 2] == 'd') { + itoa(va_arg(args, unsigned long long), 10); + i += 2; + } else if (fmt[i + 1] == 'd') { + itoa(va_arg(args, unsigned long), 10); + i++; + } + break; + case 'c': + PUT_CHAR((unsigned char)va_arg(args, int)); + break; + default: + PUT_CHAR('?'); + } + } else if (fmt[i] == '\n' && fmt[i + 1] != '\r') { + copy_string("\n\r", 2); + } else { + PUT_CHAR(fmt[i]); + } + } +} + +void dbg_log(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + print(fmt, args); + va_end(args); +} + +void panic(char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + print(fmt, args); + va_end(args); + dbg_flush(); + __asm__ volatile ("bkpt\n"); + while (1) + continue; +} diff --git a/arch/debug.h b/arch/debug.h new file mode 100644 index 0000000..740eba6 --- /dev/null +++ b/arch/debug.h @@ -0,0 +1,108 @@ +/* \file debug.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef DEBUG_H_ +#define DEBUG_H_ + +#include "autoconf.h" +#ifdef CONFIG_ARCH_CORTEX_M4 +#include "m4-systick.h" +#else +#error "no systick support for other by now!" +#endif +#include "soc-usart.h" + +/** + * This is the DBGLOG log levels definition. This is syslog compatible + */ +typedef enum { + DBG_EMERG = 0, + DBG_ALERT = 1, + DBG_CRIT = 2, + DBG_ERR = 3, + DBG_WARN = 4, + DBG_NOTICE = 5, + DBG_INFO = 6, + DBG_DEBUG = 7, +} e_dbglevel_t; + +/** + * dbg_log - log strings in ring buffer + * @fmt: format string + */ +void dbg_log(const char *fmt, ...); + +/** + * menuconfig controlled debug print + */ +#define DEBUG(level, fmt, ...) { \ + if (level <= CONFIG_DBGLEVEL) { dbg_log(fmt, __VA_ARGS__); dbg_flush(); } \ +} + +void debug_console_init(void); + +/** + * dbg_flush - flush the ring buffer to UART + */ +void dbg_flush(void); + +/** + * panic - output string on UART, flush ring buffer and stop + * @fmt: format string + */ +void panic(char *fmt, ...); + +#define assert(EXP) \ + do { \ + if (!(EXP)) \ + panic("Assert in file %s on line %d\n", __FILE__, __LINE__); \ + } while (0) + +#if DEBUG_LVL >= 3 +#define LOG(fmt, ...) dbg_log("%lld: [II] %s:%d, %s:"fmt, get_ticks(), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) +#else +#define LOG(fmt, ...) do {} while (0) +#endif + +#if DEBUG_LVL >= 2 +#define WARN(fmt, ...) dbg_log("%lld: [WW] %s:%d, %s:"fmt, get_ticks(), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) +#else +#define WARN(fmt, ...) do {} while (0) +#endif + +#if DEBUG_LVL >= 1 +extern volatile int logging; +#define ERROR(fmt, ...) \ + do { \ + dbg_log("%lld: [EE] %s:%d, %s:"fmt, get_ticks(), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \ + /*if (logging)*/ \ + dbg_flush(); \ + } while (0) +#else +#define ERROR(fmt, ...) do {} while (0) +#endif + +#define LOG_CL(fmt, ...) dbg_log(""fmt, ##__VA_ARGS__) + +void init_ring_buffer(void); + +#endif /* !DEBUG_H_ */ diff --git a/arch/get_random.c b/arch/get_random.c new file mode 100644 index 0000000..3ae1eba --- /dev/null +++ b/arch/get_random.c @@ -0,0 +1,59 @@ +/* \file get_random.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "libc.h" +#include "get_random.h" + +int get_random(unsigned char *buf, uint16_t len) +{ + uint16_t i; + + /* First, set the buffer to zero */ + memset(buf, 0, len); + + /* Generate as much random as necessary */ + for(i = 0; i < sizeof(uint32_t) * (len / sizeof(uint32_t)); i += sizeof(uint32_t)){ + if(soc_rng_manager((uint32_t*)(&(buf[i])))){ + goto err; + } + } + if((len - i) > (int16_t)sizeof(uint32_t)){ + /* We should not end here ... */ + goto err; + } + /* Handle the remaining bytes */ + if(i < len){ + uint32_t random; + if(soc_rng_manager((&random))){ + goto err; + } + while(i < len){ + buf[i] = (random >> (8 * (len - i))) & 0xff; + i++; + } + } + + return 0; +err: + return -1; +} diff --git a/arch/get_random.h b/arch/get_random.h new file mode 100644 index 0000000..7d7faf8 --- /dev/null +++ b/arch/get_random.h @@ -0,0 +1,8 @@ +#ifndef __GET_RANDOM_H__ +#define __GET_RANDOM_H__ + +#include "soc-rng.h" + +int get_random(unsigned char *buf, uint16_t len); + +#endif /* __GET_RANDOM_H__ */ diff --git a/arch/libabsp.adc b/arch/libabsp.adc new file mode 100644 index 0000000..0ce2632 --- /dev/null +++ b/arch/libabsp.adc @@ -0,0 +1,4 @@ +pragma restrictions(no_elaboration_code); +pragma restrictions(no_secondary_stack); +pragma restrictions(no_finalization); +pragma restrictions(no_exception_handlers); diff --git a/arch/libabsp.gpr b/arch/libabsp.gpr new file mode 100644 index 0000000..9554608 --- /dev/null +++ b/arch/libabsp.gpr @@ -0,0 +1,50 @@ +library project Libabsp is + + for Languages use ("Ada"); + + for Source_Dirs use + ("Ada", + "../../kernel/arch/cores/" & external("ARCH") & "/Ada", + "../../kernel/arch/socs/" & external("SOCNAME") & "/Ada"); + + for Library_Dir use external("BUILD_DIR") & "/Ada/lib"; + for Object_Dir use external("BUILD_DIR") & "/Ada"; + for Target use external("ADA_ARCH"); + for Runtime ("ada") use external("ADA_PROFILE"); + for Library_Name use "absp"; + for Library_Kind use "static"; + + package Compiler is + + basic := + ("-fstack-usage", -- Generate .su file with informations about the + -- amount of stack used + "-gnateG", -- Generate preprocessed source + "-gnatec=" & Libabsp'Project_Dir & "libabsp.adc", + "-gnatn", -- Enable pragma Inline + "-gnatwa", -- Turn on all warnings + "-gnatw.X", -- Turn off warnings for export/import + "-gnatwe"); -- Treat all warnings as errors + + verif := + ("-gnato", -- Turn on all checks + "-gnatVa"); -- Turn on all validity checks + + no_verif := + ("-gnatp", -- Turn off all checks + "-gnatVn"); -- Turn off all validity checks + + for Default_Switches ("ada") use ("-O3", "-g") & basic & verif; + for Switches ("soc-dma.adb") use ("-Os", "-g") & basic & verif; + + -- Proved SPARK code + for Switches ("soc-dwt.adb") use ("-O3", "-g") & basic & no_verif; + for Switches ("m4-mpu.adb") use ("-O3", "-g") & basic & no_verif; + + end Compiler; + + package Binder is + for Default_Switches ("ada") use ("-n"); + end Binder; + +end Libabsp; diff --git a/arch/libc.c b/arch/libc.c new file mode 100644 index 0000000..ae253ae --- /dev/null +++ b/arch/libc.c @@ -0,0 +1,127 @@ +/* \file libc.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "types.h" + +void *memset(void *s, int c, uint32_t n) +{ + char *bytes = s; + while (n) { + *bytes = c; + bytes++; + n--; + } + return s; +} + +void *memcpy(void *dest, const void *src, uint32_t n) +{ + char *d_bytes = dest; + const char *s_bytes = src; + + while (n) { + *d_bytes = *s_bytes; + d_bytes++; + s_bytes++; + n--; + } + + return dest; +} + +uint32_t strlen(const char *s) +{ + uint32_t i = 0; + while (*s) { + i++; + s++; + } + return i; +} + +char *strncpy(char *dest, const char *src, uint32_t n) +{ + char *return_value = dest; + + while (n && *src) { + *dest = *src; + dest++; + src++; + n--; + } + + while (n) { + *dest = 0; + dest++; + n--; + } + + return return_value; +} + +int8_t strcmp(const char *a, const char *b) +{ + unsigned char len = 0; + while (1) { + if (a[len] != b[len] || a[len] == '\0' || b[len] == '\0') { + return a[len] - b[len]; + } + len++; + } +} + +char tolower (char c) { + if (c >= 'A' && c <= 'Z') { + return c + ('a' - 'A'); + } else { + return c; + } +} + +int8_t strcasecmp(const char *a, const char *b) +{ + char c1, c2; + uint8_t len = 0; + + while (1) { + c1 = tolower(a[len]); + c2 = tolower(b[len]); + + if (c1 != c2 || c1 == '\0' || c2 == '\0') { + return c1 - c2; + } + + len++; + } +} + + +void sleep_intern(uint8_t length) +{ + /* FIXME Assert length value */ + int i = 0, j = 0; + int time_value = (1 << (length * 2)); + for (i = 0; i < time_value; i++) { + for (j = 0; j < time_value; j++) ; + } +} diff --git a/arch/libc.h b/arch/libc.h new file mode 100644 index 0000000..cfd27f7 --- /dev/null +++ b/arch/libc.h @@ -0,0 +1,24 @@ +#ifndef _LIBC_ +#define _LIBC_ + +#include "types.h" + +/* + * Define time to sleep (for loop) + */ +#define MICRO_TIME 1 +#define SHORT_TIME 3 +#define MEDIUM_TIME 5 +#define LONG_TIME 6 +#define DFU_TIME 24 + +void *memset(void *s, int c, uint32_t n); +void *memcpy(void *dest, const void *src, uint32_t n); +uint32_t strlen(const char *s); +char *strncpy(char *dest, const char *src, uint32_t n); +char tolower (char c); +int8_t strcmp(const char *a, const char *b); +int8_t strcasecmp(const char *a, const char *b); +void sleep_intern(uint8_t length); + +#endif /* _LIBC_ */ diff --git a/arch/socs/stm32f407/Ada/config.def b/arch/socs/stm32f407/Ada/config.def new file mode 120000 index 0000000..e239448 --- /dev/null +++ b/arch/socs/stm32f407/Ada/config.def @@ -0,0 +1 @@ +../../stm32f439/Ada/config.def \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/default_handlers.adb b/arch/socs/stm32f407/Ada/default_handlers.adb new file mode 120000 index 0000000..4182d81 --- /dev/null +++ b/arch/socs/stm32f407/Ada/default_handlers.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/default_handlers.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/default_handlers.ads b/arch/socs/stm32f407/Ada/default_handlers.ads new file mode 120000 index 0000000..3de3a85 --- /dev/null +++ b/arch/socs/stm32f407/Ada/default_handlers.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/default_handlers.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-devmap.ads.DRAFT b/arch/socs/stm32f407/Ada/soc-devmap.ads.DRAFT new file mode 120000 index 0000000..e0c56c6 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-devmap.ads.DRAFT @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-devmap.ads.DRAFT \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-dma-interfaces.adb b/arch/socs/stm32f407/Ada/soc-dma-interfaces.adb new file mode 120000 index 0000000..e3fa2cf --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-dma-interfaces.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dma-interfaces.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-dma-interfaces.ads b/arch/socs/stm32f407/Ada/soc-dma-interfaces.ads new file mode 120000 index 0000000..a785ef1 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-dma-interfaces.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dma-interfaces.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-dma.adb b/arch/socs/stm32f407/Ada/soc-dma.adb new file mode 120000 index 0000000..da10ff2 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-dma.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dma.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-dma.ads b/arch/socs/stm32f407/Ada/soc-dma.ads new file mode 120000 index 0000000..bd1d2aa --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-dma.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dma.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-dwt-interfaces.adb b/arch/socs/stm32f407/Ada/soc-dwt-interfaces.adb new file mode 120000 index 0000000..9cc78de --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-dwt-interfaces.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dwt-interfaces.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-dwt-interfaces.ads b/arch/socs/stm32f407/Ada/soc-dwt-interfaces.ads new file mode 120000 index 0000000..58f3b63 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-dwt-interfaces.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dwt-interfaces.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-dwt.adb b/arch/socs/stm32f407/Ada/soc-dwt.adb new file mode 120000 index 0000000..d4f1931 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-dwt.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dwt.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-dwt.ads b/arch/socs/stm32f407/Ada/soc-dwt.ads new file mode 120000 index 0000000..9d3d121 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-dwt.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dwt.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-exti.adb b/arch/socs/stm32f407/Ada/soc-exti.adb new file mode 120000 index 0000000..da3d266 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-exti.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-exti.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-exti.ads b/arch/socs/stm32f407/Ada/soc-exti.ads new file mode 120000 index 0000000..52f8c83 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-exti.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-exti.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-gpio-interfaces.adb b/arch/socs/stm32f407/Ada/soc-gpio-interfaces.adb new file mode 120000 index 0000000..29c592f --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-gpio-interfaces.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-gpio-interfaces.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-gpio-interfaces.ads b/arch/socs/stm32f407/Ada/soc-gpio-interfaces.ads new file mode 120000 index 0000000..9820e85 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-gpio-interfaces.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-gpio-interfaces.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-gpio.adb b/arch/socs/stm32f407/Ada/soc-gpio.adb new file mode 120000 index 0000000..502bf6c --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-gpio.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-gpio.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-gpio.ads b/arch/socs/stm32f407/Ada/soc-gpio.ads new file mode 120000 index 0000000..7d96aca --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-gpio.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-gpio.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-interrupts.adb b/arch/socs/stm32f407/Ada/soc-interrupts.adb new file mode 120000 index 0000000..664e3bd --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-interrupts.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-interrupts.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-interrupts.ads b/arch/socs/stm32f407/Ada/soc-interrupts.ads new file mode 120000 index 0000000..a57f613 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-interrupts.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-interrupts.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-layout-stm32f4.ads b/arch/socs/stm32f407/Ada/soc-layout-stm32f4.ads new file mode 120000 index 0000000..0e6fd9c --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-layout-stm32f4.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-layout-stm32f4.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-layout-stm32f42x.ads b/arch/socs/stm32f407/Ada/soc-layout-stm32f42x.ads new file mode 120000 index 0000000..82e5a57 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-layout-stm32f42x.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-layout-stm32f42x.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-layout.ads b/arch/socs/stm32f407/Ada/soc-layout.ads new file mode 100644 index 0000000..4c6a6de --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-layout.ads @@ -0,0 +1,106 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with m4.mpu; +with types; + +package soc.layout + with spark_mode => on +is + + FLASH_BASE : constant system_address := 16#0800_0000#; + FLASH_SIZE : constant := 1 * MBYTE; + + SRAM_BASE : constant system_address := 16#1000_0000#; + SRAM_SIZE : constant := 64 * KBYTE; + + BOOTROM_BASE : constant system_address := 16#1FFF_0000#; + + RAM_BASE : constant system_address := 16#2000_0000#; -- SRAM + RAM_SIZE : constant := 128 * KBYTE; + + PERIPH_BASE : constant system_address := 16#4000_0000#; + MEMORY_BANK1_BASE : constant system_address := 16#6000_0000#; + MEMORY_BANK2_BASE : constant system_address := MEMORY_BANK1_BASE; + + APB1PERIPH_BASE : constant system_address := PERIPH_BASE; + APB2PERIPH_BASE : constant system_address := PERIPH_BASE + 16#0001_0000#; + AHB1PERIPH_BASE : constant system_address := PERIPH_BASE + 16#0002_0000#; + AHB2PERIPH_BASE : constant system_address := PERIPH_BASE + 16#1000_0000#; + + -- + -- AHB1 peripherals + -- + + GPIOA_BASE : constant system_address := AHB1PERIPH_BASE + 16#0000#; + GPIOB_BASE : constant system_address := AHB1PERIPH_BASE + 16#0400#; + GPIOC_BASE : constant system_address := AHB1PERIPH_BASE + 16#0800#; + GPIOD_BASE : constant system_address := AHB1PERIPH_BASE + 16#0C00#; + GPIOE_BASE : constant system_address := AHB1PERIPH_BASE + 16#1000#; + GPIOF_BASE : constant system_address := AHB1PERIPH_BASE + 16#1400#; + GPIOG_BASE : constant system_address := AHB1PERIPH_BASE + 16#1800#; + GPIOH_BASE : constant system_address := AHB1PERIPH_BASE + 16#1C00#; + GPIOI_BASE : constant system_address := AHB1PERIPH_BASE + 16#2000#; + + DMA1_BASE : constant system_address := AHB1PERIPH_BASE + 16#6000#; + DMA2_BASE : constant system_address := AHB1PERIPH_BASE + 16#6400#; + + -- + -- APB2 peripherals + -- + + SYSCFG_BASE : constant system_address := APB2PERIPH_BASE + 16#3800#; + + -- + -- Flash and firmware structure + -- + -- + -- Flip bank + + FW1_SIZE : constant unsigned_32 := 576*1024; + + FW1_KERN_BASE : constant unsigned_32 := 16#08020000#; + FW1_KERN_SIZE : constant unsigned_32 := 64*1024; + FW1_KERN_REGION_SIZE : constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_64KB; + + FW1_USER_BASE : constant unsigned_32 := 16#08080000#; + FW1_USER_SIZE : constant unsigned_32 := 512*1024; + FW1_USER_REGION_SIZE : constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_512KB; + + -- DFU 1 + + DFU1_SIZE : constant unsigned_32 := 320*1024; + + DFU1_KERN_BASE : constant unsigned_32 := 16#08030000#; + DFU1_USER_BASE : constant unsigned_32 := 16#08040000#; + + DFU1_KERN_SIZE : constant unsigned_32 := 64*1024; + DFU1_KERN_REGION_SIZE: constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_64KB; + DFU1_USER_SIZE : constant unsigned_32 := 256*1024; + DFU1_USER_REGION_SIZE: constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_256KB; + + + -- STM32F429 has 1MB flash that can be mapped at a time, which forbid + -- the usage of efficient dual banking. + -- This layout does not declare the complete dual bank + +end soc.layout; diff --git a/arch/socs/stm32f407/Ada/soc-nvic.adb b/arch/socs/stm32f407/Ada/soc-nvic.adb new file mode 120000 index 0000000..a320e44 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-nvic.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-nvic.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-nvic.ads b/arch/socs/stm32f407/Ada/soc-nvic.ads new file mode 120000 index 0000000..4e6293c --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-nvic.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-nvic.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-rcc.adb.DRAFT b/arch/socs/stm32f407/Ada/soc-rcc.adb.DRAFT new file mode 120000 index 0000000..17caedd --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-rcc.adb.DRAFT @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-rcc.adb.DRAFT \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-rcc.ads b/arch/socs/stm32f407/Ada/soc-rcc.ads new file mode 120000 index 0000000..195d086 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-rcc.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-rcc.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-syscfg.adb b/arch/socs/stm32f407/Ada/soc-syscfg.adb new file mode 120000 index 0000000..3915e62 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-syscfg.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-syscfg.adb \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc-syscfg.ads b/arch/socs/stm32f407/Ada/soc-syscfg.ads new file mode 120000 index 0000000..f5f3de6 --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc-syscfg.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-syscfg.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Ada/soc.ads b/arch/socs/stm32f407/Ada/soc.ads new file mode 120000 index 0000000..badea8c --- /dev/null +++ b/arch/socs/stm32f407/Ada/soc.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc.ads \ No newline at end of file diff --git a/arch/socs/stm32f407/Kconfig b/arch/socs/stm32f407/Kconfig new file mode 120000 index 0000000..fb7d112 --- /dev/null +++ b/arch/socs/stm32f407/Kconfig @@ -0,0 +1 @@ +../stm32f439/Kconfig \ No newline at end of file diff --git a/arch/socs/stm32f407/Makefile.objs b/arch/socs/stm32f407/Makefile.objs new file mode 100644 index 0000000..feac059 --- /dev/null +++ b/arch/socs/stm32f407/Makefile.objs @@ -0,0 +1,45 @@ +SOC_DIR = $(PROJ_FILES)kernel/arch/socs/stm32f407 + +CFLAGS += -I$(PROJ_FILES)/kernel/arch/socs +CFLAGS += -I$(PROJ_FILES)/kernel/arch/socs/stm32f407 + +socdrv-y := +socdrv-bsp-y := + +# this is the Board Support package content +socdrv-bsp-y += soc-rcc.c +socdrv-bsp-y += soc-rng.c +socdrv-bsp-y += soc-interrupts.c +socdrv-bsp-y += soc-gpio.c +socdrv-bsp-y += soc-usart.c +socdrv-bsp-y += soc-exti.c +socdrv-bsp-y += soc-init.c +socdrv-bsp-y += soc-devmap.c +socdrv-bsp-y += default_handlers.c +socdrv-bsp-y += postpone.c +# mutually exclusive +socdrv-bsp-$(CONFIG_KERNEL_DMA_ENABLE) += soc-dma.c +socdrv-bsp-$(CONFIG_KERNEL_UNSAFE_DMA_ENABLE) += soc-dma.c + +socdrv-bsp-y += soc-dwt.c + +socdrv-$(CONFIG_IWDG) += soc-iwdg.c + +ifeq ($(CONFIG_ADAKERNEL),y) +# for Ada equivalent +#socdrv-ada-bsp-y += Ada/soc-rcc.adb +#socdrv-ada-bsp-y += Ada/soc-rng.adb +socdrv-ada-bsp-y += Ada/soc-interrupts.adb +socdrv-ada-bsp-y += Ada/soc-gpio.adb +socdrv-ada-bsp-y += Ada/soc-gpio-interfaces.adb +#socdrv-ada-bsp-y += Ada/soc-usart.adb +socdrv-ada-bsp-y += Ada/soc-exti.adb +#socdrv-ada-bsp-y += Ada/soc-init.adb +socdrv-ada-bsp-y += Ada/default_handlers.adb +#socdrv-ada-bsp-y += Ada/postpone.adb +socdrv-ada-bsp-y += Ada/soc-dma.adb +socdrv-ada-bsp-y += Ada/soc-dwt.adb +#socdrv-ada_bsp-y += Ada/soc-devmap.adb +socdrv-ada-bsp-y += Ada/soc-nvic.adb +socdrv-ada-bsp-y += Ada/soc-syscfg.adb +endif diff --git a/arch/socs/stm32f407/default_handlers.c b/arch/socs/stm32f407/default_handlers.c new file mode 120000 index 0000000..db31e82 --- /dev/null +++ b/arch/socs/stm32f407/default_handlers.c @@ -0,0 +1 @@ +../stm32f439/default_handlers.c \ No newline at end of file diff --git a/arch/socs/stm32f407/default_handlers.h b/arch/socs/stm32f407/default_handlers.h new file mode 120000 index 0000000..d2dbca7 --- /dev/null +++ b/arch/socs/stm32f407/default_handlers.h @@ -0,0 +1 @@ +../stm32f439/default_handlers.h \ No newline at end of file diff --git a/arch/socs/stm32f407/fw1.ld.in b/arch/socs/stm32f407/fw1.ld.in new file mode 120000 index 0000000..2c38ba0 --- /dev/null +++ b/arch/socs/stm32f407/fw1.ld.in @@ -0,0 +1 @@ +../stm32f439/fw1.ld.in \ No newline at end of file diff --git a/arch/socs/stm32f407/fw2.ld.in b/arch/socs/stm32f407/fw2.ld.in new file mode 120000 index 0000000..a0b96ea --- /dev/null +++ b/arch/socs/stm32f407/fw2.ld.in @@ -0,0 +1 @@ +../stm32f439/fw2.ld.in \ No newline at end of file diff --git a/arch/socs/stm32f407/postpone.c b/arch/socs/stm32f407/postpone.c new file mode 120000 index 0000000..ed171f9 --- /dev/null +++ b/arch/socs/stm32f407/postpone.c @@ -0,0 +1 @@ +../stm32f439/postpone.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-core.h b/arch/socs/stm32f407/soc-core.h new file mode 120000 index 0000000..1ddd321 --- /dev/null +++ b/arch/socs/stm32f407/soc-core.h @@ -0,0 +1 @@ +../stm32f439/soc-core.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-devmap.c b/arch/socs/stm32f407/soc-devmap.c new file mode 120000 index 0000000..122c2ba --- /dev/null +++ b/arch/socs/stm32f407/soc-devmap.c @@ -0,0 +1 @@ +../stm32f439/soc-devmap.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-devmap.h b/arch/socs/stm32f407/soc-devmap.h new file mode 120000 index 0000000..88b9479 --- /dev/null +++ b/arch/socs/stm32f407/soc-devmap.h @@ -0,0 +1 @@ +../stm32f439/soc-devmap.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-dma.c b/arch/socs/stm32f407/soc-dma.c new file mode 120000 index 0000000..4c95424 --- /dev/null +++ b/arch/socs/stm32f407/soc-dma.c @@ -0,0 +1 @@ +../stm32f439/soc-dma.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-dma.h b/arch/socs/stm32f407/soc-dma.h new file mode 120000 index 0000000..b2b7dcd --- /dev/null +++ b/arch/socs/stm32f407/soc-dma.h @@ -0,0 +1 @@ +../stm32f439/soc-dma.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-dma_regs.h b/arch/socs/stm32f407/soc-dma_regs.h new file mode 120000 index 0000000..4ed831c --- /dev/null +++ b/arch/socs/stm32f407/soc-dma_regs.h @@ -0,0 +1 @@ +../stm32f439/soc-dma_regs.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-dwt.c b/arch/socs/stm32f407/soc-dwt.c new file mode 120000 index 0000000..aadf8fc --- /dev/null +++ b/arch/socs/stm32f407/soc-dwt.c @@ -0,0 +1 @@ +../stm32f439/soc-dwt.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-dwt.h b/arch/socs/stm32f407/soc-dwt.h new file mode 120000 index 0000000..21f8931 --- /dev/null +++ b/arch/socs/stm32f407/soc-dwt.h @@ -0,0 +1 @@ +../stm32f439/soc-dwt.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-exti.c b/arch/socs/stm32f407/soc-exti.c new file mode 120000 index 0000000..ee01a1f --- /dev/null +++ b/arch/socs/stm32f407/soc-exti.c @@ -0,0 +1 @@ +../stm32f439/soc-exti.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-exti.h b/arch/socs/stm32f407/soc-exti.h new file mode 120000 index 0000000..9082a5e --- /dev/null +++ b/arch/socs/stm32f407/soc-exti.h @@ -0,0 +1 @@ +../stm32f439/soc-exti.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-flash.h b/arch/socs/stm32f407/soc-flash.h new file mode 120000 index 0000000..432727b --- /dev/null +++ b/arch/socs/stm32f407/soc-flash.h @@ -0,0 +1 @@ +../stm32f439/soc-flash.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-gpio.c b/arch/socs/stm32f407/soc-gpio.c new file mode 120000 index 0000000..c5e31a2 --- /dev/null +++ b/arch/socs/stm32f407/soc-gpio.c @@ -0,0 +1 @@ +../stm32f439/soc-gpio.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-gpio.h b/arch/socs/stm32f407/soc-gpio.h new file mode 120000 index 0000000..f113102 --- /dev/null +++ b/arch/socs/stm32f407/soc-gpio.h @@ -0,0 +1 @@ +../stm32f439/soc-gpio.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-init.c b/arch/socs/stm32f407/soc-init.c new file mode 120000 index 0000000..f21a74a --- /dev/null +++ b/arch/socs/stm32f407/soc-init.c @@ -0,0 +1 @@ +../stm32f439/soc-init.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-init.h b/arch/socs/stm32f407/soc-init.h new file mode 120000 index 0000000..32a8a06 --- /dev/null +++ b/arch/socs/stm32f407/soc-init.h @@ -0,0 +1 @@ +../stm32f439/soc-init.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-interrupts.c b/arch/socs/stm32f407/soc-interrupts.c new file mode 120000 index 0000000..2699e75 --- /dev/null +++ b/arch/socs/stm32f407/soc-interrupts.c @@ -0,0 +1 @@ +../stm32f439/soc-interrupts.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-interrupts.h b/arch/socs/stm32f407/soc-interrupts.h new file mode 120000 index 0000000..82344d1 --- /dev/null +++ b/arch/socs/stm32f407/soc-interrupts.h @@ -0,0 +1 @@ +../stm32f439/soc-interrupts.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-iwdg.c b/arch/socs/stm32f407/soc-iwdg.c new file mode 120000 index 0000000..8f92f1c --- /dev/null +++ b/arch/socs/stm32f407/soc-iwdg.c @@ -0,0 +1 @@ +../stm32f439/soc-iwdg.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-iwdg.h b/arch/socs/stm32f407/soc-iwdg.h new file mode 120000 index 0000000..cf61c43 --- /dev/null +++ b/arch/socs/stm32f407/soc-iwdg.h @@ -0,0 +1 @@ +../stm32f439/soc-iwdg.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-layout.h b/arch/socs/stm32f407/soc-layout.h new file mode 100644 index 0000000..d7e919a --- /dev/null +++ b/arch/socs/stm32f407/soc-layout.h @@ -0,0 +1,173 @@ +/* soc-layout.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_LAYOUT_H +#define SOC_LAYOUT_H + +#include "autoconf.h" + +/* +** About the mapping: here is the flash layout described below +** This mapping is feasable for mono-bank, mono-bank with DFU. +** +** +----------------+0x0800 0000 +** | LDR (64k) | +** +----------------+0x0801 0000 +** | SHR (64k) | +** +----------------+0x0802 0000 +** | FW_k (64k) | +** +----------------+0x0803 0000 +** | DFU_k (64k) | +** + - - - - - - - -+0x0804 0000 +** | | +** | DFU_u (256k) | +** | | +** +----------------+0x0808 0000 +** | | +** | FW_u (512k) | +** | | +** | | +** +----------------+0x0810 0000 +** +*/ + +#define NB_MEM_BANK 1 + + +#define KBYTE 1024 +#define FLASH_SIZE 1024*KBYTE +#define VTORS_SIZE 0x188 + +/* + * Mapping + */ +#define LDR_BASE 0x08000000 /* loader */ +#define SHR_BASE 0x08008000 /* shared memory */ + +#define RAM2_BASE 0x10000000 +#define RAM_KERN_BASE 0x10000000 /* 96k user RAM (div by 8 subregions, 12*8, 24*4), starting at RAM size + 32k */ + +/* User tasks */ +#define RAM_BASE 0x20000000 /* 24k kernel RAM + 8k empty */ +#define RAM_USER_BASE RAM_BASE /* 96k user RAM (div by 8 subregions, 12*8, 24*4), starting at RAM size + 32k */ +#define RAM_USER_REGION_SIZE MPU_REGION_SIZE_128Kb /* 96k user RAM (div by 8 subregions, 12*8, 24*4), starting at RAM size + 32k */ + +#define RAM_USER_APPS_BASE RAM_BASE +#define RAM_USER_SIZE 16*KBYTE +#define RAM_USER_APP1_BASE RAM_USER_APPS_BASE +#define RAM_USER_APP2_BASE RAM_USER_APP1_BASE + RAM_USER_SIZE +#define RAM_USER_APP3_BASE RAM_USER_APP2_BASE + RAM_USER_SIZE +#define RAM_USER_APP4_BASE RAM_USER_APP3_BASE + RAM_USER_SIZE +#define RAM_USER_APP5_BASE RAM_USER_APP4_BASE + RAM_USER_SIZE +#define RAM_USER_APP6_BASE RAM_USER_APP5_BASE + RAM_USER_SIZE +#define RAM_USER_APP7_BASE RAM_USER_APP6_BASE + RAM_USER_SIZE +#define RAM_USER_APP8_BASE RAM_USER_APP7_BASE + RAM_USER_SIZE + +#define FW1_APP1_BASE 0x08080000 +#define FW1_APP2_BASE 0x08090000 +#define FW1_APP3_BASE 0x080a0000 +#define FW1_APP4_BASE 0x080b0000 +#define FW1_APP5_BASE 0x080c0000 +#define FW1_APP6_BASE 0x080d0000 +#define FW1_APP7_BASE 0x080e0000 +#define FW1_APP8_BASE 0x080f0000 + +#define DFU1_APP1_BASE 0x08040000 +#define DFU1_APP2_BASE 0x08048000 +#define DFU1_APP3_BASE 0x08050000 +#define DFU1_APP4_BASE 0x08058000 +#define DFU1_APP5_BASE 0x08060000 +#define DFU1_APP6_BASE 0x08068000 +#define DFU1_APP7_BASE 0x08070000 +#define DFU1_APP8_BASE 0x08078000 + +/* LDR is in the last sub-region (slot 8) */ +#define RAM_LDR_BASE 0x2001c000 +#define RAM_LDR_SIZE 20*KBYTE + +/* + * STM32F4 + */ + + +#define RAM2_SIZE 64*KBYTE +#define RAM_KERN_SIZE RAM2_SIZE +#define LDR_SIZE 128*KBYTE + +/* Flip bank */ + +#define FW1_SIZE 576*KBYTE + +#define FW1_KERN_BASE 0x08020000 +#define FW1_KERN_SIZE 64*KBYTE +#define FW1_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb + +#define FW1_USER_BASE 0x08080000 +#define FW1_USER_SIZE 512*KBYTE +#define FW1_USER_REGION_SIZE MPU_REGION_SIZE_512Kb + +/**** DFU 1 ****/ + +#define DFU1_SIZE 320*KBYTE + +#define DFU1_KERN_BASE 0x08030000 +#define DFU1_USER_BASE 0x08040000 + +#define DFU1_KERN_SIZE 64*KBYTE +#define DFU1_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb +#define DFU1_USER_SIZE 256*KBYTE +#define DFU1_USER_REGION_SIZE MPU_REGION_SIZE_256Kb + + +/* No Flop bank feasable on this SoC, as there is only 1MB flash */ + + +#define RAM2_SIZE 64*KBYTE +#define RAM_KERN_SIZE RAM2_SIZE +#define RAM_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb +#define LDR_SIZE 128*KBYTE + + +#define MB1_BASE 0x60000000 +#define MB2_BASE 0x60000000 +#define MB1_SIZE 0 +#define MB2_SIZE 0 + + +#define FW1_START FW1_KERN_BASE + VTORS_SIZE + 1 +#define FW2_START FW2_KERN_BASE + VTORS_SIZE + 1 +#define DFU1_START DFU1_BASE + VTORS_SIZE + 1 +#define DFU2_START DFU2_BASE + VTORS_SIZE + 1 + + +#define FW_MAX_USER_SIZE 64*KBYTE +#define DFU_MAX_USER_SIZE 32*KBYTE + +/**** Shared mem ****/ +#define SHR_SIZE 32*KBYTE + +/**** SRAM ****/ +#define RAM_SIZE 128*KBYTE + + + +#endif /*!SOC_LAYOUT_H*/ diff --git a/arch/socs/stm32f407/soc-nvic.h b/arch/socs/stm32f407/soc-nvic.h new file mode 120000 index 0000000..45b8ae2 --- /dev/null +++ b/arch/socs/stm32f407/soc-nvic.h @@ -0,0 +1 @@ +../stm32f439/soc-nvic.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-pwr.h b/arch/socs/stm32f407/soc-pwr.h new file mode 120000 index 0000000..5977637 --- /dev/null +++ b/arch/socs/stm32f407/soc-pwr.h @@ -0,0 +1 @@ +../stm32f439/soc-pwr.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-rcc.c b/arch/socs/stm32f407/soc-rcc.c new file mode 120000 index 0000000..9b5f70d --- /dev/null +++ b/arch/socs/stm32f407/soc-rcc.c @@ -0,0 +1 @@ +../stm32f439/soc-rcc.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-rcc.h b/arch/socs/stm32f407/soc-rcc.h new file mode 120000 index 0000000..164b999 --- /dev/null +++ b/arch/socs/stm32f407/soc-rcc.h @@ -0,0 +1 @@ +../stm32f439/soc-rcc.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-rng.c b/arch/socs/stm32f407/soc-rng.c new file mode 120000 index 0000000..0000aea --- /dev/null +++ b/arch/socs/stm32f407/soc-rng.c @@ -0,0 +1 @@ +../stm32f439/soc-rng.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-rng.h b/arch/socs/stm32f407/soc-rng.h new file mode 120000 index 0000000..6fb4714 --- /dev/null +++ b/arch/socs/stm32f407/soc-rng.h @@ -0,0 +1 @@ +../stm32f439/soc-rng.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-scb.h b/arch/socs/stm32f407/soc-scb.h new file mode 120000 index 0000000..ff2add8 --- /dev/null +++ b/arch/socs/stm32f407/soc-scb.h @@ -0,0 +1 @@ +../stm32f439/soc-scb.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-syscfg.h b/arch/socs/stm32f407/soc-syscfg.h new file mode 120000 index 0000000..09e3e99 --- /dev/null +++ b/arch/socs/stm32f407/soc-syscfg.h @@ -0,0 +1 @@ +../stm32f439/soc-syscfg.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-usart-regs.h b/arch/socs/stm32f407/soc-usart-regs.h new file mode 120000 index 0000000..812b5d0 --- /dev/null +++ b/arch/socs/stm32f407/soc-usart-regs.h @@ -0,0 +1 @@ +../stm32f439/soc-usart-regs.h \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-usart.c b/arch/socs/stm32f407/soc-usart.c new file mode 120000 index 0000000..12d2522 --- /dev/null +++ b/arch/socs/stm32f407/soc-usart.c @@ -0,0 +1 @@ +../stm32f439/soc-usart.c \ No newline at end of file diff --git a/arch/socs/stm32f407/soc-usart.h b/arch/socs/stm32f407/soc-usart.h new file mode 120000 index 0000000..794a2f9 --- /dev/null +++ b/arch/socs/stm32f407/soc-usart.h @@ -0,0 +1 @@ +../stm32f439/soc-usart.h \ No newline at end of file diff --git a/arch/socs/stm32f407/startup_stm32f407.s b/arch/socs/stm32f407/startup_stm32f407.s new file mode 100644 index 0000000..a0bef75 --- /dev/null +++ b/arch/socs/stm32f407/startup_stm32f407.s @@ -0,0 +1,330 @@ +/** + ****************************************************************************** + * @file startup_stm32f4xx.s + * @author MCD Application Team + * @version V1.0.0 + * @date 30-September-2011 + * @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Configure the clock system and the external SRAM mounted on + * STM324xG-EVAL board to be used as data memory (optional, + * to be enabled by user) + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +.syntax unified +.cpu cortex-m4 +.fpu softvfp +.thumb + +.global g_pfnVectors +.global g_BaseAddress +.global g_StackAddress + +.extern Default_SubHandler + +/* start address for the initialization values of the .data section. defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +.word _sigot +.word _sgot +.word _egot + + +/* +.word _svtors +.word _evtors +*/ +/* + * @brief Globals variables + * @param None + * @retval None + * + */ + +.section .data +g_BaseAddress: + .word 0 +g_StackAddress: + .word 0 + +/* + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval None + */ + +.section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + bl _start /* Entry point address */ +_start: + cpsid i + movs r5, lr + sub r5, #5 /* In thumb mode LR is pointing to PC + 4 bytes + 1 because in thumb mode LR must be odd aligned*/ + sub r2, r5, #0x188 /* Compute vector table address FIXME: We should use dynimic value for VTORS_SIZE */ + ldr r2, [r2] + msr msp, r2 /* Reset stack address to default 0x20002000 */ + + movs r1, #0 + b LoopCopyDataInit +CopyDataInit: /* Copy the data segment initializers from flash to SRAM */ + ldr r3, =_sidata /* start address for the initialization values of the .data section. */ + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 +LoopCopyDataInit: + ldr r0, =_sdata /* start address for the .data section */ + ldr r3, =_edata /* end address for the .data section */ + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + + + ldr r2, =_sbss /* start address for the .bss section */ + b LoopFillZerobss +FillZerobss: /* Zero fill the bss segment. */ + movs r3, #0 + str r3, [r2], #4 +LoopFillZerobss: + ldr r3, = _ebss /* end address for the .bss section */ + cmp r2, r3 + bcc FillZerobss + movs r0, #1 + ldr r1, = g_BaseAddress + str r5, [r1] + dmb + bl main + bx lr + +.size Reset_Handler, .-Reset_Handler + +.section .text.Default_Handler + .weak Default_Handler + .type Default_Handler, %function +Default_Handler: + cpsid i + + /* + * The NVIC has already saved R0-R3, R12, LR, PC and xPSR registers on the + * stack. We save the remaining registers (R4-R11) and LR (with the new + * value) on that previously used stack. + */ + + /* 1) Which stack was previously used ? */ + + tst lr, #4 /* bit 2: (0) MSP (1) PSP stack */ + ite eq /* if equal 0 */ + mrseq r0, msp /* r0 <- MSP */ + mrsne r0, psp /* r0 <- PSP (process stack) */ + + /* + * 2) Save registers on the previously used stack. + * R0 points to the saved registers: + * LR, R4-R11, R0-R3, R12, previous LR, PC, xPSR + */ + + stmfd r0!, {r4-r11, lr} + + /* 3) Adjusting the previously used stack pointer (might be PSP or MSP) */ + + tst lr, #4 /* bit 2: (0) MSP (1) PSP stack */ + ite eq /* if equal 0 */ + msreq msp, r0 /* MSP <- r0 */ + msrne psp, r0 /* PSP <- r0 */ + + /* + * R0 is passed as a parameter. It still points to the saved registers. + * In case of task switching, R0 returned by `Default_SubHandler' might be + * different. + * R1 is returned by `Default_SubHandler' and it contains the task type. + * Valid R1 values are privileged (0) or unprivileged (1). + */ + + bl Default_SubHandler + + /* Registers LR, R4-R11 are restored */ + ldmfd r0!, {r4-r11, lr} + + /* + * Adjusting PSP/MSP so that the NVIC can restore the remaining registers + * and setting the execution mode (privileged or unprivileged) + */ + + tst lr, #4 /* bit 2: (0) MSP (1) PSP stack */ + bne psp_use /* if not equal 0 */ + +msp_use: + /* That branch should never be executed as every task use the PSP */ + msr msp, r0 /* MSP <- r0 */ + cpsie i + bx lr + +psp_use: + msr psp, r0 /* PSP <- r0 */ + + /* Is it an unprivileged task ? */ + cmp r1, #1 + bne kern_mode + +user_mode: + mov r0, #3 + msr control, r0 + isb + cpsie i + bx lr + +kern_mode: + mov r0, #2 + msr control, r0 + isb + cpsie i + bx lr +.size Default_Handler, .-Default_Handler + +/****************************************************************************** + * + * The minimal vector table for a Cortex M4. Note that the proper constructs + * must be placed on this to ensure that it ends up at physical address + * 0x0000.0000. + * + ******************************************************************************/ +.section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word Default_Handler + .word Default_Handler + .word Default_Handler + .word Default_Handler + .word Default_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word Default_Handler + .word Default_Handler + .word 0 + .word Default_Handler + .word Default_Handler + + /* + * External Interrupts + */ + .word Default_Handler /* Window WatchDog */ + .word Default_Handler /* PVD through EXTI Line detection */ + .word Default_Handler /* Tamper and TimeStamps through the EXTI line */ + .word Default_Handler /* RTC Wakeup through the EXTI line */ + .word Default_Handler /* FLASH */ + .word Default_Handler /* RCC */ + .word Default_Handler /* EXTI Line0 */ + .word Default_Handler /* EXTI Line1 */ + .word Default_Handler /* EXTI Line2 */ + .word Default_Handler /* EXTI Line3 */ + .word Default_Handler /* EXTI Line4 */ + .word Default_Handler /* DMA1 Stream 0 */ + .word Default_Handler /* DMA1 Stream 1 */ + .word Default_Handler /* DMA1 Stream 2 */ + .word Default_Handler /* DMA1 Stream 3 */ + .word Default_Handler /* DMA1 Stream 4 */ + .word Default_Handler /* DMA1 Stream 5 */ + .word Default_Handler /* DMA1 Stream 6 */ + .word Default_Handler /* ADC1, ADC2 and ADC3s */ + .word Default_Handler /* CAN1 TX */ + .word Default_Handler /* CAN1 RX0 */ + .word Default_Handler /* CAN1 RX1 */ + .word Default_Handler /* CAN1 SCE */ + .word Default_Handler /* External Line[9:5]s */ + .word Default_Handler /* TIM1 Break and TIM9 */ + .word Default_Handler /* TIM1 Update and TIM10 */ + .word Default_Handler /* TIM1 Trigger and Commutation and TIM11 */ + .word Default_Handler /* TIM1 Capture Compare */ + .word Default_Handler /* TIM2 */ + .word Default_Handler /* TIM3 */ + .word Default_Handler /* TIM4 */ + .word Default_Handler /* I2C1 Event */ + .word Default_Handler /* I2C1 Error */ + .word Default_Handler /* I2C2 Event */ + .word Default_Handler /* I2C2 Error */ + .word Default_Handler /* SPI1 */ + .word Default_Handler /* SPI2 */ + .word Default_Handler /* USART1 */ + .word Default_Handler /* USART2 */ + .word Default_Handler /* USART3 */ + .word Default_Handler /* External Line[15:10]s */ + .word Default_Handler /* RTC Alarm (A and B) through EXTI Line */ + .word Default_Handler /* USB OTG FS Wakeup through EXTI line */ + .word Default_Handler /* TIM8 Break and TIM12 */ + .word Default_Handler /* TIM8 Update and TIM13 */ + .word Default_Handler /* TIM8 Trigger and Commutation and TIM14 */ + .word Default_Handler /* TIM8 Capture Compare */ + .word Default_Handler /* DMA1 Stream7 */ + .word Default_Handler /* FSMC */ + .word Default_Handler /* SDIO */ + .word Default_Handler /* TIM5 */ + .word Default_Handler /* SPI3 */ + .word Default_Handler /* UART4 */ + .word Default_Handler /* UART5 */ + .word Default_Handler /* TIM6 and DAC1&2 underrun errors */ + .word Default_Handler /* TIM7 */ + .word Default_Handler /* DMA2 Stream 0 */ + .word Default_Handler /* DMA2 Stream 1 */ + .word Default_Handler /* DMA2 Stream 2 */ + .word Default_Handler /* DMA2 Stream 3 */ + .word Default_Handler /* DMA2 Stream 4 */ + .word Default_Handler /* Ethernet */ + .word Default_Handler /* Ethernet Wakeup through EXTI line */ + .word Default_Handler /* CAN2 TX */ + .word Default_Handler /* CAN2 RX0 */ + .word Default_Handler /* CAN2 RX1 */ + .word Default_Handler /* CAN2 SCE */ + .word Default_Handler /* USB OTG FS */ + .word Default_Handler /* DMA2 Stream 5 */ + .word Default_Handler /* DMA2 Stream 6 */ + .word Default_Handler /* DMA2 Stream 7 */ + .word Default_Handler /* USART6 */ + .word Default_Handler /* I2C3 event */ + .word Default_Handler /* I2C3 error */ + .word Default_Handler /* USB OTG HS End Point 1 Out */ + .word Default_Handler /* USB OTG HS End Point 1 In */ + .word Default_Handler /* USB OTG HS Wakeup through EXTI */ + .word Default_Handler /* USB OTG HS */ + .word Default_Handler /* DCMI */ + .word Default_Handler /* CRYP crypto */ + .word Default_Handler /* Hash and Rng */ + .word Default_Handler /* FPU */ + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/arch/socs/stm32f429/Ada/config.def b/arch/socs/stm32f429/Ada/config.def new file mode 120000 index 0000000..e239448 --- /dev/null +++ b/arch/socs/stm32f429/Ada/config.def @@ -0,0 +1 @@ +../../stm32f439/Ada/config.def \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/default_handlers.adb b/arch/socs/stm32f429/Ada/default_handlers.adb new file mode 120000 index 0000000..4182d81 --- /dev/null +++ b/arch/socs/stm32f429/Ada/default_handlers.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/default_handlers.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/default_handlers.ads b/arch/socs/stm32f429/Ada/default_handlers.ads new file mode 120000 index 0000000..3de3a85 --- /dev/null +++ b/arch/socs/stm32f429/Ada/default_handlers.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/default_handlers.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-devmap.ads.DRAFT b/arch/socs/stm32f429/Ada/soc-devmap.ads.DRAFT new file mode 120000 index 0000000..e0c56c6 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-devmap.ads.DRAFT @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-devmap.ads.DRAFT \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-dma-interfaces.adb b/arch/socs/stm32f429/Ada/soc-dma-interfaces.adb new file mode 120000 index 0000000..e3fa2cf --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-dma-interfaces.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dma-interfaces.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-dma-interfaces.ads b/arch/socs/stm32f429/Ada/soc-dma-interfaces.ads new file mode 120000 index 0000000..a785ef1 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-dma-interfaces.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dma-interfaces.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-dma.adb b/arch/socs/stm32f429/Ada/soc-dma.adb new file mode 120000 index 0000000..da10ff2 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-dma.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dma.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-dma.ads b/arch/socs/stm32f429/Ada/soc-dma.ads new file mode 120000 index 0000000..bd1d2aa --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-dma.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dma.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-dwt-interfaces.adb b/arch/socs/stm32f429/Ada/soc-dwt-interfaces.adb new file mode 120000 index 0000000..9cc78de --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-dwt-interfaces.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dwt-interfaces.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-dwt-interfaces.ads b/arch/socs/stm32f429/Ada/soc-dwt-interfaces.ads new file mode 120000 index 0000000..58f3b63 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-dwt-interfaces.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dwt-interfaces.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-dwt.adb b/arch/socs/stm32f429/Ada/soc-dwt.adb new file mode 120000 index 0000000..d4f1931 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-dwt.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dwt.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-dwt.ads b/arch/socs/stm32f429/Ada/soc-dwt.ads new file mode 120000 index 0000000..9d3d121 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-dwt.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-dwt.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-exti.adb b/arch/socs/stm32f429/Ada/soc-exti.adb new file mode 120000 index 0000000..da3d266 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-exti.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-exti.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-exti.ads b/arch/socs/stm32f429/Ada/soc-exti.ads new file mode 120000 index 0000000..52f8c83 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-exti.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-exti.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-gpio-interfaces.adb b/arch/socs/stm32f429/Ada/soc-gpio-interfaces.adb new file mode 120000 index 0000000..29c592f --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-gpio-interfaces.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-gpio-interfaces.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-gpio-interfaces.ads b/arch/socs/stm32f429/Ada/soc-gpio-interfaces.ads new file mode 120000 index 0000000..9820e85 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-gpio-interfaces.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-gpio-interfaces.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-gpio.adb b/arch/socs/stm32f429/Ada/soc-gpio.adb new file mode 120000 index 0000000..502bf6c --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-gpio.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-gpio.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-gpio.ads b/arch/socs/stm32f429/Ada/soc-gpio.ads new file mode 120000 index 0000000..7d96aca --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-gpio.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-gpio.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-interrupts.adb b/arch/socs/stm32f429/Ada/soc-interrupts.adb new file mode 120000 index 0000000..664e3bd --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-interrupts.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-interrupts.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-interrupts.ads b/arch/socs/stm32f429/Ada/soc-interrupts.ads new file mode 120000 index 0000000..a57f613 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-interrupts.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-interrupts.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-layout-stm32f4.ads b/arch/socs/stm32f429/Ada/soc-layout-stm32f4.ads new file mode 120000 index 0000000..0e6fd9c --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-layout-stm32f4.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-layout-stm32f4.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-layout-stm32f42x.ads b/arch/socs/stm32f429/Ada/soc-layout-stm32f42x.ads new file mode 120000 index 0000000..82e5a57 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-layout-stm32f42x.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-layout-stm32f42x.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-layout.ads b/arch/socs/stm32f429/Ada/soc-layout.ads new file mode 100644 index 0000000..2db794d --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-layout.ads @@ -0,0 +1,83 @@ +with m4.mpu; +with types; + +package soc.layout + with spark_mode => on +is + + FLASH_BASE : constant system_address := 16#0800_0000#; + FLASH_SIZE : constant := 1 * MBYTE; + + SRAM_BASE : constant system_address := 16#1000_0000#; + SRAM_SIZE : constant := 64 * KBYTE; + + BOOTROM_BASE : constant system_address := 16#1FFF_0000#; + + RAM_BASE : constant system_address := 16#2000_0000#; -- SRAM + RAM_SIZE : constant := 128 * KBYTE; + + PERIPH_BASE : constant system_address := 16#4000_0000#; + MEMORY_BANK1_BASE : constant system_address := 16#6000_0000#; + MEMORY_BANK2_BASE : constant system_address := MEMORY_BANK1_BASE; + + APB1PERIPH_BASE : constant system_address := PERIPH_BASE; + APB2PERIPH_BASE : constant system_address := PERIPH_BASE + 16#0001_0000#; + AHB1PERIPH_BASE : constant system_address := PERIPH_BASE + 16#0002_0000#; + AHB2PERIPH_BASE : constant system_address := PERIPH_BASE + 16#1000_0000#; + + -- + -- AHB1 peripherals + -- + + GPIOA_BASE : constant system_address := AHB1PERIPH_BASE + 16#0000#; + GPIOB_BASE : constant system_address := AHB1PERIPH_BASE + 16#0400#; + GPIOC_BASE : constant system_address := AHB1PERIPH_BASE + 16#0800#; + GPIOD_BASE : constant system_address := AHB1PERIPH_BASE + 16#0C00#; + GPIOE_BASE : constant system_address := AHB1PERIPH_BASE + 16#1000#; + GPIOF_BASE : constant system_address := AHB1PERIPH_BASE + 16#1400#; + GPIOG_BASE : constant system_address := AHB1PERIPH_BASE + 16#1800#; + GPIOH_BASE : constant system_address := AHB1PERIPH_BASE + 16#1C00#; + GPIOI_BASE : constant system_address := AHB1PERIPH_BASE + 16#2000#; + + DMA1_BASE : constant system_address := AHB1PERIPH_BASE + 16#6000#; + DMA2_BASE : constant system_address := AHB1PERIPH_BASE + 16#6400#; + + -- + -- APB2 peripherals + -- + + SYSCFG_BASE : constant system_address := APB2PERIPH_BASE + 16#3800#; + + -- + -- Flash and firmware structure + -- + -- + -- Flip bank + + FW1_SIZE : constant unsigned_32 := 576*1024; + + FW1_KERN_BASE : constant unsigned_32 := 16#08020000#; + FW1_KERN_SIZE : constant unsigned_32 := 64*1024; + FW1_KERN_REGION_SIZE : constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_64KB; + + FW1_USER_BASE : constant unsigned_32 := 16#08080000#; + FW1_USER_SIZE : constant unsigned_32 := 512*1024; + FW1_USER_REGION_SIZE : constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_512KB; + + -- DFU 1 + + DFU1_SIZE : constant unsigned_32 := 320*1024; + + DFU1_KERN_BASE : constant unsigned_32 := 16#08030000#; + DFU1_USER_BASE : constant unsigned_32 := 16#08040000#; + + DFU1_KERN_SIZE : constant unsigned_32 := 64*1024; + DFU1_KERN_REGION_SIZE: constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_64KB; + DFU1_USER_SIZE : constant unsigned_32 := 256*1024; + DFU1_USER_REGION_SIZE: constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_256KB; + + + -- STM32F429 has 1MB flash that can be mapped at a time, which forbid + -- the usage of efficient dual banking. + -- This layout does not declare the complete dual bank +end soc.layout; diff --git a/arch/socs/stm32f429/Ada/soc-nvic.adb b/arch/socs/stm32f429/Ada/soc-nvic.adb new file mode 120000 index 0000000..a320e44 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-nvic.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-nvic.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-nvic.ads b/arch/socs/stm32f429/Ada/soc-nvic.ads new file mode 120000 index 0000000..4e6293c --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-nvic.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-nvic.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-rcc.adb.DRAFT b/arch/socs/stm32f429/Ada/soc-rcc.adb.DRAFT new file mode 120000 index 0000000..17caedd --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-rcc.adb.DRAFT @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-rcc.adb.DRAFT \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-rcc.ads b/arch/socs/stm32f429/Ada/soc-rcc.ads new file mode 120000 index 0000000..195d086 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-rcc.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-rcc.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-syscfg.adb b/arch/socs/stm32f429/Ada/soc-syscfg.adb new file mode 120000 index 0000000..3915e62 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-syscfg.adb @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-syscfg.adb \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc-syscfg.ads b/arch/socs/stm32f429/Ada/soc-syscfg.ads new file mode 120000 index 0000000..f5f3de6 --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc-syscfg.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc-syscfg.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Ada/soc.ads b/arch/socs/stm32f429/Ada/soc.ads new file mode 120000 index 0000000..badea8c --- /dev/null +++ b/arch/socs/stm32f429/Ada/soc.ads @@ -0,0 +1 @@ +../../stm32f439/Ada/soc.ads \ No newline at end of file diff --git a/arch/socs/stm32f429/Kconfig b/arch/socs/stm32f429/Kconfig new file mode 120000 index 0000000..fb7d112 --- /dev/null +++ b/arch/socs/stm32f429/Kconfig @@ -0,0 +1 @@ +../stm32f439/Kconfig \ No newline at end of file diff --git a/arch/socs/stm32f429/Makefile.objs b/arch/socs/stm32f429/Makefile.objs new file mode 100644 index 0000000..47ef8a7 --- /dev/null +++ b/arch/socs/stm32f429/Makefile.objs @@ -0,0 +1,45 @@ +SOC_DIR = $(PROJ_FILES)kernel/arch/socs/stm32f429 + +CFLAGS += -I$(PROJ_FILES)/kernel/arch/socs +CFLAGS += -I$(PROJ_FILES)/kernel/arch/socs/stm32f429 + +socdrv-y := +socdrv-bsp-y := + +# this is the Board Support package content +socdrv-bsp-y += soc-rcc.c +socdrv-bsp-y += soc-rng.c +socdrv-bsp-y += soc-interrupts.c +socdrv-bsp-y += soc-gpio.c +socdrv-bsp-y += soc-usart.c +socdrv-bsp-y += soc-exti.c +socdrv-bsp-y += soc-init.c +socdrv-bsp-y += soc-devmap.c +socdrv-bsp-y += default_handlers.c +socdrv-bsp-y += postpone.c +# mutually exclusive +socdrv-bsp-$(CONFIG_KERNEL_DMA_ENABLE) += soc-dma.c +socdrv-bsp-$(CONFIG_KERNEL_UNSAFE_DMA_ENABLE) += soc-dma.c + +socdrv-bsp-y += soc-dwt.c + +socdrv-$(CONFIG_IWDG) += soc-iwdg.c + +ifeq ($(CONFIG_ADAKERNEL),y) +# for Ada equivalent +#socdrv-ada-bsp-y += Ada/soc-rcc.adb +#socdrv-ada-bsp-y += Ada/soc-rng.adb +socdrv-ada-bsp-y += Ada/soc-interrupts.adb +socdrv-ada-bsp-y += Ada/soc-gpio.adb +socdrv-ada-bsp-y += Ada/soc-gpio-interfaces.adb +#socdrv-ada-bsp-y += Ada/soc-usart.adb +socdrv-ada-bsp-y += Ada/soc-exti.adb +#socdrv-ada-bsp-y += Ada/soc-init.adb +socdrv-ada-bsp-y += Ada/default_handlers.adb +#socdrv-ada-bsp-y += Ada/postpone.adb +socdrv-ada-bsp-y += Ada/soc-dma.adb +socdrv-ada-bsp-y += Ada/soc-dwt.adb +#socdrv-ada_bsp-y += Ada/soc-devmap.adb +socdrv-ada-bsp-y += Ada/soc-nvic.adb +socdrv-ada-bsp-y += Ada/soc-syscfg.adb +endif diff --git a/arch/socs/stm32f429/default_handlers.c b/arch/socs/stm32f429/default_handlers.c new file mode 120000 index 0000000..db31e82 --- /dev/null +++ b/arch/socs/stm32f429/default_handlers.c @@ -0,0 +1 @@ +../stm32f439/default_handlers.c \ No newline at end of file diff --git a/arch/socs/stm32f429/default_handlers.h b/arch/socs/stm32f429/default_handlers.h new file mode 120000 index 0000000..d2dbca7 --- /dev/null +++ b/arch/socs/stm32f429/default_handlers.h @@ -0,0 +1 @@ +../stm32f439/default_handlers.h \ No newline at end of file diff --git a/arch/socs/stm32f429/fw1.ld.in b/arch/socs/stm32f429/fw1.ld.in new file mode 120000 index 0000000..2c38ba0 --- /dev/null +++ b/arch/socs/stm32f429/fw1.ld.in @@ -0,0 +1 @@ +../stm32f439/fw1.ld.in \ No newline at end of file diff --git a/arch/socs/stm32f429/fw2.ld.in b/arch/socs/stm32f429/fw2.ld.in new file mode 120000 index 0000000..a0b96ea --- /dev/null +++ b/arch/socs/stm32f429/fw2.ld.in @@ -0,0 +1 @@ +../stm32f439/fw2.ld.in \ No newline at end of file diff --git a/arch/socs/stm32f429/postpone.c b/arch/socs/stm32f429/postpone.c new file mode 120000 index 0000000..ed171f9 --- /dev/null +++ b/arch/socs/stm32f429/postpone.c @@ -0,0 +1 @@ +../stm32f439/postpone.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-core.h b/arch/socs/stm32f429/soc-core.h new file mode 120000 index 0000000..1ddd321 --- /dev/null +++ b/arch/socs/stm32f429/soc-core.h @@ -0,0 +1 @@ +../stm32f439/soc-core.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-devmap.c b/arch/socs/stm32f429/soc-devmap.c new file mode 120000 index 0000000..122c2ba --- /dev/null +++ b/arch/socs/stm32f429/soc-devmap.c @@ -0,0 +1 @@ +../stm32f439/soc-devmap.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-devmap.h b/arch/socs/stm32f429/soc-devmap.h new file mode 120000 index 0000000..88b9479 --- /dev/null +++ b/arch/socs/stm32f429/soc-devmap.h @@ -0,0 +1 @@ +../stm32f439/soc-devmap.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-dma.c b/arch/socs/stm32f429/soc-dma.c new file mode 120000 index 0000000..4c95424 --- /dev/null +++ b/arch/socs/stm32f429/soc-dma.c @@ -0,0 +1 @@ +../stm32f439/soc-dma.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-dma.h b/arch/socs/stm32f429/soc-dma.h new file mode 120000 index 0000000..b2b7dcd --- /dev/null +++ b/arch/socs/stm32f429/soc-dma.h @@ -0,0 +1 @@ +../stm32f439/soc-dma.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-dma_regs.h b/arch/socs/stm32f429/soc-dma_regs.h new file mode 120000 index 0000000..4ed831c --- /dev/null +++ b/arch/socs/stm32f429/soc-dma_regs.h @@ -0,0 +1 @@ +../stm32f439/soc-dma_regs.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-dwt.c b/arch/socs/stm32f429/soc-dwt.c new file mode 120000 index 0000000..aadf8fc --- /dev/null +++ b/arch/socs/stm32f429/soc-dwt.c @@ -0,0 +1 @@ +../stm32f439/soc-dwt.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-dwt.h b/arch/socs/stm32f429/soc-dwt.h new file mode 120000 index 0000000..21f8931 --- /dev/null +++ b/arch/socs/stm32f429/soc-dwt.h @@ -0,0 +1 @@ +../stm32f439/soc-dwt.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-exti.c b/arch/socs/stm32f429/soc-exti.c new file mode 120000 index 0000000..ee01a1f --- /dev/null +++ b/arch/socs/stm32f429/soc-exti.c @@ -0,0 +1 @@ +../stm32f439/soc-exti.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-exti.h b/arch/socs/stm32f429/soc-exti.h new file mode 120000 index 0000000..9082a5e --- /dev/null +++ b/arch/socs/stm32f429/soc-exti.h @@ -0,0 +1 @@ +../stm32f439/soc-exti.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-flash.h b/arch/socs/stm32f429/soc-flash.h new file mode 120000 index 0000000..432727b --- /dev/null +++ b/arch/socs/stm32f429/soc-flash.h @@ -0,0 +1 @@ +../stm32f439/soc-flash.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-gpio.c b/arch/socs/stm32f429/soc-gpio.c new file mode 120000 index 0000000..c5e31a2 --- /dev/null +++ b/arch/socs/stm32f429/soc-gpio.c @@ -0,0 +1 @@ +../stm32f439/soc-gpio.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-gpio.h b/arch/socs/stm32f429/soc-gpio.h new file mode 120000 index 0000000..f113102 --- /dev/null +++ b/arch/socs/stm32f429/soc-gpio.h @@ -0,0 +1 @@ +../stm32f439/soc-gpio.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-init.c b/arch/socs/stm32f429/soc-init.c new file mode 120000 index 0000000..f21a74a --- /dev/null +++ b/arch/socs/stm32f429/soc-init.c @@ -0,0 +1 @@ +../stm32f439/soc-init.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-init.h b/arch/socs/stm32f429/soc-init.h new file mode 120000 index 0000000..32a8a06 --- /dev/null +++ b/arch/socs/stm32f429/soc-init.h @@ -0,0 +1 @@ +../stm32f439/soc-init.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-interrupts.c b/arch/socs/stm32f429/soc-interrupts.c new file mode 120000 index 0000000..2699e75 --- /dev/null +++ b/arch/socs/stm32f429/soc-interrupts.c @@ -0,0 +1 @@ +../stm32f439/soc-interrupts.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-interrupts.h b/arch/socs/stm32f429/soc-interrupts.h new file mode 120000 index 0000000..82344d1 --- /dev/null +++ b/arch/socs/stm32f429/soc-interrupts.h @@ -0,0 +1 @@ +../stm32f439/soc-interrupts.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-iwdg.c b/arch/socs/stm32f429/soc-iwdg.c new file mode 120000 index 0000000..8f92f1c --- /dev/null +++ b/arch/socs/stm32f429/soc-iwdg.c @@ -0,0 +1 @@ +../stm32f439/soc-iwdg.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-iwdg.h b/arch/socs/stm32f429/soc-iwdg.h new file mode 120000 index 0000000..cf61c43 --- /dev/null +++ b/arch/socs/stm32f429/soc-iwdg.h @@ -0,0 +1 @@ +../stm32f439/soc-iwdg.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-layout.h b/arch/socs/stm32f429/soc-layout.h new file mode 100644 index 0000000..9c72333 --- /dev/null +++ b/arch/socs/stm32f429/soc-layout.h @@ -0,0 +1,178 @@ +/* \file soc-layout.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_LAYOUT_H +#define SOC_LAYOUT_H + +#include "autoconf.h" + +/* +** About the mapping: here is the flash layout described below +** This mapping is feasable for mono-bank, mono-bank with DFU. +** +** +----------------+0x0800 0000 +** | LDR (64k) | +** +----------------+0x0801 0000 +** | SHR (64k) | +** +----------------+0x0802 0000 +** | FW_k (64k) | +** +----------------+0x0803 0000 +** | DFU_k (64k) | +** + - - - - - - - -+0x0804 0000 +** | | +** | DFU_u (256k) | +** | | +** +----------------+0x0808 0000 +** | | +** | FW_u (512k) | +** | | +** | | +** +----------------+0x0810 0000 +** +*/ + +#ifdef CONFIG_STM32F4 +#define NB_MEM_BANK 1 +#elif defined CONFIG_STM32F42X +#define NB_MEM_BANK 2 +#else +#error "unknown SoC reference layout" +#endif + + +#define KBYTE 1024 +#define FLASH_SIZE 1024*KBYTE +#define VTORS_SIZE 0x188 + +/* + * Mapping + */ +#define LDR_BASE 0x08000000 /* loader */ +#define SHR_BASE 0x08008000 /* shared memory */ + +#define RAM2_BASE 0x10000000 +#define RAM_KERN_BASE 0x10000000 /* 96k user RAM (div by 8 subregions, 12*8, 24*4), starting at RAM size + 32k */ + +/* User tasks */ +#define RAM_BASE 0x20000000 /* 24k kernel RAM + 8k empty */ +#define RAM_USER_BASE RAM_BASE /* 96k user RAM (div by 8 subregions, 12*8, 24*4), starting at RAM size + 32k */ +#define RAM_USER_REGION_SIZE MPU_REGION_SIZE_128Kb /* 96k user RAM (div by 8 subregions, 12*8, 24*4), starting at RAM size + 32k */ + +#define RAM_USER_APPS_BASE RAM_BASE +#define RAM_USER_SIZE 16*KBYTE +#define RAM_USER_APP1_BASE RAM_USER_APPS_BASE +#define RAM_USER_APP2_BASE RAM_USER_APP1_BASE + RAM_USER_SIZE +#define RAM_USER_APP3_BASE RAM_USER_APP2_BASE + RAM_USER_SIZE +#define RAM_USER_APP4_BASE RAM_USER_APP3_BASE + RAM_USER_SIZE +#define RAM_USER_APP5_BASE RAM_USER_APP4_BASE + RAM_USER_SIZE +#define RAM_USER_APP6_BASE RAM_USER_APP5_BASE + RAM_USER_SIZE +#define RAM_USER_APP7_BASE RAM_USER_APP6_BASE + RAM_USER_SIZE +#define RAM_USER_APP8_BASE RAM_USER_APP7_BASE + RAM_USER_SIZE + + +#define FW1_APP1_BASE 0x08080000 +#define FW1_APP2_BASE 0x08090000 +#define FW1_APP3_BASE 0x080a0000 +#define FW1_APP4_BASE 0x080b0000 +#define FW1_APP5_BASE 0x080c0000 +#define FW1_APP6_BASE 0x080d0000 +#define FW1_APP7_BASE 0x080e0000 +#define FW1_APP8_BASE 0x080f0000 + +#define DFU1_APP1_BASE 0x08040000 +#define DFU1_APP2_BASE 0x08048000 +#define DFU1_APP3_BASE 0x08050000 +#define DFU1_APP4_BASE 0x08058000 +#define DFU1_APP5_BASE 0x08060000 +#define DFU1_APP6_BASE 0x08068000 +#define DFU1_APP7_BASE 0x08070000 +#define DFU1_APP8_BASE 0x08078000 + +/* LDR is in the last sub-region (slot 8) */ +#define RAM_LDR_BASE 0x2001c000 +#define RAM_LDR_SIZE 20*KBYTE + +/* + * STM32F4 + */ + + +#define RAM2_SIZE 64*KBYTE +#define RAM_KERN_SIZE RAM2_SIZE +#define LDR_SIZE 128*KBYTE + +/* Flip bank */ + +#define FW1_SIZE 576*KBYTE + +#define FW1_KERN_BASE 0x08020000 +#define FW1_KERN_SIZE 64*KBYTE +#define FW1_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb + +#define FW1_USER_BASE 0x08080000 +#define FW1_USER_SIZE 512*KBYTE +#define FW1_USER_REGION_SIZE MPU_REGION_SIZE_512Kb + +/**** DFU 1 ****/ + +#define DFU1_SIZE 320*KBYTE + +#define DFU1_KERN_BASE 0x08030000 +#define DFU1_USER_BASE 0x08040000 + +#define DFU1_KERN_SIZE 64*KBYTE +#define DFU1_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb +#define DFU1_USER_SIZE 256*KBYTE +#define DFU1_USER_REGION_SIZE MPU_REGION_SIZE_256Kb + + +/* No Flop bank feasable on this SoC, as there is only 1MB flash */ + + +#define RAM2_SIZE 64*KBYTE +#define RAM_KERN_SIZE RAM2_SIZE +#define RAM_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb +#define LDR_SIZE 128*KBYTE + + +#define MB1_BASE 0x60000000 +#define MB2_BASE 0x60000000 +#define MB1_SIZE 0 +#define MB2_SIZE 0 + + +#define FW1_START FW1_KERN_BASE + VTORS_SIZE + 1 + +#define DFU1_START DFU1_KERN_BASE + VTORS_SIZE + 1 + +#define FW_MAX_USER_SIZE 64*KBYTE +#define DFU_MAX_USER_SIZE 32*KBYTE + +/**** Shared mem ****/ +#define SHR_SIZE 32*KBYTE + +/**** SRAM ****/ +#define RAM_SIZE 128*KBYTE + + + +#endif /*!SOC_LAYOUT_H*/ diff --git a/arch/socs/stm32f429/soc-nvic.h b/arch/socs/stm32f429/soc-nvic.h new file mode 120000 index 0000000..45b8ae2 --- /dev/null +++ b/arch/socs/stm32f429/soc-nvic.h @@ -0,0 +1 @@ +../stm32f439/soc-nvic.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-pwr.h b/arch/socs/stm32f429/soc-pwr.h new file mode 120000 index 0000000..5977637 --- /dev/null +++ b/arch/socs/stm32f429/soc-pwr.h @@ -0,0 +1 @@ +../stm32f439/soc-pwr.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-rcc.c b/arch/socs/stm32f429/soc-rcc.c new file mode 120000 index 0000000..9b5f70d --- /dev/null +++ b/arch/socs/stm32f429/soc-rcc.c @@ -0,0 +1 @@ +../stm32f439/soc-rcc.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-rcc.h b/arch/socs/stm32f429/soc-rcc.h new file mode 120000 index 0000000..164b999 --- /dev/null +++ b/arch/socs/stm32f429/soc-rcc.h @@ -0,0 +1 @@ +../stm32f439/soc-rcc.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-rng.c b/arch/socs/stm32f429/soc-rng.c new file mode 120000 index 0000000..0000aea --- /dev/null +++ b/arch/socs/stm32f429/soc-rng.c @@ -0,0 +1 @@ +../stm32f439/soc-rng.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-rng.h b/arch/socs/stm32f429/soc-rng.h new file mode 120000 index 0000000..6fb4714 --- /dev/null +++ b/arch/socs/stm32f429/soc-rng.h @@ -0,0 +1 @@ +../stm32f439/soc-rng.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-scb.h b/arch/socs/stm32f429/soc-scb.h new file mode 120000 index 0000000..ff2add8 --- /dev/null +++ b/arch/socs/stm32f429/soc-scb.h @@ -0,0 +1 @@ +../stm32f439/soc-scb.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-syscfg.h b/arch/socs/stm32f429/soc-syscfg.h new file mode 120000 index 0000000..09e3e99 --- /dev/null +++ b/arch/socs/stm32f429/soc-syscfg.h @@ -0,0 +1 @@ +../stm32f439/soc-syscfg.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-usart-regs.h b/arch/socs/stm32f429/soc-usart-regs.h new file mode 120000 index 0000000..812b5d0 --- /dev/null +++ b/arch/socs/stm32f429/soc-usart-regs.h @@ -0,0 +1 @@ +../stm32f439/soc-usart-regs.h \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-usart.c b/arch/socs/stm32f429/soc-usart.c new file mode 120000 index 0000000..12d2522 --- /dev/null +++ b/arch/socs/stm32f429/soc-usart.c @@ -0,0 +1 @@ +../stm32f439/soc-usart.c \ No newline at end of file diff --git a/arch/socs/stm32f429/soc-usart.h b/arch/socs/stm32f429/soc-usart.h new file mode 120000 index 0000000..794a2f9 --- /dev/null +++ b/arch/socs/stm32f429/soc-usart.h @@ -0,0 +1 @@ +../stm32f439/soc-usart.h \ No newline at end of file diff --git a/arch/socs/stm32f429/startup_stm32f429.s b/arch/socs/stm32f429/startup_stm32f429.s new file mode 100644 index 0000000..bb42645 --- /dev/null +++ b/arch/socs/stm32f429/startup_stm32f429.s @@ -0,0 +1,321 @@ +/** + ****************************************************************************** + * @file startup_stm32f4xx.s + * @author MCD Application Team + * @version V1.0.0 + * @date 30-September-2011 + * @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Configure the clock system and the external SRAM mounted on + * STM324xG-EVAL board to be used as data memory (optional, + * to be enabled by user) + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +.syntax unified +.cpu cortex-m4 +.fpu softvfp +.thumb + +.global g_pfnVectors +.global g_BaseAddress +.global g_StackAddress + +.extern Default_SubHandler + +/* start address for the initialization values of the .data section. defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +.word _sigot +.word _sgot +.word _egot + + +/* +.word _svtors +.word _evtors +*/ +/* + * @brief Globals variables + * @param None + * @retval None + * + */ + +.section .data +g_BaseAddress: + .word 0 +g_StackAddress: + .word 0 + +/* + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval None + */ + +.section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + bl _start /* Entry point address */ +_start: + movs r5, lr + sub r5, #5 /* In thumb mode LR is pointing to PC + 4 bytes + 1 because in thumb mode LR must be odd aligned*/ + sub r2, r5, #0x188 /* Compute vector table address FIXME: We should use dynimic value for VTORS_SIZE */ + ldr r2, [r2] + msr msp, r2 /* Reset stack address to default 0x20002000 */ + + movs r1, #0 + b LoopCopyDataInit +CopyDataInit: /* Copy the data segment initializers from flash to SRAM */ + ldr r3, =_sidata /* start address for the initialization values of the .data section. */ + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 +LoopCopyDataInit: + ldr r0, =_sdata /* start address for the .data section */ + ldr r3, =_edata /* end address for the .data section */ + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + + + ldr r2, =_sbss /* start address for the .bss section */ + b LoopFillZerobss +FillZerobss: /* Zero fill the bss segment. */ + movs r3, #0 + str r3, [r2], #4 +LoopFillZerobss: + ldr r3, = _ebss /* end address for the .bss section */ + cmp r2, r3 + bcc FillZerobss + movs r0, #1 + ldr r1, = g_BaseAddress + str r5, [r1] + dmb + bl main + bx lr + +.size Reset_Handler, .-Reset_Handler + +.section .text.Default_Handler + .weak Default_Handler + .type Default_Handler, %function +Default_Handler: + cpsid i + + /* + * The NVIC has already saved R0-R3, R12, LR, PC and xPSR registers on the + * stack. We save the remaining registers (R4-R11) and LR (with the new + * value) on that previously used stack. + */ + + /* 1) Which stack was previously used ? */ + + tst lr, #4 /* bit 2: (0) MSP (1) PSP stack */ + ite eq /* if equal 0 */ + mrseq r0, msp /* r0 <- MSP */ + mrsne r0, psp /* r0 <- PSP (process stack) */ + + /* + * 2) Save registers on the previously used stack. + * R0 points to the saved registers: + * LR, R4-R11, R0-R3, R12, previous LR, PC, xPSR + */ + + stmfd r0!, {r4-r11, lr} + + /* 3) Adjusting the previously used stack pointer (might be PSP or MSP) */ + + tst lr, #4 /* bit 2: (0) MSP (1) PSP stack */ + ite eq /* if equal 0 */ + msreq msp, r0 /* MSP <- r0 */ + msrne psp, r0 /* PSP <- r0 */ + + /* + * R0 is passed as a parameter. It still points to the saved registers. + * In case of task switching, R0 returned by `Default_SubHandler' might be + * different. + */ + + bl Default_SubHandler + + /* Registers LR, R4-R11 are restored */ + ldmfd r0!, {r4-r11, lr} + + /* Adjusting PSP/MSP so that the NVIC can restore the remaining registers */ + + tst lr, #4 /* bit 2: (0) MSP (1) PSP stack */ + bne psp_use /* if not equal 0 */ + +msp_use: + msr msp, r0 /* MSP <- r0 */ + cpsie i + bx lr + +psp_use: + msr psp, r0 /* PSP <- r0 */ + cmp r1, #1 + bne kern_mode + +user_mode: + mov r0, #3 + msr control, r0 + isb + cpsie i + bx lr + +kern_mode: + mov r0, #2 + msr control, r0 + isb + cpsie i + bx lr +.size Default_Handler, .-Default_Handler + +/****************************************************************************** + * + * The minimal vector table for a Cortex M4. Note that the proper constructs + * must be placed on this to ensure that it ends up at physical address + * 0x0000.0000. + * + ******************************************************************************/ +.section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word Default_Handler + .word Default_Handler + .word Default_Handler + .word Default_Handler + .word Default_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word Default_Handler + .word Default_Handler + .word 0 + .word Default_Handler + .word Default_Handler + + /* + * External Interrupts + */ + .word Default_Handler /* Window WatchDog */ + .word Default_Handler /* PVD through EXTI Line detection */ + .word Default_Handler /* Tamper and TimeStamps through the EXTI line */ + .word Default_Handler /* RTC Wakeup through the EXTI line */ + .word Default_Handler /* FLASH */ + .word Default_Handler /* RCC */ + .word Default_Handler /* EXTI Line0 */ + .word Default_Handler /* EXTI Line1 */ + .word Default_Handler /* EXTI Line2 */ + .word Default_Handler /* EXTI Line3 */ + .word Default_Handler /* EXTI Line4 */ + .word Default_Handler /* DMA1 Stream 0 */ + .word Default_Handler /* DMA1 Stream 1 */ + .word Default_Handler /* DMA1 Stream 2 */ + .word Default_Handler /* DMA1 Stream 3 */ + .word Default_Handler /* DMA1 Stream 4 */ + .word Default_Handler /* DMA1 Stream 5 */ + .word Default_Handler /* DMA1 Stream 6 */ + .word Default_Handler /* ADC1, ADC2 and ADC3s */ + .word Default_Handler /* CAN1 TX */ + .word Default_Handler /* CAN1 RX0 */ + .word Default_Handler /* CAN1 RX1 */ + .word Default_Handler /* CAN1 SCE */ + .word Default_Handler /* External Line[9:5]s */ + .word Default_Handler /* TIM1 Break and TIM9 */ + .word Default_Handler /* TIM1 Update and TIM10 */ + .word Default_Handler /* TIM1 Trigger and Commutation and TIM11 */ + .word Default_Handler /* TIM1 Capture Compare */ + .word Default_Handler /* TIM2 */ + .word Default_Handler /* TIM3 */ + .word Default_Handler /* TIM4 */ + .word Default_Handler /* I2C1 Event */ + .word Default_Handler /* I2C1 Error */ + .word Default_Handler /* I2C2 Event */ + .word Default_Handler /* I2C2 Error */ + .word Default_Handler /* SPI1 */ + .word Default_Handler /* SPI2 */ + .word Default_Handler /* USART1 */ + .word Default_Handler /* USART2 */ + .word Default_Handler /* USART3 */ + .word Default_Handler /* External Line[15:10]s */ + .word Default_Handler /* RTC Alarm (A and B) through EXTI Line */ + .word Default_Handler /* USB OTG FS Wakeup through EXTI line */ + .word Default_Handler /* TIM8 Break and TIM12 */ + .word Default_Handler /* TIM8 Update and TIM13 */ + .word Default_Handler /* TIM8 Trigger and Commutation and TIM14 */ + .word Default_Handler /* TIM8 Capture Compare */ + .word Default_Handler /* DMA1 Stream7 */ + .word Default_Handler /* FSMC */ + .word Default_Handler /* SDIO */ + .word Default_Handler /* TIM5 */ + .word Default_Handler /* SPI3 */ + .word Default_Handler /* UART4 */ + .word Default_Handler /* UART5 */ + .word Default_Handler /* TIM6 and DAC1&2 underrun errors */ + .word Default_Handler /* TIM7 */ + .word Default_Handler /* DMA2 Stream 0 */ + .word Default_Handler /* DMA2 Stream 1 */ + .word Default_Handler /* DMA2 Stream 2 */ + .word Default_Handler /* DMA2 Stream 3 */ + .word Default_Handler /* DMA2 Stream 4 */ + .word Default_Handler /* Ethernet */ + .word Default_Handler /* Ethernet Wakeup through EXTI line */ + .word Default_Handler /* CAN2 TX */ + .word Default_Handler /* CAN2 RX0 */ + .word Default_Handler /* CAN2 RX1 */ + .word Default_Handler /* CAN2 SCE */ + .word Default_Handler /* USB OTG FS */ + .word Default_Handler /* DMA2 Stream 5 */ + .word Default_Handler /* DMA2 Stream 6 */ + .word Default_Handler /* DMA2 Stream 7 */ + .word Default_Handler /* USART6 */ + .word Default_Handler /* I2C3 event */ + .word Default_Handler /* I2C3 error */ + .word Default_Handler /* USB OTG HS End Point 1 Out */ + .word Default_Handler /* USB OTG HS End Point 1 In */ + .word Default_Handler /* USB OTG HS Wakeup through EXTI */ + .word Default_Handler /* USB OTG HS */ + .word Default_Handler /* DCMI */ + .word Default_Handler /* CRYP crypto */ + .word Default_Handler /* Hash and Rng */ + .word Default_Handler /* FPU */ + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/arch/socs/stm32f439/Ada/.placeholder b/arch/socs/stm32f439/Ada/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/arch/socs/stm32f439/Ada/config.def b/arch/socs/stm32f439/Ada/config.def new file mode 120000 index 0000000..2f78398 --- /dev/null +++ b/arch/socs/stm32f439/Ada/config.def @@ -0,0 +1 @@ +../../../../Ada/generated/config.def \ No newline at end of file diff --git a/arch/socs/stm32f439/Ada/default_handlers.adb b/arch/socs/stm32f439/Ada/default_handlers.adb new file mode 100644 index 0000000..038a286 --- /dev/null +++ b/arch/socs/stm32f439/Ada/default_handlers.adb @@ -0,0 +1,31 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package body default_handlers + with spark_mode => off +is + procedure dummy is + begin + null; + end dummy; +end default_handlers; diff --git a/arch/socs/stm32f439/Ada/default_handlers.ads b/arch/socs/stm32f439/Ada/default_handlers.ads new file mode 100644 index 0000000..5ff1f4d --- /dev/null +++ b/arch/socs/stm32f439/Ada/default_handlers.ads @@ -0,0 +1,29 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +-- Dummy package added to avoid default_handlers.c compilation +package default_handlers + with spark_mode => on +is + procedure dummy; +end default_handlers; diff --git a/arch/socs/stm32f439/Ada/soc-devmap.ads.DRAFT b/arch/socs/stm32f439/Ada/soc-devmap.ads.DRAFT new file mode 100644 index 0000000..bad4bb3 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-devmap.ads.DRAFT @@ -0,0 +1,70 @@ + +package soc.devmap + with spark_mode => off +is + + type t_peripheral_id is + (DEV_BKPSRAM, + DEV_RNG + DEV_CRYP + DEV_HASH + DEV_DCMI, + DEV_USB_OTG_FS, DEV_USB_OTG_HS, DEV_USB_OTG_HS_ULPI, + DEV_SDIO, + DEV_DMA1, DEV_DMA2, + DEV_ETH_MAC, DEV_ETH_MAC_TX, DEV_ETH_MAC_RX, DEV_ETH_MAC_PTP, + DEV_CRC, + DEV_USART1, DEV_USART2, DEV_USART3, DEV_UART4, DEV_UART5, DEV_USART6, + DEV_UART7, DEV_UART8, + DEV_SYSCFG, + DEV_NVIC, + DEV_WWDG, + DEV_PWR, + DEV_DAC, + DEV_SPI1, DEV_SPI2, DEV_SPI3, + DEV_I2C1, DEV_I2C2, DEV_I2C3, + DEV_CAN1, DEV_CAN2, + DEV_GPIOA, DEV_GPIOB, DEV_GPIOC, DEV_GPIOD, DEV_GPIOE, DEV_GPIOF, + DEV_GPIOG, DEV_GPIOH, DEV_GPIOI, + DEV_TIM1, DEV_TIM2, DEV_TIM3, DEV_TIM4, DEV_TIM5, DEV_TIM6, DEV_TIM7, + DEV_TIM8, DEV_TIM9, DEV_TIM10, DEV_TIM11, DEV_TIM12, DEV_TIM13, + DEV_TIM14, + DEV_ADC1, DEV_ADC2, DEV_ADC3); + + type t_device_soc_infos is record + id : t_peripheral_id; + base_addr : system_address; -- MMIO base address + size : unsigned_16; + subregions : unsigned_8; + intr_num : unsigned_8; + ro : boolean; + minperm : ewok.perm.t_perm_name; + end record; + + subtype irq is unsigned_8 range 0 .. 127; + type t_device_irqs is array (1 .. 8) of irq; + + type t_peripheral is record + id : t_peripheral_id; -- device identifier (enum) + address : system_address; -- device's address + size : device_size; -- device size in memory + irqs : t_device_irqs; -- list of device's IRQ. 0 in a cell indicate 'no irq' + subregions : unsigned_8; + readonly : boolean; + end record; + + device_map : t_device_specs := + ((id => DEV_RNG, + address => 16#50060800#, + size => 16#400#, + irqs => (0,0,0,0,0,0,0,0), + subregions => 0, + readonly => false), + (id => DEV_CRYP, + address => 16#50060000#, + size => 16#1000#, + irqs => (0,0,0,0,0,0,0,0), + subregions => 0, + readonly => false)); + +end soc.devmap; diff --git a/arch/socs/stm32f439/Ada/soc-dma-interfaces.adb b/arch/socs/stm32f439/Ada/soc-dma-interfaces.adb new file mode 100644 index 0000000..ad53409 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-dma-interfaces.adb @@ -0,0 +1,353 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ada.unchecked_conversion; + +package body soc.dma.interfaces + with spark_mode => off +is + + procedure enable_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index) + is + begin + case dma_id is + when ID_DMA1 => soc.dma.enable (soc.dma.DMA1, stream); + when ID_DMA2 => soc.dma.enable (soc.dma.DMA2, stream); + end case; + end enable_stream; + + + procedure disable_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index) + is + begin + case dma_id is + when ID_DMA1 => soc.dma.disable (soc.dma.DMA1, stream); + when ID_DMA2 => soc.dma.disable (soc.dma.DMA2, stream); + end case; + end disable_stream; + + + procedure clear_interrupt + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index; + interrupt : in t_dma_interrupts) + is + reg : t_dma_stream_clear_interrupts := (others => false); + begin + case interrupt is + when FIFO_ERROR => reg.CLEAR_FIFO_ERROR := true; + when DIRECT_MODE_ERROR => reg.CLEAR_DIRECT_MODE_ERROR := true; + when TRANSFER_ERROR => reg.CLEAR_TRANSFER_ERROR := true; + when HALF_COMPLETE => reg.CLEAR_HALF_TRANSFER := true; + when TRANSFER_COMPLETE => reg.CLEAR_TRANSFER_COMPLETE := true; + end case; + case dma_id is + when ID_DMA1 => set_IFCR (soc.dma.DMA1, stream, reg); + when ID_DMA2 => set_IFCR (soc.dma.DMA2, stream, reg); + end case; + end clear_interrupt; + + + procedure clear_all_interrupts + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index) + is + begin + case dma_id is + when ID_DMA1 => soc.dma.clear_all_interrupts (soc.dma.DMA1, stream); + when ID_DMA2 => soc.dma.clear_all_interrupts (soc.dma.DMA2, stream); + end case; + end clear_all_interrupts; + + + function get_interrupt_status + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index) + return t_dma_stream_int_status + is + begin + case dma_id is + when ID_DMA1 => + return soc.dma.get_interrupt_status (soc.dma.DMA1, stream); + when ID_DMA2 => + return soc.dma.get_interrupt_status (soc.dma.DMA2, stream); + end case; + end get_interrupt_status; + + + procedure configure_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index; + user_config : in t_dma_config) -- FIXME - duplicate ewok.exported + is + controller : t_dma_periph_access; + size : unsigned_16; -- Number of data items to transfer + begin + + case dma_id is + when ID_DMA1 => controller := soc.dma.DMA1'access; + when ID_DMA2 => controller := soc.dma.DMA2'access; + end case; + + controller.streams(stream).CR.EN := false; + + -- Direction + -- The conversion below is due to the difference of representation + -- between the field in the CR register and the more abstract + -- type manipulated by the soc.dma.interfaces sub-package. + controller.streams(stream).CR.DIR := + soc.dma.t_transfer_dir'val + (t_transfer_dir'pos (user_config.transfer_dir)); + + -- Input and output addresses + case user_config.transfer_dir is + when PERIPHERAL_TO_MEMORY => + controller.streams(stream).PAR := user_config.in_addr; + controller.streams(stream).M0AR := user_config.out_addr; + + when MEMORY_TO_PERIPHERAL => + controller.streams(stream).M0AR := user_config.in_addr; + controller.streams(stream).PAR := user_config.out_addr; + + when MEMORY_TO_MEMORY => + controller.streams(stream).PAR := user_config.in_addr; + controller.streams(stream).M0AR := user_config.out_addr; + end case; + + -- Channel selection + controller.streams(stream).CR.CHSEL := user_config.channel; + + -- Burst size (single, 4 beats, 8 beats or 16 beats) + controller.streams(stream).CR.MBURST := + soc.dma.t_burst_size'val + (t_burst_size'pos (user_config.mem_burst_size)); + + controller.streams(stream).CR.PBURST := + soc.dma.t_burst_size'val + (t_burst_size'pos (user_config.periph_burst_size)); + + -- Current target + controller.streams(stream).CR.CT := MEMORY_0; + + -- Double buffer mode + controller.streams(stream).CR.DBM := false; + + -- Peripheral incr. size (PSIZE or WORD) + controller.streams(stream).CR.PINCOS := INCREMENT_PSIZE; + + -- Memory and peripheral data size (byte, half word or word) + controller.streams(stream).CR.MSIZE := + soc.dma.t_data_size'val (t_data_size'pos (user_config.data_size)); + controller.streams(stream).CR.PSIZE := + soc.dma.t_data_size'val (t_data_size'pos (user_config.data_size)); + + -- Set if address pointer is incremented after each data transfer + controller.streams(stream).CR.MINC := user_config.memory_inc; + controller.streams(stream).CR.PINC := user_config.periph_inc; + + -- Circular mode is disabled + controller.streams(stream).CR.CIRC := false; + + -- DMA or peripheral flow controller + controller.streams(stream).CR.PFCTRL := + soc.dma.t_flow_controller'val + (t_flow_controller'pos (user_config.flow_controller)); + + -- Number of data items to transfer + if user_config.flow_controller = DMA_FLOW_CONTROLLER then + + -- In direct mode, item size in the DMA bufsize register is + -- calculated using the data_size unit. In FIFO/circular mode, + -- the increment is always in bytes. + if user_config.mode = DIRECT_MODE then + case user_config.data_size is + when TRANSFER_BYTE => size := user_config.bytes; + when TRANSFER_HALF_WORD => size := user_config.bytes / 2; + when TRANSFER_WORD => size := user_config.bytes / 4; + end case; + else + size := user_config.bytes; + end if; + + controller.streams(stream).NDTR.NDT := size; + end if; + + -- Priority + if user_config.transfer_dir = PERIPHERAL_TO_MEMORY then + -- Memory is the destination + controller.streams(stream).CR.PL := soc.dma.t_priority_level'val + (t_priority_level'pos (user_config.out_priority)); + else + -- Memory is the source + controller.streams(stream).CR.PL := soc.dma.t_priority_level'val + (t_priority_level'pos (user_config.in_priority)); + end if; + + -- Enable interrupts + case user_config.mode is + when DIRECT_MODE => + controller.streams(stream).FCR.FIFO_ERROR := false; + controller.streams(stream).CR.DIRECT_MODE_ERROR := true; + controller.streams(stream).CR.TRANSFER_ERROR := true; + controller.streams(stream).CR.TRANSFER_COMPLETE := true; + + when FIFO_MODE => + controller.streams(stream).FCR.DMDIS := true; -- Disable direct mode + controller.streams(stream).FCR.FIFO_ERROR := true; + controller.streams(stream).FCR.FTH := FIFO_FULL; + controller.streams(stream).CR.TRANSFER_ERROR := true; + controller.streams(stream).CR.TRANSFER_COMPLETE := true; + + when CIRCULAR_MODE => + if user_config.transfer_dir = MEMORY_TO_MEMORY then + raise program_error; -- Not implemented + end if; + controller.streams(stream).FCR.DMDIS := true; -- Disable direct mode + controller.streams(stream).FCR.FIFO_ERROR := false; + controller.streams(stream).CR.CIRC := true; -- Enable circular mode + controller.streams(stream).CR.TRANSFER_ERROR := true; + controller.streams(stream).CR.TRANSFER_COMPLETE := true; + end case; + + end configure_stream; + + + procedure reconfigure_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index; + user_config : in t_dma_config; -- FIXME - duplicate ewok.exported + to_configure: in t_config_mask) + is + controller : t_dma_periph_access; + size : unsigned_16; -- Number of data items to transfer + begin + + case dma_id is + when ID_DMA1 => controller := soc.dma.DMA1'access; + when ID_DMA2 => controller := soc.dma.DMA2'access; + end case; + + controller.streams(stream).CR.EN := false; + + -- Direction + controller.streams(stream).CR.DIR := + soc.dma.t_transfer_dir'val + (t_transfer_dir'pos (user_config.transfer_dir)); + + -- Input and output addresses + case user_config.transfer_dir is + when PERIPHERAL_TO_MEMORY => + controller.streams(stream).PAR := user_config.in_addr; + controller.streams(stream).M0AR := user_config.out_addr; + + when MEMORY_TO_PERIPHERAL => + controller.streams(stream).M0AR := user_config.in_addr; + controller.streams(stream).PAR := user_config.out_addr; + + when MEMORY_TO_MEMORY => + controller.streams(stream).PAR := user_config.in_addr; + controller.streams(stream).M0AR := user_config.out_addr; + end case; + + -- Number of data items to transfer + if user_config.flow_controller = DMA_FLOW_CONTROLLER then + -- In direct mode, item size in the DMA bufsize register is + -- calculated using the data_size unit. In FIFO/circular mode, + -- the increment is always in bytes. + if user_config.mode = DIRECT_MODE then + case user_config.data_size is + when TRANSFER_BYTE => size := user_config.bytes; + when TRANSFER_HALF_WORD => size := user_config.bytes / 2; + when TRANSFER_WORD => size := user_config.bytes / 4; + end case; + else + size := user_config.bytes; + end if; + + controller.streams(stream).NDTR.NDT := size; + end if; + + -- Priority + if to_configure.priority then + if user_config.transfer_dir = PERIPHERAL_TO_MEMORY then + -- Memory is the destination + controller.streams(stream).CR.PL := soc.dma.t_priority_level'val + (t_priority_level'pos (user_config.out_priority)); + else + -- Memory is the source + controller.streams(stream).CR.PL := soc.dma.t_priority_level'val + (t_priority_level'pos (user_config.in_priority)); + end if; + end if; + + -- Enable interrupts + if to_configure.mode then + case user_config.mode is + when DIRECT_MODE => + controller.streams(stream).FCR.FIFO_ERROR := false; + controller.streams(stream).CR.DIRECT_MODE_ERROR := true; + controller.streams(stream).CR.TRANSFER_ERROR := true; + controller.streams(stream).CR.TRANSFER_COMPLETE := true; + + when FIFO_MODE => + controller.streams(stream).FCR.DMDIS := true; -- Disable direct mode + + controller.streams(stream).FCR.FIFO_ERROR := true; + controller.streams(stream).FCR.FTH := FIFO_FULL; + controller.streams(stream).CR.TRANSFER_ERROR := true; + controller.streams(stream).CR.TRANSFER_COMPLETE := true; + + when CIRCULAR_MODE => + if user_config.transfer_dir = MEMORY_TO_MEMORY then + raise program_error; -- Not implemented + end if; + controller.streams(stream).FCR.DMDIS := true; -- Disable direct mode + controller.streams(stream).FCR.FIFO_ERROR := false; + controller.streams(stream).CR.CIRC := true; -- Enable circular mode + controller.streams(stream).CR.TRANSFER_ERROR := true; + controller.streams(stream).CR.TRANSFER_COMPLETE := true; + + end case; + end if; + + end reconfigure_stream; + + + procedure reset_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index) + is + begin + case dma_id is + when ID_DMA1 => + soc.dma.reset_stream (soc.dma.DMA1, stream); + when ID_DMA2 => + soc.dma.reset_stream (soc.dma.DMA2, stream); + end case; + end reset_stream; + + +end soc.dma.interfaces; diff --git a/arch/socs/stm32f439/Ada/soc-dma-interfaces.ads b/arch/socs/stm32f439/Ada/soc-dma-interfaces.ads new file mode 100644 index 0000000..c8cf369 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-dma-interfaces.ads @@ -0,0 +1,124 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package soc.dma.interfaces + with spark_mode => off +is + + type t_dma_interrupts is + (FIFO_ERROR, DIRECT_MODE_ERROR, TRANSFER_ERROR, + HALF_COMPLETE, TRANSFER_COMPLETE); + + type t_config_mask is record + handlers : boolean; + buffer_in : boolean; + buffer_out : boolean; + buffer_size : boolean; + mode : boolean; + priority : boolean; + direction : boolean; + end record; + + for t_config_mask use record + handlers at 0 range 0 .. 0; + buffer_in at 0 range 1 .. 1; + buffer_out at 0 range 2 .. 2; + buffer_size at 0 range 3 .. 3; + mode at 0 range 4 .. 4; + priority at 0 range 5 .. 5; + direction at 0 range 6 .. 6; + end record; + + type t_mode is (DIRECT_MODE, FIFO_MODE, CIRCULAR_MODE); + + type t_transfer_dir is + (PERIPHERAL_TO_MEMORY, MEMORY_TO_PERIPHERAL, MEMORY_TO_MEMORY); + + type t_priority_level is (LOW, MEDIUM, HIGH, VERY_HIGH); + + type t_data_size is (TRANSFER_BYTE, TRANSFER_HALF_WORD, TRANSFER_WORD); + + type t_burst_size is + (SINGLE_TRANSFER, INCR_4_BEATS, INCR_8_BEATS, INCR_16_BEATS); + + type t_flow_controller is (DMA_FLOW_CONTROLLER, PERIPH_FLOW_CONTROLLER); + + type t_dma_config is record + dma_id : soc.dma.t_dma_periph_index; + stream : soc.dma.t_stream_index; + channel : soc.dma.t_channel_index; + bytes : unsigned_16; + in_addr : system_address; + in_priority : t_priority_level; + in_handler : system_address; -- ISR + out_addr : system_address; + out_priority : t_priority_level; + out_handler : system_address; -- ISR + flow_controller : t_flow_controller; + transfer_dir : t_transfer_dir; + mode : t_mode; + data_size : t_data_size; + memory_inc : boolean; + periph_inc : boolean; + mem_burst_size : t_burst_size; + periph_burst_size : t_burst_size; + end record; + + procedure enable_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index); + + procedure disable_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index); + + procedure clear_interrupt + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index; + interrupt : in t_dma_interrupts); + + procedure clear_all_interrupts + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index); + + function get_interrupt_status + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index) + return t_dma_stream_int_status; + + procedure configure_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index; + user_config : in t_dma_config); -- FIXME - duplicate ewok.exported + + procedure reconfigure_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index; + user_config : in t_dma_config; -- FIXME - duplicate ewok.exported + to_configure: in t_config_mask); + + procedure reset_stream + (dma_id : in soc.dma.t_dma_periph_index; + stream : in soc.dma.t_stream_index); + +end soc.dma.interfaces; diff --git a/arch/socs/stm32f439/Ada/soc-dma.adb b/arch/socs/stm32f439/Ada/soc-dma.adb new file mode 100644 index 0000000..6e1ed74 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-dma.adb @@ -0,0 +1,189 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.interrupts; use soc.interrupts; +with soc.rcc; + + +package body soc.dma + with spark_mode => off +is + + procedure enable_clocks + is + begin + soc.rcc.RCC.AHB1.DMA1EN := true; + soc.rcc.RCC.AHB1.DMA2EN := true; + end enable_clocks; + + + procedure enable + (controller : in out t_dma_periph; + stream : in t_stream_index) + is begin + controller.streams(stream).CR.EN := true; + end enable; + + + procedure disable + (controller : in out t_dma_periph; + stream : in t_stream_index) + is begin + controller.streams(stream).CR.EN := false; + end disable; + + + procedure get_dma_stream_from_interrupt + (intr : in soc.interrupts.t_interrupt; + dma_id : out t_dma_periph_index; + stream : out t_stream_index; + success : out boolean) + is + begin + case intr is + when INT_DMA1_STREAM0 => dma_id := ID_DMA1; stream := 0; success := true; + when INT_DMA1_STREAM1 => dma_id := ID_DMA1; stream := 1; success := true; + when INT_DMA1_STREAM2 => dma_id := ID_DMA1; stream := 2; success := true; + when INT_DMA1_STREAM3 => dma_id := ID_DMA1; stream := 3; success := true; + when INT_DMA1_STREAM4 => dma_id := ID_DMA1; stream := 4; success := true; + when INT_DMA1_STREAM5 => dma_id := ID_DMA1; stream := 5; success := true; + when INT_DMA1_STREAM6 => dma_id := ID_DMA1; stream := 6; success := true; + when INT_DMA1_STREAM7 => dma_id := ID_DMA1; stream := 7; success := true; + when INT_DMA2_STREAM0 => dma_id := ID_DMA2; stream := 0; success := true; + when INT_DMA2_STREAM1 => dma_id := ID_DMA2; stream := 1; success := true; + when INT_DMA2_STREAM2 => dma_id := ID_DMA2; stream := 2; success := true; + when INT_DMA2_STREAM3 => dma_id := ID_DMA2; stream := 3; success := true; + when INT_DMA2_STREAM4 => dma_id := ID_DMA2; stream := 4; success := true; + when INT_DMA2_STREAM5 => dma_id := ID_DMA2; stream := 5; success := true; + when INT_DMA2_STREAM6 => dma_id := ID_DMA2; stream := 6; success := true; + when INT_DMA2_STREAM7 => dma_id := ID_DMA2; stream := 7; success := true; + when others => success := false; + end case; + end get_dma_stream_from_interrupt; + + + function soc_is_dma_irq + (intr : soc.interrupts.t_interrupt) + return boolean + is + dma_id : soc.dma.t_dma_periph_index; + stream : soc.dma.t_stream_index; + ok : boolean; + begin + soc.dma.get_dma_stream_from_interrupt (intr, dma_id, stream, ok); + return ok; + end soc_is_dma_irq; + + + function get_interrupt_status + (controller : t_dma_periph; + stream : t_stream_index) return t_dma_stream_int_status + is + status : t_dma_stream_int_status; + begin + case stream is + when 0 => status := controller.LISR.stream_0; + when 1 => status := controller.LISR.stream_1; + when 2 => status := controller.LISR.stream_2; + when 3 => status := controller.LISR.stream_3; + when 4 => status := controller.HISR.stream_4; + when 5 => status := controller.HISR.stream_5; + when 6 => status := controller.HISR.stream_6; + when 7 => status := controller.HISR.stream_7; + end case; + return status; + end get_interrupt_status; + + + procedure set_IFCR + (controller : in out t_dma_periph; + stream : in t_stream_index; + IFCR : in t_dma_stream_clear_interrupts) + is + begin + case stream is + when 0 => controller.LIFCR.stream_0 := IFCR; + when 1 => controller.LIFCR.stream_1 := IFCR; + when 2 => controller.LIFCR.stream_2 := IFCR; + when 3 => controller.LIFCR.stream_3 := IFCR; + when 4 => controller.HIFCR.stream_4 := IFCR; + when 5 => controller.HIFCR.stream_5 := IFCR; + when 6 => controller.HIFCR.stream_6 := IFCR; + when 7 => controller.HIFCR.stream_7 := IFCR; + end case; + end set_IFCR; + + + procedure clear_all_interrupts + (controller : in out t_dma_periph; + stream : in t_stream_index) + is + IFCR : constant t_dma_stream_clear_interrupts := (others => true); + begin + set_IFCR (controller, stream, IFCR); + end clear_all_interrupts; + + + procedure reset_stream + (controller : in out t_dma_periph; + stream : in t_stream_index) + is + begin + + controller.streams(stream).CR.EN := false; + + -- FIXME - We really need this? + loop + exit when controller.streams(stream).CR.EN = false; + end loop; + + clear_all_interrupts (controller, stream); + + -- Setting default values to CR register + controller.streams(stream).CR := (others => <>); + + controller.streams(stream).NDTR.NDT := 0; + controller.streams(stream).PAR := 0; + controller.streams(stream).M0AR := 0; + controller.streams(stream).M1AR := 0; + + -- Setting default values to FCR register + controller.streams(stream).FCR := (others => <>); + + end reset_stream; + + + procedure reset_streams + is + begin + + for stream in t_stream_index'range loop + reset_stream (DMA1, stream); + end loop; + + for stream in t_stream_index'range loop + reset_stream (DMA2, stream); + end loop; + + end reset_streams; + +end soc.dma; diff --git a/arch/socs/stm32f439/Ada/soc-dma.ads b/arch/socs/stm32f439/Ada/soc-dma.ads new file mode 100644 index 0000000..e69ff0a --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-dma.ads @@ -0,0 +1,414 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.layout; +with soc.interrupts; +with system; + +package soc.dma + with spark_mode => off +is + + type t_dma_periph_index is (ID_DMA1, ID_DMA2); + for t_dma_periph_index use (ID_DMA1 => 1, ID_DMA2 => 2); + + type t_stream_index is range 0 .. 7; + type t_channel_index is range 0 .. 7 with size => 3; + + ------------------------------------------ + -- DMA interrupt status registers (ISR) -- + ------------------------------------------ + + type t_dma_stream_int_status is record + -- Stream FIFO error interrupt flag (FEIF) + FIFO_ERROR : boolean; + -- Stream direct mode error interrupt flag (DMEIF) + DIRECT_MODE_ERROR : boolean; + -- Stream transfer error interrupt flag (TEIF) + TRANSFER_ERROR : boolean; + -- Stream half transfer interrupt flag (HTIF) + HALF_COMPLETE : boolean; + -- Stream transfer complete interrupt flag (TCIF) + TRANSFER_COMPLETE : boolean; + end record + with size => 6; + + for t_dma_stream_int_status use record + FIFO_ERROR at 0 range 0 .. 0; + DIRECT_MODE_ERROR at 0 range 2 .. 2; + TRANSFER_ERROR at 0 range 3 .. 3; + HALF_COMPLETE at 0 range 4 .. 4; + TRANSFER_COMPLETE at 0 range 5 .. 5; + end record; + + -- + -- DMA low interrupt status register (DMA_LISR) + -- + + type t_DMA_LISR is record + stream_0 : t_dma_stream_int_status; + stream_1 : t_dma_stream_int_status; + reserved_12_15 : bits_4; + stream_2 : t_dma_stream_int_status; + stream_3 : t_dma_stream_int_status; + reserved_28_31 : bits_4; + end record + with pack, size => 32, volatile_full_access; + + -- + -- DMA high interrupt status register (DMA_HISR) + -- + + type t_DMA_HISR is record + stream_4 : t_dma_stream_int_status; + stream_5 : t_dma_stream_int_status; + reserved_12_15 : bits_4; + stream_6 : t_dma_stream_int_status; + stream_7 : t_dma_stream_int_status; + reserved_28_31 : bits_4; + end record + with pack, size => 32, volatile_full_access; + + ---------------------------------------- + -- DMA interrupt flag clear registers -- + ---------------------------------------- + + type t_dma_stream_clear_interrupts is record + -- Stream clear FIFO error interrupt flag (CFEIF) + CLEAR_FIFO_ERROR : boolean; + -- Stream clear direct mode error interrupt flag (CDMEIF) + CLEAR_DIRECT_MODE_ERROR : boolean; + -- Stream clear transfer error interrupt flag (CTEIF) + CLEAR_TRANSFER_ERROR : boolean; + -- Stream clear half transfer interrupt flag (CHTIF) + CLEAR_HALF_TRANSFER : boolean; + -- Stream clear transfer complete interrupt flag (CTCIF) + CLEAR_TRANSFER_COMPLETE : boolean; + end record + with size => 6; + + for t_dma_stream_clear_interrupts use record + CLEAR_FIFO_ERROR at 0 range 0 .. 0; + CLEAR_DIRECT_MODE_ERROR at 0 range 2 .. 2; + CLEAR_TRANSFER_ERROR at 0 range 3 .. 3; + CLEAR_HALF_TRANSFER at 0 range 4 .. 4; + CLEAR_TRANSFER_COMPLETE at 0 range 5 .. 5; + end record; + + -- + -- DMA low interrupt flag clear register (DMA_LIFCR) + -- + + type t_DMA_LIFCR is record + stream_0 : t_dma_stream_clear_interrupts; + stream_1 : t_dma_stream_clear_interrupts; + reserved_12_15 : bits_4; + stream_2 : t_dma_stream_clear_interrupts; + stream_3 : t_dma_stream_clear_interrupts; + reserved_28_31 : bits_4; + end record + with pack, size => 32, volatile_full_access; + + -- + -- DMA high interrupt flag clear register (DMA_HIFCR) + -- + + type t_DMA_HIFCR is record + stream_4 : t_dma_stream_clear_interrupts; + stream_5 : t_dma_stream_clear_interrupts; + reserved_12_15 : bits_4; + stream_6 : t_dma_stream_clear_interrupts; + stream_7 : t_dma_stream_clear_interrupts; + reserved_28_31 : bits_4; + end record + with pack, size => 32, volatile_full_access; + + + ---------------------------------------------------- + -- DMA stream x configuration register (DMA_SxCR) -- + ---------------------------------------------------- + + type t_flow_controller is (DMA_FLOW_CONTROLLER, PERIPH_FLOW_CONTROLLER) + with size => 1; + for t_flow_controller use + (DMA_FLOW_CONTROLLER => 0, + PERIPH_FLOW_CONTROLLER => 1); + + type t_transfer_dir is + (PERIPHERAL_TO_MEMORY, MEMORY_TO_PERIPHERAL, MEMORY_TO_MEMORY) + with size => 2; + for t_transfer_dir use + (PERIPHERAL_TO_MEMORY => 2#00#, + MEMORY_TO_PERIPHERAL => 2#01#, + MEMORY_TO_MEMORY => 2#10#); + + type t_data_size is + (TRANSFER_BYTE, TRANSFER_HALF_WORD, TRANSFER_WORD) + with size => 2; + for t_data_size use + (TRANSFER_BYTE => 2#00#, + TRANSFER_HALF_WORD => 2#01#, + TRANSFER_WORD => 2#10#); + + type t_increment_offset_size is (INCREMENT_PSIZE, INCREMENT_WORD) + with size => 1; + for t_increment_offset_size use + (INCREMENT_PSIZE => 0, + INCREMENT_WORD => 1); + + type t_priority_level is (LOW, MEDIUM, HIGH, VERY_HIGH) with size => 2; + for t_priority_level use + (LOW => 2#00#, + MEDIUM => 2#01#, + HIGH => 2#10#, + VERY_HIGH => 2#11#); + + type t_current_target is (MEMORY_0, MEMORY_1) with size => 1; + for t_current_target use + (MEMORY_0 => 0, + MEMORY_1 => 1); + + type t_burst_size is + (SINGLE_TRANSFER, INCR_4_BEATS, INCR_8_BEATS, INCR_16_BEATS) + with size => 2; + for t_burst_size use + (SINGLE_TRANSFER => 2#00#, + INCR_4_BEATS => 2#01#, + INCR_8_BEATS => 2#10#, + INCR_16_BEATS => 2#11#); + + type t_DMA_SxCR is record + EN : boolean := false; -- Stream enable + DIRECT_MODE_ERROR : boolean := false; -- DMEIE + TRANSFER_ERROR : boolean := false; -- TEIE + HALF_COMPLETE : boolean := false; -- HTIE + TRANSFER_COMPLETE : boolean := false; -- TCIE + PFCTRL : t_flow_controller := DMA_FLOW_CONTROLLER; + DIR : t_transfer_dir := PERIPHERAL_TO_MEMORY; + CIRC : boolean := false; -- Circular mode enable + PINC : boolean := false; -- Peripheral incr. mode enable + MINC : boolean := false; -- Memory incr. mode enable + PSIZE : t_data_size := TRANSFER_BYTE; -- Peripheral data size + MSIZE : t_data_size := TRANSFER_BYTE; -- Memory data size + PINCOS : t_increment_offset_size := INCREMENT_PSIZE; + PL : t_priority_level := LOW; + DBM : boolean := false; -- Double buffer mode + CT : t_current_target := MEMORY_0; + reserved_20 : bit := 0; + PBURST : t_burst_size := SINGLE_TRANSFER; -- Periph. burst transfer + MBURST : t_burst_size := SINGLE_TRANSFER; -- Memory burst transfer + CHSEL : t_channel_index := 0; -- Channel selection (0..7) + reserved_28_31 : bits_4 := 0; + end record + with size => 32, volatile_full_access; + + for t_DMA_SxCR use record + EN at 0 range 0 .. 0; + DIRECT_MODE_ERROR at 0 range 1 .. 1; + TRANSFER_ERROR at 0 range 2 .. 2; + HALF_COMPLETE at 0 range 3 .. 3; + TRANSFER_COMPLETE at 0 range 4 .. 4; + PFCTRL at 0 range 5 .. 5; + DIR at 0 range 6 .. 7; + CIRC at 0 range 8 .. 8; + PINC at 0 range 9 .. 9; + MINC at 0 range 10 .. 10; + PSIZE at 0 range 11 .. 12; + MSIZE at 0 range 13 .. 14; + PINCOS at 0 range 15 .. 15; + PL at 0 range 16 .. 17; + DBM at 0 range 18 .. 18; + CT at 0 range 19 .. 19; + reserved_20 at 0 range 20 .. 20; + PBURST at 0 range 21 .. 22; + MBURST at 0 range 23 .. 24; + CHSEL at 0 range 25 .. 27; + reserved_28_31 at 0 range 28 .. 31; + end record; + + ------------------------------------------------------- + -- DMA stream x number of data register (DMA_SxNDTR) -- + ------------------------------------------------------- + + type t_DMA_SxNDTR is record + NDT : short; + -- Number of data items to be transferred (0 up to 65535) + reserved_16_31 : short; + end record + with pack, size => 32, volatile_full_access; + + ---------------------------------------------------------- + -- DMA stream x peripheral address register (DMA_SxPAR) -- + ---------------------------------------------------------- + + subtype t_DMA_SxPAR is system_address; + + --------------------------------------------------------- + -- DMA stream x memory 0 address register (DMA_SxM0AR) -- + --------------------------------------------------------- + + subtype t_DMA_SxM0AR is system_address; + + --------------------------------------------------------- + -- DMA stream x memory 1 address register (DMA_SxM1AR) -- + --------------------------------------------------------- + + subtype t_DMA_SxM1AR is system_address; + + ---------------------------------------------------- + -- DMA stream x FIFO control register (DMA_SxFCR) -- + ---------------------------------------------------- + + type t_FIFO_threshold is + (FIFO_1DIV4_FULL, FIFO_1DIV2_FULL, FIFO_3DIV4_FULL, FIFO_FULL) + with size => 2; + + for t_FIFO_threshold use + (FIFO_1DIV4_FULL => 2#00#, + FIFO_1DIV2_FULL => 2#01#, + FIFO_3DIV4_FULL => 2#10#, + FIFO_FULL => 2#11#); + + type t_FIFO_status is + (FIFO_LESS_1DIV4, + FIFO_LESS_1DIV2, + FIFO_LESS_3DIV4, + FIFO_LESS_FULL, + FIFO_IS_EMPTY, + FIFO_IS_FULL) + with size => 3; + + for t_FIFO_status use + (FIFO_LESS_1DIV4 => 2#000#, + FIFO_LESS_1DIV2 => 2#001#, + FIFO_LESS_3DIV4 => 2#010#, + FIFO_LESS_FULL => 2#011#, + FIFO_IS_EMPTY => 2#100#, + FIFO_IS_FULL => 2#101#); + + type t_DMA_SxFCR is record + FTH : t_FIFO_threshold := FIFO_1DIV2_FULL; -- FIFO threshold + DMDIS : boolean := false; -- Direct mode disable + FS : t_FIFO_status := FIFO_IS_EMPTY; -- FIFO status + reserved_6 : bit := 0; + FIFO_ERROR : boolean := false; -- FIFO error intr. enable (FEIE) + reserved_8_15 : byte := 0; + reserved_16_31 : short := 0; + end record + with pack, size => 32, volatile_full_access; + + -------------------- + -- DMA peripheral -- + -------------------- + + type t_stream_registers is record + CR : t_DMA_SxCR; -- Control register + NDTR : t_DMA_SxNDTR; -- Number of data register + PAR : t_DMA_SxPAR; -- Peripheral address register + M0AR : t_DMA_SxM0AR; -- memory 0 address register + M1AR : t_DMA_SxM1AR; -- memory 1 address register + FCR : t_DMA_SxFCR; -- FIFO control register + end record + with volatile; + + for t_stream_registers use record + CR at 16#00# range 0 .. 31; + NDTR at 16#04# range 0 .. 31; + PAR at 16#08# range 0 .. 31; + M0AR at 16#0C# range 0 .. 31; + M1AR at 16#10# range 0 .. 31; + FCR at 16#14# range 0 .. 31; + end record; + + type t_streams_registers is array (t_stream_index) of t_stream_registers + with pack; + + type t_dma_periph is record + LISR : t_DMA_LISR; -- Interrupt status register (0 .. 3) + HISR : t_DMA_HISR; -- Interrupt status register (4 .. 7) + LIFCR : t_DMA_LIFCR; -- Interrupt clear register (0 .. 3) + HIFCR : t_DMA_HIFCR; -- Interrupt clear register (4 .. 7) + streams : t_streams_registers; + end record + with volatile; + + for t_dma_periph use record + LISR at 16#00# range 0 .. 31; + HISR at 16#04# range 0 .. 31; + LIFCR at 16#08# range 0 .. 31; + HIFCR at 16#0C# range 0 .. 31; + streams at 16#10# range 0 .. (32 * 6 * 8) - 1; + end record; + + type t_dma_periph_access is access all t_dma_periph; + + DMA1 : aliased t_dma_periph + with import, volatile, address => system'to_address (soc.layout.DMA1_BASE); + + DMA2 : aliased t_dma_periph + with import, volatile, address => system'to_address (soc.layout.DMA2_BASE); + + + --------------- + -- Utilities -- + --------------- + + procedure enable_clocks; + + procedure enable + (controller : in out t_dma_periph; + stream : in t_stream_index); + + procedure disable + (controller : in out t_dma_periph; + stream : in t_stream_index); + + procedure get_dma_stream_from_interrupt + (intr : in soc.interrupts.t_interrupt; + dma_id : out t_dma_periph_index; + stream : out t_stream_index; + success : out boolean); + + function soc_is_dma_irq + (intr : soc.interrupts.t_interrupt) + return boolean; + + function get_interrupt_status + (controller : t_dma_periph; + stream : t_stream_index) return t_dma_stream_int_status; + + procedure set_IFCR + (controller : in out t_dma_periph; + stream : in t_stream_index; + IFCR : in t_dma_stream_clear_interrupts); + + procedure clear_all_interrupts + (controller : in out t_dma_periph; + stream : in t_stream_index); + + procedure reset_stream + (controller : in out t_dma_periph; + stream : in t_stream_index); + + procedure reset_streams; + +end soc.dma; diff --git a/arch/socs/stm32f439/Ada/soc-dwt-interfaces.adb b/arch/socs/stm32f439/Ada/soc-dwt-interfaces.adb new file mode 100644 index 0000000..acea6f2 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-dwt-interfaces.adb @@ -0,0 +1,53 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +package body soc.dwt.interfaces + with spark_mode => off +is + + ------------------- + -- get_cycles_32 -- + ------------------- + + function get_cycles_32 + return Unsigned_32 + is + val : unsigned_32; + begin + soc.dwt.get_cycles_32(val); + return val; + end get_cycles_32; + + ---------------- + -- get_cycles -- + ---------------- + + function get_cycles + return Unsigned_64 + is + val : unsigned_64; + begin + soc.dwt.get_cycles(val); + return val; + end get_cycles; + +end soc.dwt.interfaces; diff --git a/arch/socs/stm32f439/Ada/soc-dwt-interfaces.ads b/arch/socs/stm32f439/Ada/soc-dwt-interfaces.ads new file mode 100644 index 0000000..af37117 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-dwt-interfaces.ads @@ -0,0 +1,44 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +package soc.dwt.interfaces + with spark_mode => on +is + + -- get the DWT timer (without overflow support, keep a 32bit value) + function get_cycles_32 + return Unsigned_32 + with + convention => c, + export => true, + external_name => "soc_dwt_getcycles"; + + -- get the DWT timer with overflow support. permits linear measurement + -- on 64 bits cycles time window (approx. 1270857 days) + function get_cycles + return Unsigned_64 + with + convention => c, + export => true, + external_name => "soc_dwt_getcycles_64"; + +end soc.dwt.interfaces; diff --git a/arch/socs/stm32f439/Ada/soc-dwt.adb b/arch/socs/stm32f439/Ada/soc-dwt.adb new file mode 100644 index 0000000..b48e7f8 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-dwt.adb @@ -0,0 +1,177 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ada.unchecked_conversion; +with m4.systick; + +package body soc.dwt + with spark_mode => on, + Refined_State => (Cnt => DWT_CYCCNT, + Ctrl => DWT_CONTROL, + Ini_F => init_done, + Loo => dwt_loops, + Last => last_dwt, + Lar_register => LAR, + Dem => DEMCR) + +is + ----------------------------------------------------- + -- SPARK ghost functions and procedures + ----------------------------------------------------- + + function init_is_done + return boolean + is + begin + return init_done; + end init_is_done; + + + function check_32bits_overflow + return boolean + is + begin + return (init_done and then dwt_loops < unsigned_64(unsigned_32'Last)); + end; + + -------------------------------------------------- + -- The Data Watchpoint and Trace unit (DWT) -- + -- (Cf. ARMv7-M Arch. Ref. Manual, C1.8, p.779) -- + -------------------------------------------------- + + procedure reset_timer + with + Refined_Global => (Input => init_done, + In_Out => (DEMCR, DWT_CONTROL), + Output => (LAR, DWT_CYCCNT)) + is + begin + DEMCR.TRCENA := true; + LAR := LAR_ENABLE_WRITE_KEY; + DWT_CYCCNT := 0; -- reset the counter + DWT_CONTROL.CYCCNTENA := false; + end reset_timer; + + + procedure start_timer + with + Refined_Global => (Input => init_done, + In_Out => DWT_CONTROL) + is + begin + DWT_CONTROL.CYCCNTENA := true; -- enable the counter + end start_timer; + + + procedure stop_timer + with + Refined_Global=> (Input => init_done, + In_Out => DWT_CONTROL) + is + begin + DWT_CONTROL.CYCCNTENA := false; -- stop the counter + end stop_timer; + + + procedure ovf_manage + with + Refined_Post => (dwt_loops = dwt_loops'Old + or dwt_loops = (dwt_loops'Old + 1)) + is + dwt : unsigned_32; + begin + dwt := DWT_CYCCNT; + if dwt < last_dwt then + dwt_loops := dwt_loops + 1; + end if; + last_dwt := dwt; + end ovf_manage; + + + procedure init + with + Refined_Post => (init_done), + Refined_Global => (In_Out => (init_done, + DWT_CONTROL, + DEMCR), + Output => (last_dwt, + dwt_loops, + DWT_CYCCNT, + LAR)) + is + begin + last_dwt := 0; + dwt_loops := 0; + reset_timer; + start_timer; + init_done := True; + end init; + + + procedure get_cycles_32 (cycles : out unsigned_32) + with + Refined_Global=> (Input => init_done, + In_Out => DWT_CYCCNT) + is + begin + cycles := DWT_CYCCNT; -- can't return volatile (SPARK RM 7.1.3(12)) + end get_cycles_32; + + + procedure get_cycles (cycles : out unsigned_64) + with + Refined_Global => (Input => (init_done, dwt_loops), + In_Out => DWT_CYCCNT) + is + cyccnt : unsigned_64; + begin + cyccnt := unsigned_64(DWT_CYCCNT); + cyccnt := cyccnt and 16#0000_0000_ffff_ffff#; + cycles := interfaces.shift_left (dwt_loops, 32) + cyccnt; + end get_cycles; + + + procedure get_microseconds (micros : out unsigned_64) + with + Refined_Global => (Input => (init_done, dwt_loops), + In_Out => DWT_CYCCNT) + is + cycles : unsigned_64; + begin + get_cycles(cycles); + micros := cycles / (m4.systick.MAIN_CLOCK_FREQUENCY / 1000_000); + end get_microseconds; + + + procedure get_milliseconds (milli : out unsigned_64) + with + Refined_Global => (Input => (init_done, dwt_loops), + In_Out => DWT_CYCCNT) + is + cycles : unsigned_64; + begin + get_cycles(cycles); + milli := cycles / (m4.systick.MAIN_CLOCK_FREQUENCY / 1000); + end get_milliseconds; + + +end soc.dwt; diff --git a/arch/socs/stm32f439/Ada/soc-dwt.ads b/arch/socs/stm32f439/Ada/soc-dwt.ads new file mode 100644 index 0000000..0c56d7c --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-dwt.ads @@ -0,0 +1,356 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with system; + +-- FIXME - Should be moved to package 'm4.debug' +-- FIXME: pragma doesn't work... :-/ +pragma Annotate (GNATprove, + Intentional, + "initialization of init_done is not mentioned in Initializes contract", + "init_done is not a register, while it is a volatile"); + +package soc.dwt + with + spark_mode => on, + Abstract_State => ((Ctrl with external), -- this is a register + (Cnt with external), -- this is a register + (Lar_register with external), -- this is a register + (Dem with external), -- this is a register + Ini_F, Loo, Last), + Initializes => (Ctrl, Cnt, Dem, Ini_F) -- assumed as initialized +is + + ----------------------------------------------------- + -- SPARK ghost functions and procedures + ----------------------------------------------------- + + function init_is_done + return boolean + with + ghost; + + + function check_32bits_overflow + return boolean + with + ghost; + + -------------------------------------------------- + -- The Data Watchpoint and Trace unit (DWT) -- + -- (Cf. ARMv7-M Arch. Ref. Manual, C1.8, p.779) -- + -------------------------------------------------- + + + -- reset the DWT-based timer (initialize to 0) + procedure reset_timer + with + pre => not init_is_done, + global => (Input => Ini_F, + In_Out => (Dem, Ctrl), + Output => (Lar_register, Cnt) ), + depends => (Dem =>+ null, + Lar_register => null, + Cnt => null, + Ctrl =>+ null, + null => Ini_F); + + + -- start the DWT timer. The register is counting the number of + -- CPU cycles + procedure start_timer + with + pre => not init_is_done, + global => (Input => Ini_F, + In_Out => Ctrl), + depends => (Ctrl =>+ null, + null => Ini_F); + + + -- stop the DWT timer + procedure stop_timer + with + convention => c, + export => true, + external_name => "soc_dwt_stop_timer", + pre => init_is_done, + global => (Input => Ini_F, + In_Out => Ctrl), + depends => (Ctrl =>+ null, + null => Ini_F); + + + -- periodically check the DWT CYCCNT register for overflow. This permit + -- to detect each time an overflow happends and increment the + -- overflow counter to keep a valid 64 bit time value + -- precondition check that the package has been initialized and that + -- dwt_loop doesn't overflow + procedure ovf_manage + with + pre => check_32bits_overflow, + convention => c, + export => true, + external_name => "soc_dwt_ovf_manage"; + + -- initialize the DWT module + -- This procedure is called by the kernel main() function, and as + -- a consequence exported to C + procedure init + with + pre => not init_is_done, + Global => (In_Out => (Ini_F, + Ctrl, + Dem), + Output => (Last, + Loo, + Cnt, + Lar_register)), + convention => c, + export => true, + external_name => "soc_dwt_init"; + + + + -- get the DWT timer (without overflow support, keep a 32bit value) + procedure get_cycles_32(cycles : out unsigned_32) + with + pre => init_is_done, + global => (Input => Ini_F, + In_Out => Cnt), + depends => (Cnt =>+ null, + cycles => Cnt, + null => Ini_F); + + + -- get the DWT timer with overflow support. permits linear measurement + -- on 64 bits cycles time window (approx. 1270857 days) + procedure get_cycles (cycles : out unsigned_64) + with + pre => init_is_done, + global => (Input => (Ini_F, Loo), + In_Out => Cnt), + depends => (Cnt =>+ null, + cycles => (Cnt, Loo), + null => Ini_F); + + + procedure get_microseconds (micros : out unsigned_64) + with + pre => init_is_done, + global => (Input => (Ini_F, Loo), + In_Out => Cnt), + depends => (micros => (Cnt, Loo), + Cnt =>+ null, + null => Ini_F); + + + procedure get_milliseconds (milli : out unsigned_64) + with + pre => init_is_done, + global => (In_Out => Cnt, + Input => (Loo, Ini_F)), + depends => (milli => (Cnt, Loo), + Cnt =>+ null, + null => Ini_F); + + +private + + -- + -- Control register + -- + + type t_DWT_CTRL is record + CYCCNTENA : boolean; -- Enables CYCCNT + POSTPRESET : bits_4; + POSTINIT : bits_4; + CYCTAP : bit; + SYNCTAP : bits_2; + PCSAMPLENA : bit; + reserved_13_15 : bits_3; + EXCTRCENA : bit; + CPIEVTENA : bit; + EXCEVTENA : bit; + SLEEPEVTENA : bit; + LSUEVTENA : bit; + FOLDEVTENA : bit; + CYCEVTENA : bit; + reserved_23 : bit; + NOPRFCNT : bit; + NOCYCCNT : bit; + NOEXTTRIG : bit; + NOTRCPKT : bit; + NUMCOMP : bits_4; + end record + with size => 32; + + for t_DWT_CTRL use record + CYCCNTENA at 0 range 0 .. 0; + POSTPRESET at 0 range 1 .. 4; + POSTINIT at 0 range 5 .. 8; + CYCTAP at 0 range 9 .. 9; + SYNCTAP at 0 range 10 .. 11; + PCSAMPLENA at 0 range 12 .. 12; + reserved_13_15 at 0 range 13 .. 15; + EXCTRCENA at 0 range 16 .. 16; + CPIEVTENA at 0 range 17 .. 17; + EXCEVTENA at 0 range 18 .. 18; + SLEEPEVTENA at 0 range 19 .. 19; + LSUEVTENA at 0 range 20 .. 20; + FOLDEVTENA at 0 range 21 .. 21; + CYCEVTENA at 0 range 22 .. 22; + reserved_23 at 0 range 23 .. 23; + NOPRFCNT at 0 range 24 .. 24; + NOCYCCNT at 0 range 25 .. 25; + NOEXTTRIG at 0 range 26 .. 26; + NOTRCPKT at 0 range 27 .. 27; + NUMCOMP at 0 range 28 .. 31; + end record; + + DWT_CONTROL : t_DWT_CTRL + with + import, + volatile, + address => system'to_address (16#E000_1000#), + Part_Of => Ctrl; + + -- + -- CYCCNT register + -- + + subtype t_DWT_CYCCNT is unsigned_32; + + DWT_CYCCNT : t_DWT_CYCCNT + with + import, + volatile, + address => system'to_address (16#E000_1004#), + Part_Of => Cnt; + + + -- specify the package state. Set to true by init(). + init_done : boolean := False with Part_Of => Ini_F; + -- + -- DWT CYCCNT register overflow counting + -- This permit to support incremental getcycle + -- with a time window of 64bits length (instead of 32bits) + -- + + dwt_loops : unsigned_64 with Part_Of => Loo; + + -- + -- Last measured DWT CYCCNT. Compared with current measurement, + -- we can detect if the register has generated an overflow or not + -- + + last_dwt : unsigned_32 with Part_Of => Last; + + -------------------------------------------------- + -- CoreSight Software Lock registers -- + -- Ref.: -- + -- - ARMv7-M Arch. Ref. Manual, D1.1, p.826) -- + -- - CoreSight Arch. Spec. B2.5.9, p.48 -- + -------------------------------------------------- + + -- + -- Lock Access Register (LAR) + -- + + LAR : unsigned_32 + with + import, + volatile, + address => system'to_address (16#E000_1FB0#), + Part_Of => Lar_register; + + LAR_ENABLE_WRITE_KEY : constant := 16#C5AC_CE55#; + + --------------------------------------------------------- + -- Debug Exception and Monitor Control Register, DEMCR -- + -- (Cf. ARMv7-M Arch. Ref. Manual, C1.6.5, p.765) -- + --------------------------------------------------------- + + type t_DEMCR is record + VC_CORERESET : boolean; -- Reset Vector Catch enabled + + reserved_1_3 : bits_3; + + VC_MMERR : boolean; -- Debug trap on a MemManage exception + + VC_NOCPERR : boolean; + -- Debug trap on a UsageFault exception caused by an access to a + -- Coprocessor + + VC_CHKERR : boolean; + -- Debug trap on a UsageFault exception caused by a checking error + + VC_STATERR : boolean; + -- Debug trap on a UsageFault exception caused by a state information + -- error + + VC_BUSERR : boolean; -- Debug trap on a BusFault exception + + VC_INTERR : boolean; + -- Debug trap on a fault occurring during exception entry or exception + -- return + + VC_HARDERR : boolean; -- Debug trap on a HardFault exception + + reserved_11_15 : bits_5; + MON_EN : boolean; -- DebugMonitor exception enabled + MON_PEND : boolean; -- Sets or clears the pending state of the + -- DebugMonitor exception + MON_STEP : boolean; -- Step the processor + MON_REQ : boolean; -- DebugMonitor semaphore bit + reserved_20_23 : bits_4; + TRCENA : boolean; -- DWT and ITM units enabled + end record + with size => 32; + + for t_DEMCR use record + VC_CORERESET at 0 range 0 .. 0; + reserved_1_3 at 0 range 1 .. 3; + VC_MMERR at 0 range 4 .. 4; + VC_NOCPERR at 0 range 5 .. 5; + VC_CHKERR at 0 range 6 .. 6; + VC_STATERR at 0 range 7 .. 7; + VC_BUSERR at 0 range 8 .. 8; + VC_INTERR at 0 range 9 .. 9; + VC_HARDERR at 0 range 10 .. 10; + reserved_11_15 at 0 range 11 .. 15; + MON_EN at 0 range 16 .. 16; + MON_PEND at 0 range 17 .. 17; + MON_STEP at 0 range 18 .. 18; + MON_REQ at 0 range 19 .. 19; + reserved_20_23 at 0 range 20 .. 23; + TRCENA at 0 range 24 .. 24; + end record; + + DEMCR : t_DEMCR + with import, + volatile, + address => system'to_address (16#E000_EDFC#), + Part_Of => Dem; + + + +end soc.dwt; diff --git a/arch/socs/stm32f439/Ada/soc-exti.adb b/arch/socs/stm32f439/Ada/soc-exti.adb new file mode 100644 index 0000000..ccf92ac --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-exti.adb @@ -0,0 +1,78 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with system; use system; +with soc.rcc; + + +package body soc.exti + with spark_mode => off +is + + procedure init + is + begin + soc.rcc.RCC.APB2.SYSCFGEN := true; + end init; + + + function is_line_pending + (line : t_exti_line_index) + return boolean + is + begin + return (EXTI.PR.line(line) = PENDING_REQUEST); + end is_line_pending; + + + procedure clear_pending + (line : in t_exti_line_index) + is + begin + EXTI.PR.line(line) := CLEAR_REQUEST; + end clear_pending; + + + procedure enable + (line : in t_exti_line_index) + is + begin + EXTI.IMR.line(line) := NOT_MASKED; -- interrupt is unmasked + end enable; + + + procedure disable + (line : in t_exti_line_index) + is + begin + EXTI.IMR.line(line) := MASKED; -- interrupt is masked + end disable; + + + function is_enabled (line : in t_exti_line_index) + return boolean + is + begin + return EXTI.IMR.line(line) = NOT_MASKED; + end; + +end soc.exti; diff --git a/arch/socs/stm32f439/Ada/soc-exti.ads b/arch/socs/stm32f439/Ada/soc-exti.ads new file mode 100644 index 0000000..a0b135c --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-exti.ads @@ -0,0 +1,184 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with system; + + +package soc.exti + with spark_mode => on +is + + subtype t_exti_line_index is natural range 0 .. 22; + + -- Initialize EXTI by enabling SYSCFG.APB2 clock + procedure init; + + function is_line_pending + (line : t_exti_line_index) + return boolean; + + procedure clear_pending + (line : in t_exti_line_index); + + procedure enable + (line : in t_exti_line_index); + + procedure disable + (line : in t_exti_line_index); + + function is_enabled + (line : in t_exti_line_index) + return boolean; + + + type t_mask is (MASKED, NOT_MASKED) with size => 1; + for t_mask use (MASKED => 0, NOT_MASKED => 1); + + type t_masks is array (t_exti_line_index) of t_mask + with volatile_components, pack, size => 23; + + ---------------------------------------- + -- Interrupt mask register (EXTI_IMR) -- + ---------------------------------------- + + type t_EXTI_IMR is record + line : t_masks; + end record + with volatile_full_access, size => 32; + + for t_EXTI_IMR use record + line at 0 range 0 .. 22; + end record; + + ------------------------------------ + -- Event mask register (EXTI_EMR) -- + ------------------------------------ + + type t_EXTI_EMR is record + line : t_masks; + end record + with volatile_full_access, size => 32; + + for t_EXTI_EMR use record + line at 0 range 0 .. 22; + end record; + + --------------------------------------------------- + -- Rising trigger selection register (EXTI_RTSR) -- + --------------------------------------------------- + + type t_trigger is (TRIGGER_DISABLED, TRIGGER_ENABLED) with size => 1; + for t_trigger use (TRIGGER_DISABLED => 0, TRIGGER_ENABLED => 1); + + type t_triggers is array (t_exti_line_index) of t_trigger + with pack, size => 23; + + type t_EXTI_RTSR is record + line : t_triggers; + end record + with volatile_full_access, size => 32; + + for t_EXTI_RTSR use record + line at 0 range 0 .. 22; + end record; + + ---------------------------------------------------- + -- Falling trigger selection register (EXTI_FTSR) -- + ---------------------------------------------------- + + type t_EXTI_FTSR is record + line : t_triggers; + end record + with volatile_full_access, size => 32; + + for t_EXTI_FTSR use record + line at 0 range 0 .. 22; + end record; + + ---------------------------------------------------- + -- Software interrupt event register (EXTI_SWIER) -- + ---------------------------------------------------- + + type t_exti_lines is array (t_exti_line_index) of bit + with pack, size => 23; + + type t_EXTI_SWIER is record + line : t_exti_lines; + end record + with volatile_full_access, size => 32; + + for t_EXTI_SWIER use record + line at 0 range 0 .. 22; + end record; + + -------------------------------- + -- Pending register (EXTI_PR) -- + -------------------------------- + + type t_request is (NO_REQUEST, PENDING_REQUEST) with size => 1; + for t_request use (NO_REQUEST => 0, PENDING_REQUEST => 1); + + -- Set the bit to '1' to clear it! + CLEAR_REQUEST : constant t_request := PENDING_REQUEST; + + type t_requests is array (t_exti_line_index) of t_request + with pack, size => 23; + + type t_EXTI_PR is record + line : t_requests; + end record + with volatile_full_access, size => 32; + + for t_EXTI_PR use record + line at 0 range 0 .. 22; + end record; + + --------------------- + -- EXTI peripheral -- + --------------------- + + type t_EXTI_periph is record + IMR : t_EXTI_IMR; + EMR : t_EXTI_EMR; + RTSR : t_EXTI_RTSR; + FTSR : t_EXTI_FTSR; + SWIER : t_EXTI_SWIER; + PR : t_EXTI_PR; + end record + with volatile; + + for t_EXTI_periph use record + IMR at 16#00# range 0 .. 31; + EMR at 16#04# range 0 .. 31; + RTSR at 16#08# range 0 .. 31; + FTSR at 16#0C# range 0 .. 31; + SWIER at 16#10# range 0 .. 31; + PR at 16#14# range 0 .. 31; + end record; + + EXTI : t_EXTI_periph + with + import, + volatile, + address => system'to_address (16#4001_3C00#); -- 0x40013C00 + +end soc.exti; diff --git a/arch/socs/stm32f439/Ada/soc-gpio-interfaces.adb b/arch/socs/stm32f439/Ada/soc-gpio-interfaces.adb new file mode 100644 index 0000000..3c51f95 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-gpio-interfaces.adb @@ -0,0 +1,60 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + + +package body soc.gpio.interfaces + with spark_mode => off +is + + function configure + (port : in unsigned_8; + pin : in unsigned_8; + mode : in t_pin_mode; + otype : in t_pin_output_type; + ospeed : in t_pin_output_speed; + pupd : in t_pin_pupd; + af : in t_pin_alt_func) + return types.c.t_retval + is + gpio_port : t_gpio_port_index; + gpio_pin : t_gpio_pin_index; + begin + + gpio_port := t_gpio_port_index'val (port); + + if not port'valid then + return types.c.FAILURE; + end if; + + gpio_pin := t_gpio_pin_index'val (pin); + + if not pin'valid then + return types.c.FAILURE; + end if; + + soc.gpio.config (gpio_port, gpio_pin, mode, otype, ospeed, pupd, af); + return types.c.SUCCESS; + end configure; + + +end soc.gpio.interfaces; diff --git a/arch/socs/stm32f439/Ada/soc-gpio-interfaces.ads b/arch/socs/stm32f439/Ada/soc-gpio-interfaces.ads new file mode 100644 index 0000000..136be69 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-gpio-interfaces.ads @@ -0,0 +1,44 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with types.c; + +package soc.gpio.interfaces + with spark_mode => off +is + + function configure + (port : in unsigned_8; + pin : in unsigned_8; + mode : in t_pin_mode; + otype : in t_pin_output_type; + ospeed : in t_pin_output_speed; + pupd : in t_pin_pupd; + af : in t_pin_alt_func) + return types.c.t_retval + with + convention => c, + export => true, + external_name => "soc_gpio_configure"; + +end soc.gpio.interfaces; + diff --git a/arch/socs/stm32f439/Ada/soc-gpio.adb b/arch/socs/stm32f439/Ada/soc-gpio.adb new file mode 100644 index 0000000..21a7431 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-gpio.adb @@ -0,0 +1,88 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.rcc; + +package body soc.gpio + with spark_mode => off +is + + function get_port_access + (port : t_gpio_port_index) return t_GPIO_port_access + is + begin + case port is + when GPIO_PA => return soc.gpio.GPIOA'access; + when GPIO_PB => return soc.gpio.GPIOB'access; + when GPIO_PC => return soc.gpio.GPIOC'access; + when GPIO_PD => return soc.gpio.GPIOD'access; + when GPIO_PE => return soc.gpio.GPIOE'access; + when GPIO_PF => return soc.gpio.GPIOF'access; + when GPIO_PG => return soc.gpio.GPIOG'access; + when GPIO_PH => return soc.gpio.GPIOH'access; + when GPIO_PI => return soc.gpio.GPIOI'access; + end case; + end get_port_access; + + + procedure config + (port : in t_gpio_port_index; + pin : in t_gpio_pin_index; + mode : in t_pin_mode; + otype : in t_pin_output_type; + ospeed : in t_pin_output_speed; + pupd : in t_pin_pupd; + af : in t_pin_alt_func) + is + gpio : soc.gpio.t_GPIO_port_access; + begin + + -- Enable RCC + case port is + when GPIO_PA => soc.rcc.RCC.AHB1.GPIOAEN := true; + when GPIO_PB => soc.rcc.RCC.AHB1.GPIOBEN := true; + when GPIO_PC => soc.rcc.RCC.AHB1.GPIOCEN := true; + when GPIO_PD => soc.rcc.RCC.AHB1.GPIODEN := true; + when GPIO_PE => soc.rcc.RCC.AHB1.GPIOEEN := true; + when GPIO_PF => soc.rcc.RCC.AHB1.GPIOFEN := true; + when GPIO_PG => soc.rcc.RCC.AHB1.GPIOGEN := true; + when GPIO_PH => soc.rcc.RCC.AHB1.GPIOHEN := true; + when GPIO_PI => soc.rcc.RCC.AHB1.GPIOIEN := true; + end case; + + gpio := soc.gpio.get_port_access (port); + + gpio.all.MODER.pin(pin) := mode; + gpio.all.OTYPER.pin(pin) := otype; + gpio.all.OSPEEDR.pin(pin) := ospeed; + gpio.all.PUPDR.pin(pin) := pupd; + + if pin < 8 then + gpio.all.AFRL.pin(pin) := af; + else + gpio.all.AFRH.pin(pin) := af; + end if; + + end config; + + +end soc.gpio; diff --git a/arch/socs/stm32f439/Ada/soc-gpio.ads b/arch/socs/stm32f439/Ada/soc-gpio.ads new file mode 100644 index 0000000..0657908 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-gpio.ads @@ -0,0 +1,318 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with system; +with soc.layout; + +package soc.gpio + with spark_mode => off +is + + type t_gpio_pin_index is range 0 .. 15 + with size => 4; + + type t_gpio_port_index is + (GPIO_PA, GPIO_PB, GPIO_PC, + GPIO_PD, GPIO_PE, GPIO_PF, + GPIO_PG, GPIO_PH, GPIO_PI) with size => 4; + + ------------------------------------------- + -- GPIO port mode register (GPIOx_MODER) -- + ------------------------------------------- + + type t_pin_mode is (MODE_IN, MODE_OUT, MODE_AF, MODE_ANALOG) + with size => 2; + + for t_pin_mode use + (MODE_IN => 0, + MODE_OUT => 1, + MODE_AF => 2, + MODE_ANALOG => 3); + + type t_pins_mode is array (t_gpio_pin_index) of t_pin_mode + with pack, size => 32; + + type t_GPIOx_MODER is record + pin : t_pins_mode; + end record + with pack, size => 32, volatile_full_access; + -- Note: volatile_full_access: the register is volatile and the full + -- 32-bits needs to be written at once. + + --------------------------------------------------- + -- GPIO port output type register (GPIOx_OTYPER) -- + --------------------------------------------------- + + type t_pin_output_type is (PUSH_PULL, OPEN_DRAIN) + with size => 1; + + for t_pin_output_type use + (PUSH_PULL => 0, + OPEN_DRAIN => 1); + + type t_pins_output_type is array (t_gpio_pin_index) of t_pin_output_type + with pack, size => 16; + + type t_GPIOx_OTYPER is record + pin : t_pins_output_type; + end record + with size => 32, volatile_full_access; + + for t_GPIOx_OTYPER use record + pin at 0 range 0 .. 15; + end record; + + ----------------------------------------------------- + -- GPIO port output speed register (GPIOx_OSPEEDR) -- + ----------------------------------------------------- + + type t_pin_output_speed is + (SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH, SPEED_VERY_HIGH) + with size => 2; + + for t_pin_output_speed use + (SPEED_LOW => 0, + SPEED_MEDIUM => 1, + SPEED_HIGH => 2, + SPEED_VERY_HIGH => 3); + + type t_pins_output_speed is array (t_gpio_pin_index) of t_pin_output_speed + with pack, size => 32; + + type t_GPIOx_OSPEEDR is record + pin : t_pins_output_speed; + end record + with pack, size => 32, volatile_full_access; + + -------------------------------------------------------- + -- GPIO port pull-up/pull-down register (GPIOx_PUPDR) -- + -------------------------------------------------------- + + type t_pin_pupd is (FLOATING, PULL_UP, PULL_DOWN) + with size => 2; + + for t_pin_pupd use + (FLOATING => 0, + PULL_UP => 1, + PULL_DOWN => 2); + + type t_pins_pupd is array (t_gpio_pin_index) of t_pin_pupd + with pack, size => 32; + + type t_GPIOx_PUPDR is record + pin : t_pins_pupd; + end record + with pack, size => 32, volatile_full_access; + + ----------------------------------------------- + -- GPIO port input data register (GPIOx_IDR) -- + ----------------------------------------------- + + type t_pins_idr is array (t_gpio_pin_index) of bit + with pack, size => 16; + + type t_GPIOx_IDR is record + pin : t_pins_idr; + end record + with size => 32, volatile_full_access; + + for t_GPIOx_IDR use record + pin at 0 range 0 .. 15; + end record; + + ------------------------------------------------ + -- GPIO port output data register (GPIOx_ODR) -- + ------------------------------------------------ + + type t_pins_odr is array (t_gpio_pin_index) of bit + with pack, size => 16; + + type t_GPIOx_ODR is record + pin : t_pins_odr; + end record + with size => 32, volatile_full_access; + + for t_GPIOx_ODR use record + pin at 0 range 0 .. 15; + end record; + + --------------------------------------------------- + -- GPIO port bit set/reset register (GPIOx_BSRR) -- + --------------------------------------------------- + + type t_pins_bsrr is array (t_gpio_pin_index) of bit + with pack, size => 16; + + type t_GPIOx_BSRR is record + BS : t_pins_bsrr; + BR : t_pins_bsrr; + end record + with pack, size => 32, volatile_full_access; + + -------------------------------------------------------- + -- GPIO port configuration lock register (GPIOx_LCKR) -- + -------------------------------------------------------- + + type t_pin_lock is (NOT_LOCKED, LOCKED) + with size => 1; + + for t_pin_lock use + (NOT_LOCKED => 0, + LOCKED => 1); + + type t_pins_lock is array (t_gpio_pin_index) of t_pin_lock + with pack, size => 16; + + type t_GPIOx_LCKR is record + pin : t_pins_lock; + lock_key : bit; + end record + with size => 32, volatile_full_access; + + for t_GPIOx_LCKR use record + pin at 0 range 0 .. 15; + lock_key at 0 range 16 .. 16; + end record; + + ------------------------------------------------------- + -- GPIO alternate function low register (GPIOx_AFRL) -- + ------------------------------------------------------- + + type t_pin_alt_func is range 0 .. 15 with size => 4; + + -- See RM0090, p. 274 + GPIO_AF_USART1 : constant t_pin_alt_func := 7; + GPIO_AF_USART2 : constant t_pin_alt_func := 7; + GPIO_AF_USART3 : constant t_pin_alt_func := 7; + GPIO_AF_UART4 : constant t_pin_alt_func := 8; + GPIO_AF_UART5 : constant t_pin_alt_func := 8; + GPIO_AF_USART6 : constant t_pin_alt_func := 8; + GPIO_AF_SDIO : constant t_pin_alt_func := 12; + + type t_pins_alt_func_0_7 is array (t_gpio_pin_index range 0 .. 7) + of t_pin_alt_func + with pack, size => 32; + + type t_pins_alt_func_8_15 is array (t_gpio_pin_index range 8 .. 15) + of t_pin_alt_func + with pack, size => 32; + + type t_GPIOx_AFRL is record + pin : t_pins_alt_func_0_7; + end record + with pack, size => 32, volatile_full_access; + + type t_GPIOx_AFRH is record + pin : t_pins_alt_func_8_15; + end record + with pack, size => 32, volatile_full_access; + + --------------- + -- GPIO port -- + --------------- + + type t_GPIO_port is record + MODER : t_GPIOx_MODER; + OTYPER : t_GPIOx_OTYPER; + OSPEEDR : t_GPIOx_OSPEEDR; + PUPDR : t_GPIOx_PUPDR; + IDR : t_GPIOx_IDR; + ODR : t_GPIOx_ODR; + BSRR : t_GPIOx_BSRR; + LCKR : t_GPIOx_LCKR; + AFRL : t_GPIOx_AFRL; + AFRH : t_GPIOx_AFRH; + end record + with volatile; + + for t_GPIO_port use record + MODER at 16#00# range 0 .. 31; + OTYPER at 16#04# range 0 .. 31; + OSPEEDR at 16#08# range 0 .. 31; + PUPDR at 16#0C# range 0 .. 31; + IDR at 16#10# range 0 .. 31; + ODR at 16#14# range 0 .. 31; + BSRR at 16#18# range 0 .. 31; + LCKR at 16#1C# range 0 .. 31; + AFRL at 16#20# range 0 .. 31; + AFRH at 16#24# range 0 .. 31; + end record; + + type t_GPIO_port_access is access all t_GPIO_port; + + ---------------------- + -- GPIO peripherals -- + ---------------------- + + GPIOA : aliased t_GPIO_port + with import, volatile, + address => system'to_address (soc.layout.GPIOA_BASE); + + GPIOB : aliased t_GPIO_port + with import, volatile, + address => system'to_address (soc.layout.GPIOB_BASE); + + GPIOC : aliased t_GPIO_port + with import, volatile, + address => system'to_address (soc.layout.GPIOC_BASE); + + GPIOD : aliased t_GPIO_port + with import, volatile, + address => system'to_address (soc.layout.GPIOD_BASE); + + GPIOE : aliased t_GPIO_port + with import, volatile, + address => system'to_address (soc.layout.GPIOE_BASE); + + GPIOF : aliased t_GPIO_port + with import, volatile, + address => system'to_address (soc.layout.GPIOF_BASE); + + GPIOG : aliased t_GPIO_port + with import, volatile, + address => system'to_address (soc.layout.GPIOG_BASE); + + GPIOH : aliased t_GPIO_port + with import, volatile, + address => system'to_address (soc.layout.GPIOH_BASE); + + GPIOI : aliased t_GPIO_port + with import, volatile, + address => system'to_address (soc.layout.GPIOI_BASE); + + --------------- + -- Utilities -- + --------------- + + function get_port_access + (port : t_gpio_port_index) return t_GPIO_port_access; + + procedure config + (port : in t_gpio_port_index; + pin : in t_gpio_pin_index; + mode : in t_pin_mode; + otype : in t_pin_output_type; + ospeed : in t_pin_output_speed; + pupd : in t_pin_pupd; + af : in t_pin_alt_func); + +end soc.gpio; diff --git a/arch/socs/stm32f439/Ada/soc-interrupts.adb b/arch/socs/stm32f439/Ada/soc-interrupts.adb new file mode 100644 index 0000000..e6d68fb --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-interrupts.adb @@ -0,0 +1,37 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with m4.cpu; + +package body soc.interrupts + with spark_mode => on +is + + function get_interrupt + return t_interrupt + is + ipsr : constant m4.cpu.t_IPSR_register := m4.cpu.get_ipsr_register; + begin + return t_interrupt'val (ipsr.ISR_NUMBER); + end get_interrupt; + +end soc.interrupts; diff --git a/arch/socs/stm32f439/Ada/soc-interrupts.ads b/arch/socs/stm32f439/Ada/soc-interrupts.ads new file mode 100644 index 0000000..b210077 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-interrupts.ads @@ -0,0 +1,158 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with ada.unchecked_conversion; + +package soc.interrupts + with spark_mode => on +is + + ------------------------------------- + -- STM32F4xx interrupts and events -- + ------------------------------------- + + type t_interrupt is + (ESTACK, -- 0 + INT_RESET, + INT_NMI, + INT_HARDFAULT, + INT_MEMMANAGE, + INT_BUSFAULT, -- 5 + INT_USAGEFAULT, + INT_VOID1, + INT_VOID2, + INT_VOID3, + INT_VOID4, -- 10 + INT_SVC, + INT_DEBUGON, + INT_VOID5, + INT_PENDSV, + INT_SYSTICK, -- 15 + INT_WWDG, + INT_PVD, + INT_TAMP_STAMP, + INT_RTC_WKUP, + INT_FLASH, -- 20 + INT_RCC, + INT_EXTI0, + INT_EXTI1, + INT_EXTI2, + INT_EXTI3, -- 25 + INT_EXTI4, + INT_DMA1_STREAM0, + INT_DMA1_STREAM1, + INT_DMA1_STREAM2, + INT_DMA1_STREAM3, -- 30 + INT_DMA1_STREAM4, + INT_DMA1_STREAM5, + INT_DMA1_STREAM6, + INT_ADC, + INT_CAN1_TX, -- 35 + INT_CAN1_RX0, + INT_CAN1_RX1, + INT_CAN1_SCE, + INT_EXTI9_5, + INT_TIM1_BRK_TIM9, -- 40 + INT_TIM1_UP_TIM10, + INT_TIM1_TRG_COM_TIM11, + INT_TIM1_CC, + INT_TIM2, + INT_TIM3, -- 45 + INT_TIM4, + INT_I2C1_EV, + INT_I2C1_ER, + INT_I2C2_EV, + INT_I2C2_ER, -- 50 + INT_SPI1, + INT_SPI2, + INT_USART1, + INT_USART2, + INT_USART3, -- 55 + INT_EXTI15_10, + INT_RTC_ALARM, + INT_OTG_FS_WKUP, + INT_TIM8_BRK_TIM12, + INT_TIM8_UP_TIM13, -- 60 + INT_TIM8_TRG_COM_TIM14, + INT_TIM8_CC, + INT_DMA1_STREAM7, + INT_FSMC, + INT_SDIO, -- 65 + INT_TIM5, + INT_SPI3, + INT_UART4, + INT_UART5, + INT_TIM6_DAC, -- 70 + INT_TIM7, + INT_DMA2_STREAM0, + INT_DMA2_STREAM1, + INT_DMA2_STREAM2, + INT_DMA2_STREAM3, -- 75 + INT_DMA2_STREAM4, + INT_ETH, + INT_ETH_WKUP, + INT_CAN2_TX, + INT_CAN2_RX0, -- 80 + INT_CAN2_RX1, + INT_CAN2_SCE, + INT_OTG_FS, + INT_DMA2_STREAM5, + INT_DMA2_STREAM6, -- 85 + INT_DMA2_STREAM7, + INT_USART6, + INT_I2C3_EV, + INT_I2C3_ER, + INT_OTG_HS_EP1_OUT, -- 90 + INT_OTG_HS_EP1_IN, + INT_OTG_HS_WKUP, + INT_OTG_HS, + INT_DCMI, + INT_CRYP, -- 95 + INT_HASH_RNG, + INT_FPU, + INT_98, INT_99, + INT_100, INT_101, INT_102, INT_103, INT_104, INT_105, INT_106, INT_107, INT_108, INT_109, + INT_110, INT_111, INT_112, INT_113, INT_114, INT_115, INT_116, INT_117, INT_118, INT_119, + INT_120, INT_121, INT_122, INT_123, INT_124, INT_125, INT_126, INT_127, INT_128, INT_129, + INT_130, INT_131, INT_132, INT_133, INT_134, INT_135, INT_136, INT_137, INT_138, INT_139, + INT_140, INT_141, INT_142, INT_143, INT_144, INT_145, INT_146, INT_147, INT_148, INT_149, + INT_150, INT_151, INT_152, INT_153, INT_154, INT_155, INT_156, INT_157, INT_158, INT_159, + INT_160, INT_161, INT_162, INT_163, INT_164, INT_165, INT_166, INT_167, INT_168, INT_169, + INT_170, INT_171, INT_172, INT_173, INT_174, INT_175, INT_176, INT_177, INT_178, INT_179, + INT_180, INT_181, INT_182, INT_183, INT_184, INT_185, INT_186, INT_187, INT_188, INT_189, + INT_190, INT_191, INT_192, INT_193, INT_194, INT_195, INT_196, INT_197, INT_198, INT_199, + INT_200, INT_201, INT_202, INT_203, INT_204, INT_205, INT_206, INT_207, INT_208, INT_209, + INT_210, INT_211, INT_212, INT_213, INT_214, INT_215, INT_216, INT_217, INT_218, INT_219, + INT_220, INT_221, INT_222, INT_223, INT_224, INT_225, INT_226, INT_227, INT_228, INT_229, + INT_230, INT_231, INT_232, INT_233, INT_234, INT_235, INT_236, INT_237, INT_238, INT_239, + INT_240, INT_241, INT_242, INT_243, INT_244, INT_245, INT_246, INT_247, INT_248, INT_249, + INT_250, INT_251, INT_252, INT_253, INT_254, INT_255) + with size => 8; + + function get_interrupt return t_interrupt + with + inline, + convention => c, + export => true, + external_name => "interrupt_get_num"; + +end soc.interrupts; diff --git a/arch/socs/stm32f439/Ada/soc-layout-stm32f4.ads b/arch/socs/stm32f439/Ada/soc-layout-stm32f4.ads new file mode 100644 index 0000000..7f13706 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-layout-stm32f4.ads @@ -0,0 +1,30 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package soc.layout.stm32f4 + with spark_mode => on +is + + NB_MEM_BANK : constant := 1; + +end soc.layout.stm32f4; diff --git a/arch/socs/stm32f439/Ada/soc-layout-stm32f42x.ads b/arch/socs/stm32f439/Ada/soc-layout-stm32f42x.ads new file mode 100644 index 0000000..6b9ae99 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-layout-stm32f42x.ads @@ -0,0 +1,34 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package soc.layout.stm32f42x + with spark_mode => on +is + + NB_MEM_BANK : constant := 2; + + LDR_SIZE : constant := 256 * KBYTE; + RAM_USER_SIZE : constant := 32 * KBYTE; + RAM_KERN_SIZE : constant := 32 * KBYTE; + +end soc.layout.stm32f42x; diff --git a/arch/socs/stm32f439/Ada/soc-layout.ads b/arch/socs/stm32f439/Ada/soc-layout.ads new file mode 100644 index 0000000..94e78cc --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-layout.ads @@ -0,0 +1,105 @@ +with m4.mpu; +with types; + +package soc.layout + with spark_mode => on +is + + FLASH_BASE : constant system_address := 16#0800_0000#; + -- this specific SoC has two flash bank mapped consecutively, giving access + -- to 2MB of flash + FLASH_SIZE : constant := 2 * MBYTE; + + SRAM_BASE : constant system_address := 16#1000_0000#; + SRAM_SIZE : constant := 64 * KBYTE; + + BOOTROM_BASE : constant system_address := 16#1FFF_0000#; + + RAM_BASE : constant system_address := 16#2000_0000#; -- SRAM + RAM_SIZE : constant := 128 * KBYTE; + + PERIPH_BASE : constant system_address := 16#4000_0000#; + MEMORY_BANK1_BASE : constant system_address := 16#6000_0000#; + MEMORY_BANK2_BASE : constant system_address := MEMORY_BANK1_BASE; + + APB1PERIPH_BASE : constant system_address := PERIPH_BASE; + APB2PERIPH_BASE : constant system_address := PERIPH_BASE + 16#0001_0000#; + AHB1PERIPH_BASE : constant system_address := PERIPH_BASE + 16#0002_0000#; + AHB2PERIPH_BASE : constant system_address := PERIPH_BASE + 16#1000_0000#; + + -- + -- AHB1 peripherals + -- + + GPIOA_BASE : constant system_address := AHB1PERIPH_BASE + 16#0000#; + GPIOB_BASE : constant system_address := AHB1PERIPH_BASE + 16#0400#; + GPIOC_BASE : constant system_address := AHB1PERIPH_BASE + 16#0800#; + GPIOD_BASE : constant system_address := AHB1PERIPH_BASE + 16#0C00#; + GPIOE_BASE : constant system_address := AHB1PERIPH_BASE + 16#1000#; + GPIOF_BASE : constant system_address := AHB1PERIPH_BASE + 16#1400#; + GPIOG_BASE : constant system_address := AHB1PERIPH_BASE + 16#1800#; + GPIOH_BASE : constant system_address := AHB1PERIPH_BASE + 16#1C00#; + GPIOI_BASE : constant system_address := AHB1PERIPH_BASE + 16#2000#; + + DMA1_BASE : constant system_address := AHB1PERIPH_BASE + 16#6000#; + DMA2_BASE : constant system_address := AHB1PERIPH_BASE + 16#6400#; + + -- + -- APB2 peripherals + -- + + SYSCFG_BASE : constant system_address := APB2PERIPH_BASE + 16#3800#; + + -- + -- Flash and firmware structure + -- + -- + -- Flip bank + + FW1_SIZE : constant unsigned_32 := 576*1024; + + FW1_KERN_BASE : constant unsigned_32 := 16#08020000#; + FW1_KERN_SIZE : constant unsigned_32 := 64*1024; + FW1_KERN_REGION_SIZE : constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_64KB; + + FW1_USER_BASE : constant unsigned_32 := 16#08080000#; + FW1_USER_SIZE : constant unsigned_32 := 512*1024; + FW1_USER_REGION_SIZE : constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_512KB; + + -- DFU 1 + + DFU1_SIZE : constant unsigned_32 := 320*1024; + + DFU1_KERN_BASE : constant unsigned_32 := 16#08030000#; + DFU1_USER_BASE : constant unsigned_32 := 16#08040000#; + + DFU1_KERN_SIZE : constant unsigned_32 := 64*1024; + DFU1_KERN_REGION_SIZE: constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_64KB; + DFU1_USER_SIZE : constant unsigned_32 := 256*1024; + DFU1_USER_REGION_SIZE: constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_256KB; + + -- Flop bank + + FW2_SIZE : constant unsigned_32 := 576*1024; + + FW2_KERN_SIZE : constant unsigned_32 := 64*1024; + FW2_KERN_BASE : constant unsigned_32 := 16#09020000#; + FW2_KERN_REGION_SIZE : constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_64KB; + FW2_USER_BASE : constant unsigned_32 := 16#09080000#; + FW2_USER_SIZE : constant unsigned_32 := 512*1024; + FW2_USER_REGION_SIZE : constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_512KB; +-- FW2_USER_REGION_SIZE : constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_512KB; + + + -- DFU 2 + DFU2_SIZE : constant unsigned_32 := 320*1024; + + DFU2_KERN_BASE : constant unsigned_32 := 16#09030000#; + DFU2_KERN_SIZE : constant unsigned_32 := 64*1024; + DFU2_KERN_REGION_SIZE: constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_256KB; + + DFU2_USER_BASE : constant unsigned_32 := 16#09040000#; + DFU2_USER_SIZE : constant unsigned_32 := 256*1024; + DFU2_USER_REGION_SIZE: constant m4.mpu.t_region_size := m4.mpu.REGION_SIZE_256KB; + +end soc.layout; diff --git a/arch/socs/stm32f439/Ada/soc-nvic.adb b/arch/socs/stm32f439/Ada/soc-nvic.adb new file mode 100644 index 0000000..874ab5e --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-nvic.adb @@ -0,0 +1,60 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package body soc.nvic + with spark_mode => off +is + + function to_irq_number + (intr : soc.interrupts.t_interrupt) + return t_irq_index + is + begin + return t_irq_index'val (soc.interrupts.t_interrupt'pos (intr) - 16); + end to_irq_number; + + + procedure enable_irq + (irq : in t_irq_index) + is + begin + case irq is + when 0 .. 31 => NVIC.ISER0.irq(irq) := IRQ_ENABLED; + when 32 .. 63 => NVIC.ISER1.irq(irq) := IRQ_ENABLED; + when 64 .. 80 => NVIC.ISER2.irq(irq) := IRQ_ENABLED; + end case; + end enable_irq; + + + procedure clear_pending_irq + (irq : in t_irq_index) + is + begin + case irq is + when 0 .. 31 => NVIC.ICPR0.irq(irq) := CLEAR_PENDING; + when 32 .. 63 => NVIC.ICPR1.irq(irq) := CLEAR_PENDING; + when 64 .. 80 => NVIC.ICPR2.irq(irq) := CLEAR_PENDING; + end case; + end clear_pending_irq; + +end soc.nvic; diff --git a/arch/socs/stm32f439/Ada/soc-nvic.ads b/arch/socs/stm32f439/Ada/soc-nvic.ads new file mode 100644 index 0000000..e4b30db --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-nvic.ads @@ -0,0 +1,235 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with m4.layout; +with soc.interrupts; use type soc.interrupts.t_interrupt; + +-- Nested vectored interrupt controller (NVIC) +-- (see STM32F4xxx Cortex-M4 Programming Manual, p. 194-205) + +package soc.nvic + with spark_mode => on +is + + -- Up to 81 interrupts (see Cortex-M4 prog. manual, p. 194) + type t_irq_index is new natural range 0 .. 80; + + ---------- + -- IRQs -- + ---------- + -- (see RM0090, p. 374) + + EXTI_Line_0 : constant t_irq_index := 6; + EXTI_Line_1 : constant t_irq_index := 7; + EXTI_Line_2 : constant t_irq_index := 8; + EXTI_Line_3 : constant t_irq_index := 9; + EXTI_Line_4 : constant t_irq_index := 10; + EXTI_Line_5_9 : constant t_irq_index := 23; + EXTI_Line_10_15: constant t_irq_index := 40; + + DMA1_Stream_0 : constant t_irq_index := 11; + DMA1_Stream_1 : constant t_irq_index := 12; + DMA1_Stream_2 : constant t_irq_index := 13; + DMA1_Stream_3 : constant t_irq_index := 14; + DMA1_Stream_4 : constant t_irq_index := 15; + DMA1_Stream_5 : constant t_irq_index := 16; + DMA1_Stream_6 : constant t_irq_index := 17; + DMA1_Stream_7 : constant t_irq_index := 47; + + SDIO : constant t_irq_index := 49; + + DMA2_Stream_0 : constant t_irq_index := 56; + DMA2_Stream_1 : constant t_irq_index := 57; + DMA2_Stream_2 : constant t_irq_index := 58; + DMA2_Stream_3 : constant t_irq_index := 59; + DMA2_Stream_4 : constant t_irq_index := 60; + DMA2_Stream_5 : constant t_irq_index := 68; + DMA2_Stream_6 : constant t_irq_index := 69; + DMA2_Stream_7 : constant t_irq_index := 70; + + ------------------------------------------------- + -- Interrupt set-enable registers (NVIC_ISERx) -- + ------------------------------------------------- + + type t_irq_state is (IRQ_DISABLED, IRQ_ENABLED) + with size => 1; + for t_irq_state use (IRQ_DISABLED => 0, IRQ_ENABLED => 1); + + DISABLE_IRQ : constant t_irq_state := IRQ_ENABLED; -- NVIC_ICER + + type t_irq_states is array (t_irq_index range <>) of t_irq_state + with pack; + + -- ISER0 + type t_NVIC_ISER0 is record + irq : t_irq_states (0 .. 31); + end record + with pack, size => 32, volatile_full_access; + + -- ISER1 + type t_NVIC_ISER1 is record + irq : t_irq_states (32 .. 63); + end record + with pack, size => 32, volatile_full_access; + + -- ISER2 + type t_NVIC_ISER2 is record + irq : t_irq_states (64 .. 80); + end record + with size => 32, volatile_full_access; + + for t_NVIC_ISER2 use record + irq at 0 range 0 .. 16; + end record; + + --------------------------------------------------- + -- Interrupt clear-enable registers (NVIC_ICERx) -- + --------------------------------------------------- + + -- ICER0 + type t_NVIC_ICER0 is record + irq : t_irq_states (0 .. 31); + end record + with pack, size => 32, volatile_full_access; + + -- ICER1 + type t_NVIC_ICER1 is record + irq : t_irq_states (32 .. 63); + end record + with pack, size => 32, volatile_full_access; + + -- ICER2 + type t_NVIC_ICER2 is record + irq : t_irq_states (64 .. 80); + end record + with size => 32, volatile_full_access; + + for t_NVIC_ICER2 use record + irq at 0 range 0 .. 16; + end record; + + ---------------------------------------------------- + -- Interrupt clear-pending registers (NVIC_ICPRx) -- + ---------------------------------------------------- + + type t_irq_pending is (IRQ_NOT_PENDING, IRQ_PENDING) + with size => 1; + for t_irq_pending use (IRQ_NOT_PENDING => 0, IRQ_PENDING => 1); + + CLEAR_PENDING : constant t_irq_pending := IRQ_PENDING; + + type t_irq_pendings is array (t_irq_index range <>) of t_irq_pending + with pack; + + -- ICPR0 + type t_NVIC_ICPR0 is record + irq : t_irq_pendings (0 .. 31); + end record + with pack, size => 32, volatile_full_access; + + -- ICPR1 + type t_NVIC_ICPR1 is record + irq : t_irq_pendings (32 .. 63); + end record + with pack, size => 32, volatile_full_access; + + -- ICPR2 + type t_NVIC_ICPR2 is record + irq : t_irq_pendings (64 .. 80); + end record + with size => 32, volatile_full_access; + + for t_NVIC_ICPR2 use record + irq at 0 range 0 .. 16; + end record; + + ---------------------------------------------- + -- Interrupt priority registers (NVIC_IPRx) -- + ---------------------------------------------- + + -- NVIC_IPR0-IPR80 registers provide an 8-bit priority field for each + -- interrupt. + + type t_IPR is record + reserved : bits_4; + priority : bits_4; + end record + with pack, size => 8, volatile_full_access; + + type t_IPRs is array (t_irq_index) of t_IPR + with pack, size => 8 * 81; + + --------------------- + -- NVIC peripheral -- + --------------------- + + type t_NVIC_periph is record + ISER0 : t_NVIC_ISER0; + ISER1 : t_NVIC_ISER1; + ISER2 : t_NVIC_ISER2; + ICER0 : t_NVIC_ICER0; + ICER1 : t_NVIC_ICER1; + ICER2 : t_NVIC_ICER2; + ICPR0 : t_NVIC_ICPR0; + ICPR1 : t_NVIC_ICPR1; + ICPR2 : t_NVIC_ICPR2; + IPR : t_IPRs; + end record + with volatile; + + for t_NVIC_periph use record + ISER0 at 16#0# range 0 .. 31; + ISER1 at 16#4# range 0 .. 31; + ISER2 at 16#8# range 0 .. 31; + ICER0 at 16#80# range 0 .. 31; + ICER1 at 16#84# range 0 .. 31; + ICER2 at 16#88# range 0 .. 31; + ICPR0 at 16#180# range 0 .. 31; + ICPR1 at 16#184# range 0 .. 31; + ICPR2 at 16#188# range 0 .. 31; + IPR at 16#300# range 0 .. (8*81)-1; + end record; + + NVIC : t_NVIC_periph + with + import, volatile, address => m4.layout.NVIC_BASE; + + ------------- + -- Methods -- + ------------- + + function to_irq_number + (intr : soc.interrupts.t_interrupt) + return t_irq_index + with + inline, + pre => intr >= soc.interrupts.INT_WWDG; + + procedure enable_irq + (irq : in t_irq_index) + with inline; + + procedure clear_pending_irq + (irq : in t_irq_index) + with inline; + +end soc.nvic; diff --git a/arch/socs/stm32f439/Ada/soc-rcc.adb.DRAFT b/arch/socs/stm32f439/Ada/soc-rcc.adb.DRAFT new file mode 100644 index 0000000..ba032dc --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-rcc.adb.DRAFT @@ -0,0 +1,154 @@ +package body soc.rcc + with spark_mode => off +is + + -- + -- Simple switch/case enabling of disabling the given peripheral RCC input + -- line. + -- This procedure abstract the RCC register structure. + -- + procedure set_device_rcc(dev : soc.devmap.t_peripheral_id; + mode : t_RCC_mode) + is + value : boolean; + begin + if mode = RCC_ENABLE then + value := true; + else + value := false; + end if; + case dev is + when DEV_NVIC => + return; + -- AHB2 RCC register + when DEV_RNG => + RCC.AHB2.RNGEN := value; + when DEV_DCMI => + RCC.AHB2.DCMIEN := value; + when DEV_CRYP => + RCC.AHB2.CRYPEN := value; + when DEV_HASH => + RCC.AHB2.HASHEN := value; + when DEV_USB_OTG_FS => + RCC.AHB2.OTGFSEN := value; + -- AHB1 RCC register + when DEV_GPIOA => + RCC.AHB1.GPIOAEN := value; + when DEV_GPIOB => + RCC.AHB1.GPIOBEN := value; + when DEV_GPIOC => + RCC.AHB1.GPIOCEN := value; + when DEV_GPIOD => + RCC.AHB1.GPIODEN := value; + when DEV_GPIOE => + RCC.AHB1.GPIOEEN := value; + when DEV_GPIOF => + RCC.AHB1.GPIOFEN := value; + when DEV_GPIOG => + RCC.AHB1.GPIOGEN := value; + when DEV_GPIOH => + RCC.AHB1.GPIOAEN := value; + when DEV_GPIOI => + RCC.AHB1.GPIOIEN := value; + when DEV_USB_OTG_HS => + RCC.AHB1.OTGHSEN := value; + when DEV_USB_OTG_HS_ULPI => + RCC.AHB1.OTGHSULPIEN := value; + when DEV_CRC => + RCC.AHB1.CRCEN := value; + when DEV_BKPSRAM => + RCC.AHB1.BKPSRAMEN := value; + when DEV_DMA1 => + RCC.AHB1.DMA1EN := value; + when DEV_DMA2 => + RCC.AHB1.DMA2EN := value; + when DEV_ETH_MAC => + RCC.AHB1.ETHMACEN := value; + when DEV_ETH_MAC_TX => + RCC.AHB1.ETHMACTXEN := value; + when DEV_ETH_MAC_RX => + RCC.AHB1.ETHMACRXEN := value; + when DEV_ETH_MAC_PTP => + RCC.AHB1.ETHMACPTPEN := value; + -- APB1 RCC register + when DEV_TIM2 => + RCC.APB1.TIM2EN := value; + when DEV_TIM3 => + RCC.APB1.TIM3EN := value; + when DEV_TIM4 => + RCC.APB1.TIM4EN := value; + when DEV_TIM5 => + RCC.APB1.TIM5EN := value; + when DEV_TIM6 => + RCC.APB1.TIM6EN := value; + when DEV_TIM7 => + RCC.APB1.TIM7EN := value; + when DEV_TIM12 => + RCC.APB1.TIM12EN := value; + when DEV_TIM13 => + RCC.APB1.TIM13EN := value; + when DEV_TIM14 => + RCC.APB1.TIM14EN := value; + when DEV_WWDG => + RCC.APB1.WWDGEN := value; + when DEV_SPI2 => + RCC.APB1.SPI2EN := value; + when DEV_SPI3 => + RCC.APB1.SPI3EN := value; + when DEV_USART2 => + RCC.APB1.USART2EN := value; + when DEV_USART3 => + RCC.APB1.USART3EN := value; + when DEV_UART4 => + RCC.APB1.UART4EN := value; + when DEV_UART5 => + RCC.APB1.UART5EN := value; + when DEV_I2C1 => + RCC.APB1.I2C1EN := value; + when DEV_I2C2 => + RCC.APB1.I2C2EN := value; + when DEV_I2C3 => + RCC.APB1.I2C3EN := value; + when DEV_CAN1 => + RCC.APB1.CAN1EN := value; + when DEV_CAN2 => + RCC.APB1.CAN2EN := value; + when DEV_PWR => + RCC.APB1.PWREN := value; + when DEV_DAC => + RCC.APB1.DACEN := value; + when DEV_UART7 => + RCC.APB1.UART4EN := value; + when DEV_UART8 => + RCC.APB1.UART5EN := value; + -- APB2 RCC register + when DEV_TIM1 => + RCC.APB2.TIM1EN := value; + when DEV_TIM8 => + RCC.APB2.TIM8EN := value; + when DEV_USART1 => + RCC.APB2.USART1EN := value; + when DEV_USART6 => + RCC.APB2.USART6EN := value; + when DEV_ADC1 => + RCC.APB2.ADC1EN := value; + when DEV_ADC2 => + RCC.APB2.ADC2EN := value; + when DEV_ADC3 => + RCC.APB2.ADC3EN := value; + when DEV_SDIO => + RCC.APB2.SDIOEN := value; + when DEV_SPI1 => + RCC.APB2.SPI1EN := value; + when DEV_SYSCFG => + RCC.APB2.SYSCFGEN := value; + when DEV_TIM9 => + RCC.APB2.TIM9EN := value; + when DEV_TIM10 => + RCC.APB2.TIM10EN := value; + when DEV_TIM11 => + RCC.APB2.TIM11EN := value; + end case; + end; + +end soc.rcc; diff --git a/arch/socs/stm32f439/Ada/soc-rcc.ads b/arch/socs/stm32f439/Ada/soc-rcc.ads new file mode 100644 index 0000000..14a7b9a --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-rcc.ads @@ -0,0 +1,225 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +with system; + + +package soc.rcc + with spark_mode => on +is + + type t_RCC_mode is + (RCC_DISABLE, + RCC_ENABLE); + + type t_RCC_CR is record + HSION : boolean; -- Internal high-speed clock enable + HSIRDY : boolean; -- Internal high-speed clock ready flag + Reserved_2_2 : bit; + HSITRIM : bits_5; -- Internal high-speed clock trimming + HSICAL : unsigned_8; -- Internal high-speed clock calibration + HSEON : boolean; -- HSE clock enable + HSERDY : boolean; -- HSE clock ready flag + HSEBYP : boolean; -- HSE clock bypassed (with an ext. clock) + CSSON : boolean; -- Clock security system enable + Reserved_20_23 : bits_4; + PLLON : boolean; -- Main PLL enable + PLLRDY : boolean; -- Main PLL clock ready flag + PLLI2SON : boolean; -- PLLI2S enable + PLLI2SRDY : boolean; -- PLLI2S clock ready flag + Reserved_28_31 : bits_4; + end record + with volatile_full_access, size => 32; + + for t_RCC_CR use record + HSION at 0 range 0 .. 0; + HSIRDY at 0 range 1 .. 1; + Reserved_2_2 at 0 range 2 .. 2; + HSITRIM at 0 range 3 .. 7; + HSICAL at 0 range 8 .. 15; + HSEON at 0 range 16 .. 16; + HSERDY at 0 range 17 .. 17; + HSEBYP at 0 range 18 .. 18; + CSSON at 0 range 19 .. 19; + Reserved_20_23 at 0 range 20 .. 23; + PLLON at 0 range 24 .. 24; + PLLRDY at 0 range 25 .. 25; + PLLI2SON at 0 range 26 .. 26; + PLLI2SRDY at 0 range 27 .. 27; + Reserved_28_31 at 0 range 28 .. 31; + end record; + + ----------------- + -- RCC_AHB1ENR -- + ----------------- + + -- RCC AHB1 peripheral clock enable register + -- Ref. : RM0090, p. 242 + + type t_RCC_AHB1ENR is record + GPIOAEN : boolean; -- IO port A clock enable + GPIOBEN : boolean; -- IO port B clock enable + GPIOCEN : boolean; -- IO port C clock enable + GPIODEN : boolean; -- IO port D clock enable + GPIOEEN : boolean; -- IO port E clock enable + GPIOFEN : boolean; -- IO port F clock enable + GPIOGEN : boolean; -- IO port G clock enable + GPIOHEN : boolean; -- IO port H clock enable + GPIOIEN : boolean; -- IO port I clock enable + reserved_9_11 : bits_3; + CRCEN : boolean; -- CRC clock enable + reserved_13_17 : bits_5; + BKPSRAMEN : boolean; -- Backup SRAM interface clock enable + reserved_19 : bit; + CCMDATARAMEN : boolean; -- CCM data RAM clock enable + DMA1EN : boolean; -- DMA1 clock enable + DMA2EN : boolean; -- DMA2 clock enable + reserved_23_24 : bit; + ETHMACEN : boolean; -- Ethernet MAC clock enable + ETHMACTXEN : boolean; -- Ethernet Transmission clock enable + ETHMACRXEN : boolean; -- Ethernet Reception clock enable + ETHMACPTPEN : boolean; -- Ethernet PTP clock enable + OTGHSEN : boolean; -- USB OTG HS clock enable + OTGHSULPIEN : boolean; -- USB OTG HSULPI clock enable + reserved_31 : bit; + end record + with pack, size => 32, volatile_full_access; + + ----------------- + -- RCC_AHB2ENR -- + ----------------- + + type t_RCC_AHB2ENR is record + DCMIEN : boolean; -- DCMI clock enable + reserved_3 : bits_3; + CRYPEN : boolean; -- CRYP clock enable + HASHEN : boolean; -- HASH clock enable + RNGEN : boolean; -- RNG clock enable + OTGFSEN : boolean; -- USB OTG Full Speed clock enable + reserved_8_15 : byte; + reserved_16_31 : unsigned_16; + end record + with pack, size => 32, volatile_full_access; + + ----------------- + -- RCC_APB1ENR -- + ----------------- + + type t_RCC_APB1ENR is record + TIM2EN : boolean; -- TIM2 clock enable + TIM3EN : boolean; -- TIM3 clock enable + TIM4EN : boolean; -- TIM4 clock enable + TIM5EN : boolean; -- TIM5 clock enable + TIM6EN : boolean; -- TIM6 clock enable + TIM7EN : boolean; -- TIM7 clock enable + TIM12EN : boolean; -- TIM12 clock enable + TIM13EN : boolean; -- TIM13 clock enable + TIM14EN : boolean; -- TIM14 clock enable + reserved_9_10 : bits_2; + WWDGEN : boolean; -- Window watchdog clock enable + reserved_12_13 : bits_2; + SPI2EN : boolean; -- SPI2 clock enable + SPI3EN : boolean; -- SPI3 clock enable + reserved_16 : boolean; + USART2EN : boolean; -- USART2 clock enable + USART3EN : boolean; -- USART3 clock enable + UART4EN : boolean; -- UART4 clock enable + UART5EN : boolean; -- UART5 clock enable + I2C1EN : boolean; -- I2C1 clock enable + I2C2EN : boolean; -- I2C2 clock enable + I2C3EN : boolean; -- I2C3 clock enable + reserved_24 : bit; + CAN1EN : boolean; -- CAN 1 clock enable + CAN2EN : boolean; -- CAN 2 clock enable + reserved_27 : bit; + PWREN : boolean; -- Power interface clock enable + DACEN : boolean; -- DAC interface clock enable + UART7EN : boolean; -- UART7 clock enable + UART8EN : boolean; -- UART8 clock enable + end record + with pack, size => 32, volatile_full_access; + + ----------------- + -- RCC_APB2ENR -- + ----------------- + + -- RCC APB2 peripheral clock enable register + -- Ref. : RM0090, p. 248 + + type t_RCC_APB2ENR is record + TIM1EN : boolean; -- TIM1 clock enable + TIM8EN : boolean; -- TIM8 clock enable + reserved_2_3 : bits_2; + USART1EN : boolean; -- USART1 clock enable + USART6EN : boolean; -- USART6 clock enable + reserved_6_7 : bits_2; + ADC1EN : boolean; -- ADC1 clock enable + ADC2EN : boolean; -- ADC2 clock enable + ADC3EN : boolean; -- ADC3 clock enable + SDIOEN : boolean; -- SDIO clock enable + SPI1EN : boolean; -- SPI1 clock enable + reserved_13 : bit; + SYSCFGEN : boolean; + -- System configuration controller clock enable + reserved_15 : bit; + TIM9EN : boolean; -- TIM9 clock enable + TIM10EN : boolean; -- TIM10 clock enable + TIM11EN : boolean; -- TIM11 clock enable + reserved_19_23 : bits_5; + reserved_24_31 : unsigned_8; + end record + with pack, size => 32, volatile_full_access; + + -------------------- + -- RCC peripheral -- + -------------------- + type t_RCC_bus is + (RCC_AHB1_BUS, + RCC_AHB2_BUS, + RCC_APB1_BUS, + RCC_APB2_BUS); + + type t_RCC_peripheral is record + CR : t_RCC_CR; + AHB1 : t_RCC_AHB1ENR; + AHB2 : t_RCC_AHB2ENR; + APB1 : t_RCC_APB1ENR; + APB2 : t_RCC_APB2ENR; + end record + with volatile; + + for t_RCC_peripheral use record + CR at 16#00# range 0 .. 31; + AHB1 at 16#30# range 0 .. 31; + AHB2 at 16#34# range 0 .. 31; + APB1 at 16#40# range 0 .. 31; + APB2 at 16#44# range 0 .. 31; + end record; + + RCC : t_RCC_peripheral + with + import, + volatile, + address => system'to_address(16#4002_3800#); + +end soc.rcc; diff --git a/arch/socs/stm32f439/Ada/soc-syscfg.adb b/arch/socs/stm32f439/Ada/soc-syscfg.adb new file mode 100644 index 0000000..ac09ad5 --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-syscfg.adb @@ -0,0 +1,66 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +package body soc.syscfg + with spark_mode => off +is + + + function get_exti_port + (pin : soc.gpio.t_gpio_pin_index) + return soc.gpio.t_gpio_port_index + is + begin + + case pin is + when 0 .. 3 => + return SYSCFG.EXTICR1.exti(pin); + when 4 .. 7 => + return SYSCFG.EXTICR2.exti(pin); + when 8 .. 11 => + return SYSCFG.EXTICR3.exti(pin); + when 12 .. 15 => + return SYSCFG.EXTICR4.exti(pin); + end case; + + end get_exti_port; + + + procedure set_exti_port + (pin : in soc.gpio.t_gpio_pin_index; + port : in soc.gpio.t_gpio_port_index) + is + begin + case pin is + when 0 .. 3 => + SYSCFG.EXTICR1.exti(pin) := port; + when 4 .. 7 => + SYSCFG.EXTICR2.exti(pin) := port; + when 8 .. 11 => + SYSCFG.EXTICR3.exti(pin) := port; + when 12 .. 15 => + SYSCFG.EXTICR4.exti(pin) := port; + end case; + end set_exti_port; + +end soc.syscfg; diff --git a/arch/socs/stm32f439/Ada/soc-syscfg.ads b/arch/socs/stm32f439/Ada/soc-syscfg.ads new file mode 100644 index 0000000..74e6e2f --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc-syscfg.ads @@ -0,0 +1,173 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + +with soc.layout; +with soc.gpio; +with system; + +package soc.syscfg + with spark_mode => off +is + + -------------------------------------------------- + -- SYSCFG memory remap register (SYSCFG_MEMRMP) -- + -------------------------------------------------- + + type t_SYSCFG_MEMRMP is record + MEM_MODE : bits_3; + reserved_3_7 : bits_5; + FB_MODE : bit; + reserved_9 : bit; + SWP_FMC : bits_2; + reserved_12_15 : bits_4; + reserved_16_31 : unsigned_16; + end record + with volatile_full_access, size => 32; + + for t_SYSCFG_MEMRMP use record + MEM_MODE at 0 range 0 .. 2; + reserved_3_7 at 0 range 3 .. 7; + FB_MODE at 0 range 8 .. 8; + reserved_9 at 0 range 9 .. 9; + SWP_FMC at 0 range 10 .. 11; + reserved_12_15 at 0 range 12 .. 15; + reserved_16_31 at 0 range 16 .. 31; + end record; + + ---------------------------------------------------------------- + -- SYSCFG peripheral mode configuration register (SYSCFG_PMC) -- + ---------------------------------------------------------------- + + type t_SYSCFG_PMC is record + reserved_0_15 : unsigned_16; + ADC1DC2 : bit; + ADC2DC2 : bit; + ADC3DC2 : bit; + reserved_19_22 : bits_4; + MII_RMII_SEL : bit; + reserved_24_31 : byte; + end record + with volatile_full_access, size => 32; + + for t_SYSCFG_PMC use record + reserved_0_15 at 0 range 0 .. 15; + ADC1DC2 at 0 range 16 .. 16; + ADC2DC2 at 0 range 17 .. 17; + ADC3DC2 at 0 range 18 .. 18; + reserved_19_22 at 0 range 19 .. 22; + MII_RMII_SEL at 0 range 23 .. 23; + reserved_24_31 at 0 range 24 .. 31; + end record; + + ------------------------------------------------------------------------ + -- SYSCFG external interrupt configuration registers (SYSCFG_EXTICRx) -- + ------------------------------------------------------------------------ + type t_exticr_list is + array (soc.gpio.t_gpio_pin_index range <>) of soc.gpio.t_gpio_port_index + with pack; + + type t_SYSCFG_EXTICR1 is record + exti : t_exticr_list (0 .. 3); + reserved : short; + end record + with pack, size => 32, volatile_full_access; + + type t_SYSCFG_EXTICR2 is record + exti : t_exticr_list (4 .. 7); + reserved : short; + end record + with pack, size => 32, volatile_full_access; + + type t_SYSCFG_EXTICR3 is record + exti : t_exticr_list (8 .. 11); + reserved : short; + end record + with pack, size => 32, volatile_full_access; + + type t_SYSCFG_EXTICR4 is record + exti : t_exticr_list (12 .. 15); + reserved : short; + end record + with pack, size => 32, volatile_full_access; + + ------------------------------------------------------- + -- Compensation cell control register (SYSCFG_CMPCR) -- + ------------------------------------------------------- + + type t_SYSCFG_CMPCR is record + CMP_PD : bit; + reserved_1_6 : bits_6; + READY : bit; + reserved_8_15 : byte; + reserved_16_31 : unsigned_16; + end record + with volatile_full_access, size => 32; + + for t_SYSCFG_CMPCR use record + CMP_PD at 0 range 0 .. 0; + reserved_1_6 at 0 range 1 .. 6; + READY at 0 range 7 .. 7; + reserved_8_15 at 0 range 8 .. 15; + reserved_16_31 at 0 range 16 .. 31; + end record; + + ----------------------- + -- SYSCFG peripheral -- + ----------------------- + + type t_SYSCFG_periph is record + MEMRMP : t_SYSCFG_MEMRMP; + PMC : t_SYSCFG_PMC; + EXTICR1 : t_SYSCFG_EXTICR1; + EXTICR2 : t_SYSCFG_EXTICR2; + EXTICR3 : t_SYSCFG_EXTICR3; + EXTICR4 : t_SYSCFG_EXTICR4; + CMPCR : t_SYSCFG_CMPCR; + end record + with volatile; + + for t_SYSCFG_periph use record + MEMRMP at 16#00# range 0 .. 31; + PMC at 16#04# range 0 .. 31; + EXTICR1 at 16#08# range 0 .. 31; + EXTICR2 at 16#0C# range 0 .. 31; + EXTICR3 at 16#10# range 0 .. 31; + EXTICR4 at 16#14# range 0 .. 31; + CMPCR at 16#20# range 0 .. 31; + end record; + + SYSCFG : t_SYSCFG_periph + with + import, + volatile, + address => system'to_address (soc.layout.SYSCFG_BASE); -- 0x40013800 + + + function get_exti_port + (pin : soc.gpio.t_gpio_pin_index) + return soc.gpio.t_gpio_port_index; + + procedure set_exti_port + (pin : in soc.gpio.t_gpio_pin_index; + port : in soc.gpio.t_gpio_port_index); + +end soc.syscfg; diff --git a/arch/socs/stm32f439/Ada/soc.ads b/arch/socs/stm32f439/Ada/soc.ads new file mode 100644 index 0000000..c59e8ce --- /dev/null +++ b/arch/socs/stm32f439/Ada/soc.ads @@ -0,0 +1,38 @@ +-- +-- Copyright 2018 The wookey project team +-- - Ryad Benadjila +-- - Arnauld Michelizza +-- - Mathieu Renard +-- - Philippe Thierry +-- - Philippe Trebuchet +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- + + +pragma Restrictions (No_Elaboration_Code); + +pragma warnings (Off, "use clause for package"); + +-- distribute interfaces and types to child packages +with interfaces; use interfaces; +pragma unreferenced (interfaces); + +with types; use types; +pragma unreferenced (types); + +pragma warnings (On, "use clause for package"); + +package soc is +end soc; diff --git a/arch/socs/stm32f439/Kconfig b/arch/socs/stm32f439/Kconfig new file mode 100644 index 0000000..e69de29 diff --git a/arch/socs/stm32f439/Makefile.objs b/arch/socs/stm32f439/Makefile.objs new file mode 100644 index 0000000..e42b7c0 --- /dev/null +++ b/arch/socs/stm32f439/Makefile.objs @@ -0,0 +1,43 @@ +SOC_DIR = $(PROJ_FILES)kernel/arch/socs/stm32f439 + +CFLAGS += -I$(PROJ_FILES)/kernel/arch/socs +CFLAGS += -I$(PROJ_FILES)/kernel/arch/socs/stm32f439 + +socdrv-y := +socdrv-bsp-y := + +# this is the Board Support package content +socdrv-bsp-y += soc-rcc.c +socdrv-bsp-y += soc-rng.c +socdrv-bsp-y += soc-interrupts.c +socdrv-bsp-y += soc-gpio.c +socdrv-bsp-y += soc-usart.c +socdrv-bsp-y += soc-exti.c +socdrv-bsp-y += soc-init.c +socdrv-bsp-y += soc-devmap.c +socdrv-bsp-y += default_handlers.c +socdrv-bsp-y += postpone.c +# mutually exclusive +socdrv-bsp-$(CONFIG_KERNEL_DMA_ENABLE) += soc-dma.c +socdrv-bsp-$(CONFIG_KERNEL_UNSAFE_DMA_ENABLE) += soc-dma.c + +socdrv-bsp-y += soc-dwt.c + +ifeq ($(CONFIG_ADAKERNEL),y) +# for Ada equivalent +#socdrv-ada-bsp-y += Ada/soc-rcc.adb +#socdrv-ada-bsp-y += Ada/soc-rng.adb +socdrv-ada-bsp-y += Ada/soc-interrupts.adb +socdrv-ada-bsp-y += Ada/soc-gpio.adb +socdrv-ada-bsp-y += Ada/soc-gpio-interfaces.adb +#socdrv-ada-bsp-y += Ada/soc-usart.adb +socdrv-ada-bsp-y += Ada/soc-exti.adb +#socdrv-ada-bsp-y += Ada/soc-init.adb +socdrv-ada-bsp-y += Ada/default_handlers.adb +#socdrv-ada-bsp-y += Ada/postpone.adb +socdrv-ada-bsp-y += Ada/soc-dma.adb +socdrv-ada-bsp-y += Ada/soc-dwt.adb +#socdrv-ada_bsp-y += Ada/soc-devmap.adb +socdrv-ada-bsp-y += Ada/soc-nvic.adb +socdrv-ada-bsp-y += Ada/soc-syscfg.adb +endif diff --git a/arch/socs/stm32f439/default_handlers.c b/arch/socs/stm32f439/default_handlers.c new file mode 100644 index 0000000..8d0b35f --- /dev/null +++ b/arch/socs/stm32f439/default_handlers.c @@ -0,0 +1,184 @@ +/* \file default_handlers.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "m4-systick.h" +#include "m4-core.h" +#include "soc-interrupts.h" +#include "soc-dwt.h" +#include "soc-nvic.h" +#include "soc-scb.h" +#include "devices-shared.h" +#include "debug.h" +#include "kernel.h" +#include "isr.h" + +#ifdef KERNEL +#include "tasks.h" +#include "tasks-shared.h" +#include "sched.h" +#include "layout.h" +#endif + +#define HANDLERLOG(fmt, ...) \ + dbg_log(ANSI_COLOR_RED fmt ANSI_COLOR_RESET, ##__VA_ARGS__) + +/* +** Generic handlers. This handlers can be overloaded later if needed. +*/ + +stack_frame_t *WWDG_IRQ_Handler(stack_frame_t * stack_frame) +{ + while (1) ; + return stack_frame; /* never joined! */ +} + +stack_frame_t *HardFault_Handler(stack_frame_t * frame) +{ + uint32_t cfsr = *((uint32_t *) r_CORTEX_M_SCB_CFSR); + uint32_t hfsr = *((uint32_t *) r_CORTEX_M_SCB_HFSR); + uint32_t *p; + int i; +#ifdef KERNEL + task_t *current_task = sched_get_current(); + if (!current_task) { + /* This happend when hardfaulting before sched module initialization */ + HANDLERLOG("\nEarly kernel hard fault\n scb.hfsr %x scb.cfsr %x\n", hfsr, cfsr); + } else { + HANDLERLOG("\nHard fault from %s\n scb.hfsr %x scb.cfsr %x\n", current_task->name, hfsr, cfsr); + } +#else + HANDLERLOG("\nHard fault\n scb.hfsr %x scb.cfsr %x\n", hfsr, cfsr); +#endif + dbg_flush(); + + HANDLERLOG("-- registers (frame at %x, EXC_RETURN %x)\n", frame, frame->lr); + HANDLERLOG(" r0 %x\t r1 %x\t r2 %x\t r3 %x\n", + frame->r0, frame->r1, frame->r2, frame->r3); + HANDLERLOG(" r4 %x\t r5 %x\t r6 %x\t r7 %x\n", + frame->r4, frame->r5, frame->r6, frame->r7); + HANDLERLOG(" r8 %x\t r9 %x\t r10 %x\t r11 %x\n", + frame->r8, frame->r9, frame->r10, frame->r11); + HANDLERLOG(" r12 %x\t pc %x\t lr %x\n", + frame->r12, frame->pc, frame->prev_lr); + dbg_flush(); + + p = (uint32_t*) ((uint32_t) frame & 0xfffffff0); + dbg_log("-- stack trace\n"); + for (i=0;i<8;i++) { + HANDLERLOG(" %x: %x %x %x %x\n", p, p[0], p[1], p[2], p[3]); + dbg_flush(); + p = p + 4; + } +#ifdef KERNEL + if (frame_is_kernel((physaddr_t)frame)) { + HANDLERLOG("Oops! Kernel panic!\n"); + } + /* + * here current_task can't be null as the frame is user + * (i.e. the sched module is already started) + */ + current_task->state[current_task->mode] = TASK_STATE_FAULT; + request_schedule(); +#else + /* Non kernel mode (e.g. loader mode) */ + HANDLERLOG("Oops! Kernel panic!\n"); +#endif + return frame; +} + +/* FIXME - Should be moved in the kernel*/ + +/* + * To avoid purging the Default_Handler stack (making irq_enter/irq_return + * fail), all the default handler algorithmic MUST be done in a subframe (i.e. + * in a child function) + */ +__ISR_HANDLER stack_frame_t *Default_SubHandler(stack_frame_t * stack_frame) +{ + uint8_t int_num; + s_irq *cell; + stack_frame_t *new_frame; +#ifdef KERNEL + e_task_type current_type; + task_t *current; +#else + uint8_t current_type; +#endif + + /* Getting the IRQ number */ + interrupt_get_num(int_num); + int_num &= 0x1ff; + + /* + * The 'cell' in the IRQ table contains, for each IRQ, the related task + * and a pointer to it's IRQ handler + */ + cell = get_cell_from_interrupt(int_num); + cell->count++; + + /* + * External interrupts don't switch tasks + */ + if (int_num > 15) { + + if (cell->task_id != ID_UNUSED) { + /* User or kernel ISR */ + postpone_isr(int_num, cell, stack_frame); + } + else { + /* Kernel ISR w/o associated device (SCB ISR) */ + if (cell->irq_handler == 0) { + panic("Unhandled IRQ number %x\n", int_num); + } else { + cell->irq_handler(stack_frame); + } + } + new_frame = stack_frame; + } + /* + * System exceptions might switch tasks + */ + else { + if (cell->irq_handler == 0) { + panic("Unhandled exception %x\n", int_num); + } + new_frame = cell->irq_handler(stack_frame); + } + +#ifdef KERNEL + current = sched_get_current(); + if (current->id != ID_UNUSED) { + current_type = current->type; + } else { + current_type = TASK_TYPE_KERNEL; + } +#else + current_type = 0; +#endif + + asm volatile + ("mov r1, %0" :: "r" (current_type) : "r1"); + + return new_frame; + +} + diff --git a/arch/socs/stm32f439/default_handlers.h b/arch/socs/stm32f439/default_handlers.h new file mode 100644 index 0000000..2659ece --- /dev/null +++ b/arch/socs/stm32f439/default_handlers.h @@ -0,0 +1,33 @@ +/* \file default_handlers.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef DEFAULT_HANDLERS_H_ +# define DEFAULT_HANDLERS_H_ + +stack_frame_t *WWDG_IRQ_Handler(stack_frame_t * stack_frame); + +stack_frame_t *HardFault_Handler(stack_frame_t * frame); + +__ISR_HANDLER stack_frame_t *Default_SubHandler(stack_frame_t * stack_frame); + +#endif /*!DEFAULT_HANDLERS_H_*/ diff --git a/arch/socs/stm32f439/fw1.ld.in b/arch/socs/stm32f439/fw1.ld.in new file mode 100644 index 0000000..78992cd --- /dev/null +++ b/arch/socs/stm32f439/fw1.ld.in @@ -0,0 +1,134 @@ +/* fw1.ld */ + +/* */ +INCLUDE BUILDDIR/layout.ld + +INCLUDE BUILDDIR/layout.apps.ld + +/* + Memory layout + + +-------------------+ 0x0000 0000 + + isr_vector + + +-------------------- + + +-------------------- 0x2000 0000 (RAM_BASE) + | RAM | + ~~~~~~~~~~~~~~~~~~~~~ 0x2002 0000 + + +-------------------+ 0x0800 0000 (LDR_BASE) + + Flash + + +- - - - - - - - - -+ 0x0802 0000 (SHR_BASE) + + + + +- - - - - - - - - -+ 0x0808 0000 (FW1_BASE) + + + + +- - - - - - - - - -+ 0x080C 0000 (FW2_BASE) + + + + +-------------------+ 0x0810 0000 + +*/ + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FW1_KERN + + /* Shared variables */ + .shared : { + . = ALIGN(4); + KEEP(*(.shared)) ; + } >SHR + + /* The program code and other data goes into FLASH */ + .text : + { + _stext = .; /* create a global symbol at data start */ + *startup*(.text.Reset_Handler) /* kernel code should start with its reset handler */ + *(.text*) + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + _exit = .; + } >FW1_KERN + + /* used by the startup to initialize got */ + _sigot = .; + .got : AT ( _sigot ) { + . = ALIGN(4); + _sgot = .; + /* *(.got.plt) + * We don't need plt segment + * since we do not need dynamic library relocation + */ + *(.got) + . = ALIGN(4); + _egot = .; + ASSERT (((_egot - _stext) < _Max_Kern_Size), "Error: FW1 kernel txt region (txt+rodata+got) size too big!"); + } >FW1_KERN + + /* used by the startup to initialize data */ + _sidata = .; + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + _edata = .; /* define a global symbol at data end */ + } >RAM_KERN + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *debug.o(.bss) + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; +/* ASSERT (((__bss_end__ - _sidata) < _Max_Kern_Data), "Error: FW1 kernel .text size too big!");*/ + } >RAM_KERN + + /* Kernel _heap_stack section, used to check that there is enough RAM left */ + ._heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(4); + } >RAM_KERN + + + +/* + this part is preprocessed to associate each application to its slot properly, based on the + user's choice in the menuconfig + */ + INCLUDE BUILDDIR/apps_sections.fw1.ld + + /DISCARD/ : + { + } +} diff --git a/arch/socs/stm32f439/fw2.ld.in b/arch/socs/stm32f439/fw2.ld.in new file mode 100644 index 0000000..eddf196 --- /dev/null +++ b/arch/socs/stm32f439/fw2.ld.in @@ -0,0 +1,126 @@ +/* fw1.ld */ + +/* */ +INCLUDE BUILDDIR/layout.ld + +INCLUDE BUILDDIR/layout.apps.ld + +/* + Memory layout + + +-------------------+ 0x0000 0000 + + isr_vector + + +-------------------- + + +-------------------- 0x2000 0000 (RAM_BASE) + | RAM | + ~~~~~~~~~~~~~~~~~~~~~ 0x2002 0000 + + +-------------------+ 0x0800 0000 (LDR_BASE) + + Flash + + +- - - - - - - - - -+ 0x0802 0000 (SHR_BASE) + + + + +- - - - - - - - - -+ 0x0808 0000 (FW1_BASE) + + + + +- - - - - - - - - -+ 0x080C 0000 (FW2_BASE) + + + + +-------------------+ 0x0810 0000 + +*/ + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FW2_KERN + + /* Shared variables */ + .shared : { + . = ALIGN(4); + KEEP(*(.shared)) ; + } >SHR + + /* The program code and other data goes into FLASH */ + .text : + { + _stext = .; /* create a global symbol at data start */ + *startup*(.text.Reset_Handler) /* kernel code should start with its reset handler */ + *(.text*) + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + _exit = .; + } >FW2_KERN + + /* used by the startup to initialize got */ + _sigot = .; + .got : AT ( _sigot ) { + . = ALIGN(4); + _sgot = .; + /* *(.got.plt) + * We don't need plt segment + * since we do not need dynamic library relocation + */ + *(.got) + . = ALIGN(4); + _egot = .; + } >FW2_KERN + + /* used by the startup to initialize data */ + _sidata = .; + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + _edata = .; /* define a global symbol at data end */ + } >RAM_KERN + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *debug.o(.bss) + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM_KERN + + /* Kernel _heap_stack section, used to check that there is enough RAM left */ + ._heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(4); + } >RAM_KERN + + INCLUDE BUILDDIR/apps_sections.fw2.ld + + /DISCARD/ : + { + } +} diff --git a/arch/socs/stm32f439/postpone.c b/arch/socs/stm32f439/postpone.c new file mode 100644 index 0000000..a1cc4fd --- /dev/null +++ b/arch/socs/stm32f439/postpone.c @@ -0,0 +1,34 @@ +/* \file postpone.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "soc-interrupts.h" + +static void empty_postpone(void) +{ + for (;;) + ; +} + +/* Will be replaced by official postpone_isr function */ +stack_frame_t *postpone_isr(uint8_t, s_irq *, stack_frame_t *) + __attribute__ ((weak, alias("empty_postpone"))); + diff --git a/arch/socs/stm32f439/soc-core.h b/arch/socs/stm32f439/soc-core.h new file mode 100644 index 0000000..0ef5eec --- /dev/null +++ b/arch/socs/stm32f439/soc-core.h @@ -0,0 +1,143 @@ +/* \file soc-core.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_CORE_H +#define SOC_CORE_H + +#include "soc-dwt.h" + +#if !defined (__FPU_PRESENT) +#define __FPU_PRESENT 1 /*!< FPU present */ +#endif /* __FPU_PRESENT */ +#define __CM4_REV 0x0001 /*!< Core revision r0p1 */ +#define __MPU_PRESENT 1 /*!< STM32F4XX provides an MPU */ +#define __NVIC_PRIO_BITS 4 /*!< STM32F4XX uses 4 Bits for the Priority Levels */ + +/* Memory mapping of Cortex-M3/M4 Hardware */ +#define CODE_BASE ((uint32_t) 0x00000000) /* Internal Flash Base Address */ +#define FLASH_BASE ((uint32_t) 0x08000000) +#define SRAM_BASE ((uint32_t) 0x20000000) /* Internal SRAM Base Address */ +#define SRAM_BASE_BITBANG_BASE ((uint32_t) 0x22000000) /* From (uint32_t)0x22000000UL to (uint32_t)0x23FFFFFFUL */ +#define PERIPH_BASE ((uint32_t) 0x40000000) /* Peripheral Base Address */ +#define PERIPH_BASE_BITBANG1_BASE ((uint32_t) 0x40000000) /* From (uint32_t)0x40000000UL to (uint32_t)0x400FFFFFUL */ +#define PERIPH_BASE_BITBANG2_BASE ((uint32_t) 0x42000000) /* From (uint32_t)0x42000000UL to (uint32_t)0x43FFFFFFUL */ +#define EXTERNAL_RAM ((uint32_t) 0x60000000) /* From (uint32_t)0x60000000UL to (uint32_t)0x9FFFFFFFUL */ +#define EXTERNAL_DEVICE ((uint32_t) 0xA0000000) /* From (uint32_t)0xA0000000UL to (uint32_t)0xDFFFFFFFUL */ +#define SCS_BASE ((uint32_t) 0xE000E000) /* System Control Space Base Address */ +#define ITM_BASE ((uint32_t) 0xE0000000) /* TODO ITM Base Address */ + +#define CoreDebug_BASE ((uint32_t) 0xE000EDF0) /* Core Debug Base Address */ + +#define SysTick_BASE (SCS_BASE + (uint32_t) 0x010) /* SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + (uint32_t) 0x100) /* NVIC Base Address */ +#define SCB_BASE (SCS_BASE + (uint32_t) 0xd00) /* System Control Block Base Address */ + +#if (__FPU_PRESENT == 1) +#define CPACR_BASE (SCB_BASE + (uint32_t) 0xd88) /* Floating point unit coprocessor access control + register Base Address */ +#else +#warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" +#define __FPU_USED 0 +#endif + +#if (__MPU_PRESENT == 1) +#define MPU_BASE (SCS_BASE + (uint32_t) 0x0D90) /* Memory Protection Unit */ +#else +#warning "Using an MPU on device with no MPU (check __MPU_PRESENT)" +#define __MPU_USED 0 +#endif + +#define NVIC_STIR_BASE (SCS_BASE + (uint32_t) 0xf00) /* NVIC_STIR Base Address */ + +#if (__FPU_PRESENT == 1) +#define FPU_BASE (SCS_BASE + (uint32_t) 0x0F30) +#else +#warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" +#define __FPU_USED 0 +#endif + +/*Peripheral memory map */ +#define APB1PERIPH_BASE PERIPH_BASE +#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) +#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000) +#define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000) + +#define RCC_BASE (AHB1PERIPH_BASE + 0x3800) + +/*APB1 peripherals */ +#define TIM2_BASE (APB1PERIPH_BASE + 0x0000) +#define TIM3_BASE (APB1PERIPH_BASE + 0x0400) +#define TIM4_BASE (APB1PERIPH_BASE + 0x0800) +#define TIM5_BASE (APB1PERIPH_BASE + 0x0C00) +#define TIM6_BASE (APB1PERIPH_BASE + 0x1000) +#define TIM7_BASE (APB1PERIPH_BASE + 0x1400) +#define TIM12_BASE (APB1PERIPH_BASE + 0x1800) +#define TIM13_BASE (APB1PERIPH_BASE + 0x1C00) +#define TIM14_BASE (APB1PERIPH_BASE + 0x2000) +#define RTC_BASE (APB1PERIPH_BASE + 0x2800) +#define WWDG_BASE (APB1PERIPH_BASE + 0x2C00) +#define IWDG_BASE (APB1PERIPH_BASE + 0x3000) +#define I2S2ext_BASE (APB1PERIPH_BASE + 0x3400) +#define SPI2_BASE (APB1PERIPH_BASE + 0x3800) +#define SPI3_BASE (APB1PERIPH_BASE + 0x3C00) +#define I2S3ext_BASE (APB1PERIPH_BASE + 0x4000) +#define USART2_BASE (APB1PERIPH_BASE + 0x4400) +#define USART3_BASE (APB1PERIPH_BASE + 0x4800) +#define UART4_BASE (APB1PERIPH_BASE + 0x4C00) +#define UART5_BASE (APB1PERIPH_BASE + 0x5000) +#define I2C1_BASE (APB1PERIPH_BASE + 0x5400) +#define I2C2_BASE (APB1PERIPH_BASE + 0x5800) +#define I2C3_BASE (APB1PERIPH_BASE + 0x5C00) +#define CAN1_BASE (APB1PERIPH_BASE + 0x6400) +#define CAN2_BASE (APB1PERIPH_BASE + 0x6800) +#define PWR_BASE (APB1PERIPH_BASE + 0x7000) +#define DAC_BASE (APB1PERIPH_BASE + 0x7400) + +/*APB2 peripherals */ +#define TIM1_BASE (APB2PERIPH_BASE + 0x0000) +#define TIM8_BASE (APB2PERIPH_BASE + 0x0400) +#define USART1_BASE (APB2PERIPH_BASE + 0x1000) +#define USART6_BASE (APB2PERIPH_BASE + 0x1400) +#define ADC1_BASE (APB2PERIPH_BASE + 0x2000) +#define ADC2_BASE (APB2PERIPH_BASE + 0x2100) +#define ADC3_BASE (APB2PERIPH_BASE + 0x2200) +#define ADC_BASE (APB2PERIPH_BASE + 0x2300) +//#define SDIO_BASE (APB2PERIPH_BASE + 0x2C00) +#define SPI1_BASE (APB2PERIPH_BASE + 0x3000) +#define SYSCFG_BASE (APB2PERIPH_BASE + 0x3800) +#define EXTI_BASE (APB2PERIPH_BASE + 0x3C00) +#define TIM9_BASE (APB2PERIPH_BASE + 0x4000) +#define TIM10_BASE (APB2PERIPH_BASE + 0x4400) +#define TIM11_BASE (APB2PERIPH_BASE + 0x4800) + +/*AHB1 peripherals */ +#define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000) +#define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400) +#define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800) +#define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00) +#define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000) +#define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400) +#define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800) +#define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00) +#define GPIOI_BASE (AHB1PERIPH_BASE + 0x2000) + +#endif /* SOC_CORE_H */ diff --git a/arch/socs/stm32f439/soc-devmap.c b/arch/socs/stm32f439/soc-devmap.c new file mode 100644 index 0000000..3b2db67 --- /dev/null +++ b/arch/socs/stm32f439/soc-devmap.c @@ -0,0 +1,55 @@ +/* \file soc-devmap.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "types.h" +#include "soc-devmap.h" +#include "m4-cpu.h" +#include "regutils.h" + +struct device_soc_infos* soc_devmap_find_device + (physaddr_t addr, uint16_t size) +{ + for (uint8_t i = 0; i < soc_devices_list_size; ++i) { + if (addr == soc_devices_list[i].addr && + size == soc_devices_list[i].size) + { + return &soc_devices_list[i]; + } + } + return NULL; +} + +#ifdef CONFIG_KERNEL_DMA_ENABLE +/* return the DMA info line based on the DMA controller id and the stream id (starting with 0) */ +struct device_soc_infos *soc_devices_get_dma // FIXME rename + (enum dma_controller id, uint8_t stream) +{ + return &(soc_devices_list[6 + ((id - 1) * 9) + 1 + stream +1]); // FIXME 6 + 1 + 1... = 8 ? +} +#endif + + +void soc_devmap_enable_clock (const struct device_soc_infos *device) +{ + set_reg_bits (device->rcc_enr, device->rcc_enb); + full_memory_barrier(); +} diff --git a/arch/socs/stm32f439/soc-devmap.h b/arch/socs/stm32f439/soc-devmap.h new file mode 100644 index 0000000..b22ee95 --- /dev/null +++ b/arch/socs/stm32f439/soc-devmap.h @@ -0,0 +1,158 @@ +/* \file soc-devmap.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_DEVMAP_H_ +#define SOC_DEVMAP_H_ + +#include "types.h" +#include "perm.h" +#include "soc-rcc.h" +#include "soc-interrupts.h" +#include "soc-dma.h" +#include "regutils.h" + + +/* +** This file defines the valid adress ranges where devices are mapped. +** This allows the kernel to check that device registration requests correct +** mapping. +** +** Of course these informations are SoC specific +** This file may be completed by a bord specific file for board devices +*/ + +/*! +** \brief Structure defining the STM32 device map +** +** This table is based on doc STMicro RM0090 Reference manual memory map +** Only devices that may be registered by userspace are mapped here +** +** See #soc_devices_list +*/ +struct device_soc_infos { + char const *name; /**< Device name, as as string */ + physaddr_t addr; /**< Device MMIO base address */ + volatile uint32_t *rcc_enr; + /**< device's enable register (RCC reg) */ + uint32_t rcc_enb; /**< device's enable bit in RCC reg */ + uint16_t size; /**< Device MMIO mapping size */ + uint8_t mask; /**< subregion mask when needed */ + uint8_t irq; /**< IRQ line, when exist, or 0 */ + bool ro; /**< True if the device must be mapped RO */ + res_perm_t minperm; /**< minimum permission in comparison with the task's permission register */ +}; + +/** +** \var struct device_soc_infos *soc_device_list +** \brief STM32F4 devices map +** +** This structure define all available devices and associated informations. This +** informations are separated in two parts: +** - physical information (IRQ lines, RCC references, physical address and size...) +** - security information (required permissions, usage restriction (RO mapping, etc.) +** +** This structure is used in remplacement of a full device tree for simplicity in small +** embedded systems. +*/ +static struct device_soc_infos soc_devices_list[] = { + { "rng", 0x50060800, r_CORTEX_M_RCC_AHB2ENR, RCC_AHB2ENR_RNGEN, 0x400, 0, 0, false, PERM_RES_DEV_CRYPTO_CFG }, + /* + * Various CRYP device mapping support + */ + /* CRYP-CFG: for AES key injection only. when configuring the CRYP device, no need to handle the CRYP irq (handler is managed by CRYP user */ + { "cryp-cfg", 0x50060000, r_CORTEX_M_RCC_AHB2ENR, RCC_AHB2ENR_CRYPEN, 0x1000, 0, 0, false, PERM_RES_DEV_CRYPTO_CFG }, + /* CRYP-USER: for IV injection and data path only (no key injection) */ + { "cryp-user", 0x50060000, r_CORTEX_M_RCC_AHB2ENR, RCC_AHB2ENR_CRYPEN, 0x100, 0b11100010, CRYP_IRQ, false, PERM_RES_DEV_CRYPTO_USR }, + /* CRYP: for complete autonomous CRYP usage */ + { "cryp", 0x50060000, r_CORTEX_M_RCC_AHB2ENR, RCC_AHB2ENR_CRYPEN, 0x400, 0, CRYP_IRQ, false, PERM_RES_DEV_CRYPTO_FULL }, + + { "usb-otg-fs", 0x50000000, r_CORTEX_M_RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN, 0x4000, 0, OTG_FS_IRQ, false, PERM_RES_DEV_BUSES }, + { "usb-otg-hs", 0x40040000, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_OTGHSEN | RCC_AHB1ENR_OTGHSULPIEN, 0x4000, 0, OTG_HS_IRQ, false, PERM_RES_DEV_BUSES }, + { "sdio", 0x40012c00, r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_SDIOEN, 0x400, 0, SDIO_IRQ, false, PERM_RES_DEV_BUSES }, +#if CONFIG_KERNEL_DMA_ENABLE +/* DMA 1 */ + { "dma1-info", 0x40026000, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN, 0x0, 0, 0, false, PERM_RES_DEV_DMA }, + { "dma1-str0", 0x40026010, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN, 0x0, 0, DMA1_Stream0_IRQ, false, PERM_RES_DEV_DMA }, + { "dma1-str1", 0x40026028, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN, 0x0, 0, DMA1_Stream1_IRQ, false, PERM_RES_DEV_DMA }, + { "dma1-str2", 0x40026040, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN, 0x0, 0, DMA1_Stream2_IRQ, false, PERM_RES_DEV_DMA }, + { "dma1-str3", 0x40026058, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN, 0x0, 0, DMA1_Stream3_IRQ, false, PERM_RES_DEV_DMA }, + { "dma1-str4", 0x40026070, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN, 0x0, 0, DMA1_Stream4_IRQ, false, PERM_RES_DEV_DMA }, + { "dma1-str5", 0x40026088, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN, 0x0, 0, DMA1_Stream5_IRQ, false, PERM_RES_DEV_DMA }, + { "dma1-str6", 0x400260a0, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN, 0x0, 0, DMA1_Stream6_IRQ, false, PERM_RES_DEV_DMA }, + { "dma1-str7", 0x400260b8, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN, 0x0, 0, DMA1_Stream7_IRQ, false, PERM_RES_DEV_DMA }, +/* DMA 2 */ + { "dma2-info", 0x40026400, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA2EN, 0x0, 0, 0, false, PERM_RES_DEV_DMA }, + { "dma2-str0", 0x40026410, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA2EN, 0x0, 0, DMA2_Stream0_IRQ, false, PERM_RES_DEV_DMA }, + { "dma2-str1", 0x40026428, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA2EN, 0x0, 0, DMA2_Stream1_IRQ, false, PERM_RES_DEV_DMA }, + { "dma2-str2", 0x40026440, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA2EN, 0x0, 0, DMA2_Stream2_IRQ, false, PERM_RES_DEV_DMA }, + { "dma2-str3", 0x40026458, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA2EN, 0x0, 0, DMA2_Stream3_IRQ, false, PERM_RES_DEV_DMA }, + { "dma2-str4", 0x40026470, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA2EN, 0x0, 0, DMA2_Stream4_IRQ, false, PERM_RES_DEV_DMA }, + { "dma2-str5", 0x40026488, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA2EN, 0x0, 0, DMA2_Stream5_IRQ, false, PERM_RES_DEV_DMA }, + { "dma2-str6", 0x400264a0, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA2EN, 0x0, 0, DMA2_Stream6_IRQ, false, PERM_RES_DEV_DMA }, + { "dma2-str7", 0x400264b8, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_DMA2EN, 0x0, 0, DMA2_Stream7_IRQ, false, PERM_RES_DEV_DMA }, +#endif + { "eth-mac", 0x40028000, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_ETHMACEN, 0x1400, 0, ETH_IRQ, false, PERM_RES_DEV_BUSES }, + { "crc", 0x40023000, r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_CRCEN, 0x400, 0, 0, false, PERM_RES_DEV_CRYPTO_USR }, + { "spi1", 0x40013000, r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_SPI1EN, 0x400, 0, SPI1_IRQ, false, PERM_RES_DEV_BUSES }, + { "spi2", 0x40003800, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_SPI2EN, 0x400, 0, SPI2_IRQ, false, PERM_RES_DEV_BUSES }, + { "spi3", 0x40003c00, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_SPI3EN, 0x400, 0, SPI3_IRQ, false, PERM_RES_DEV_BUSES }, + { "i2c1", 0x40005400, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_I2C1EN, 0x400, 0, I2C1_EV_IRQ, false, PERM_RES_DEV_BUSES }, + { "i2c2", 0x40005800, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_I2C2EN, 0x400, 0, I2C2_EV_IRQ, false, PERM_RES_DEV_BUSES }, + { "i2c2", 0x40005c00, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_I2C3EN, 0x400, 0, I2C3_EV_IRQ, false, PERM_RES_DEV_BUSES }, + { "can1", 0x40006400, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_CAN1EN, 0x400, 0, 0, false, PERM_RES_DEV_BUSES }, + { "can2", 0x40006800, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_CAN2EN, 0x400, 0, 0, false, PERM_RES_DEV_BUSES }, +/* usarts. As the kernel register its own usart at boot time, any userspace usart registration of the same usart will return EBUSY */ + { "usart1", 0x40011000, r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_USART1EN, 0x400, 0, USART1_IRQ, false, PERM_RES_DEV_BUSES }, + { "usart6", 0x40011400, r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_USART6EN, 0x400, 0, USART6_IRQ, false, PERM_RES_DEV_BUSES }, + { "usart2", 0x40004400, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_USART2EN, 0x400, 0, USART2_IRQ, false, PERM_RES_DEV_BUSES }, + { "usart3", 0x40004800, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_USART3EN, 0x400, 0, USART3_IRQ, false, PERM_RES_DEV_BUSES }, + { "uart4", 0x40004c00, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_UART4EN, 0x400, 0, USART3_IRQ, false, PERM_RES_DEV_BUSES }, + { "uart5", 0x40005000, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_UART5EN, 0x400, 0, USART3_IRQ, false, PERM_RES_DEV_BUSES }, +/* mapping timers as devices */ + { "tim1", 0x40010000, r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_TIM1EN, 0x400, 0, 0, false, PERM_RES_DEV_TIM }, + { "tim8", 0x40010400, r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_TIM8EN, 0x400, 0, 0, false, PERM_RES_DEV_TIM }, + { "tim9", 0x40014000, r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_TIM9EN, 0x400, 0, TIM1_BRK_TIM9_IRQ, false, PERM_RES_DEV_TIM }, + { "tim10", 0x40014400, r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_TIM10EN, 0x400, 0, TIM1_UP_TIM10_IRQ, false, PERM_RES_DEV_TIM }, + { "tim11", 0x40014800, r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_TIM11EN, 0x400, 0, TIM1_TRG_COM_TIM11_IRQ, false, PERM_RES_DEV_TIM }, + { "tim2", 0x40000000, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_TIM2EN, 0x400, 0, TIM2_IRQ, false, PERM_RES_DEV_TIM }, + { "tim3", 0x40000400, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_TIM3EN, 0x400, 0, TIM3_IRQ, false, PERM_RES_DEV_TIM }, + { "tim4", 0x40000800, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_TIM4EN, 0x400, 0, TIM4_IRQ, false, PERM_RES_DEV_TIM }, + { "tim5", 0x40000C00, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_TIM5EN, 0x400, 0, TIM5_IRQ, false, PERM_RES_DEV_TIM }, + { "tim6", 0x40001000, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_TIM6EN, 0x400, 0, TIM6_DAC_IRQ, false, PERM_RES_DEV_TIM }, + { "tim7", 0x40001400, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_TIM7EN, 0x400, 0, TIM7_IRQ, false, PERM_RES_DEV_TIM }, + { "tim12", 0x40001800, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_TIM12EN, 0x400, 0, TIM8_BRK_TIM12_IRQ, false, PERM_RES_DEV_TIM }, + { "tim13", 0x40001C00, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_TIM13EN, 0x400, 0, TIM8_UP_TIM13_IRQ, false, PERM_RES_DEV_TIM }, + { "tim14", 0x40002000, r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_TIM14EN, 0x400, 0, TIM8_TRG_COM_TIM14_IRQ, false, PERM_RES_DEV_TIM }, +}; + +static const uint8_t soc_devices_list_size = + sizeof(soc_devices_list) / sizeof(struct device_soc_infos); + +struct device_soc_infos* soc_devmap_find_device + (physaddr_t addr, uint16_t size); + +void soc_devmap_enable_clock (const struct device_soc_infos *device); + +struct device_soc_infos *soc_devices_get_dma // FIXME rename + (enum dma_controller id, uint8_t stream); + +#endif /*!SOC_DEVMAP_H_ */ diff --git a/arch/socs/stm32f439/soc-dma.c b/arch/socs/stm32f439/soc-dma.c new file mode 100644 index 0000000..34fe7d7 --- /dev/null +++ b/arch/socs/stm32f439/soc-dma.c @@ -0,0 +1,443 @@ +/* \file soc-dma.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "soc-dma.h" +#include "soc-dma_regs.h" +#include "debug.h" + + +// TODO: for memory_to_peripheral and peripheral to memory, out/in addr should +// be controlled by the kernel, the userland should only be able to set an +// offset in a controlled memory area of the device + +#ifdef CONFIG_KERNEL_DMA_ENABLE +void soc_dma_reset_stream(enum dma_controller ctrl, uint8_t stream) +{ + soc_dma_disable(ctrl, stream); + if (stream < 4) { + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CFEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CDMEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CTEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CHTIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CTCIFx_Msk(stream)); + } else { + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CFEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CDMEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CTEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CHTIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CTCIFx_Msk(stream)); + } + + write_reg_value(r_CORTEX_M_DMA_SxCR(ctrl, stream), 0); + while (get_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_EN)) { + continue; + } + write_reg_value(r_CORTEX_M_DMA_SxNDTR(ctrl, stream), 0); + write_reg_value(r_CORTEX_M_DMA_SxPAR(ctrl, stream), 0); + write_reg_value(r_CORTEX_M_DMA_SxM0AR(ctrl, stream), 0); + write_reg_value(r_CORTEX_M_DMA_SxM1AR(ctrl, stream), 0); + write_reg_value(r_CORTEX_M_DMA_SxFCR(ctrl, stream), 0x21); +} + +static void soc_dma_set_addresses(enum dma_controller ctrl, + uint8_t stream, dma_t *param, + uint8_t mask) +{ + if (mask & DMA_RECONF_DIR) { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), param->dir, DMA_SxCR_DIR); + } + + if (param->dir == PERIPHERAL_TO_MEMORY || param->dir == MEMORY_TO_MEMORY) { + if (mask & DMA_RECONF_BUFIN) { + set_reg(r_CORTEX_M_DMA_SxPAR(ctrl, stream), + (uint32_t) param->in_addr, DMA_SxPAR_PAR); + } + if (mask & DMA_RECONF_BUFOUT) { + set_reg(r_CORTEX_M_DMA_SxM0AR(ctrl, stream), + (uint32_t) param->out_addr, DMA_SxM0AR_M0A); + } + } else { + if (mask & DMA_RECONF_BUFIN) { + set_reg(r_CORTEX_M_DMA_SxM0AR(ctrl, stream), + (uint32_t) param->in_addr, DMA_SxM0AR_M0A); + } + if (mask & DMA_RECONF_BUFOUT) { + set_reg(r_CORTEX_M_DMA_SxPAR(ctrl, stream), + (uint32_t) param->out_addr, DMA_SxPAR_PAR); + + } + } +} + +static void soc_dma_set_configuration(enum dma_controller ctrl, + uint8_t stream, + dma_t* param, + dma_config_state_t configstate, + uint8_t mask) +{ + if (configstate == DMA_INITIALIZE) { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), param->channel, DMA_SxCR_CHSEL); + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), param->mem_burst, + DMA_SxCR_MBURST); + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), param->dev_burst, + DMA_SxCR_PBURST); + + clear_reg_bits(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_CT_Msk); + clear_reg_bits(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_DBM_Msk); + } + + if (mask & DMA_RECONF_PRIO) { + if (param->dir == (uint8_t) PERIPHERAL_TO_MEMORY) { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), param->out_prio, DMA_SxCR_PL); + } else { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), param->in_prio, DMA_SxCR_PL); + } + } + if (configstate == DMA_INITIALIZE) { + clear_reg_bits(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_PINCOS_Msk); + + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), param->datasize, + DMA_SxCR_MSIZE); + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), param->datasize, + DMA_SxCR_PSIZE); + if (param->mem_inc) { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), + DMA_SxCR_MINC_ADDR_INCREMENTED, DMA_SxCR_MINC); + } else { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), + DMA_SxCR_MINC_ADDR_FIXED, DMA_SxCR_MINC); + } + if (param->dev_inc) { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), + DMA_SxCR_PINC_ADDR_INCREMENTED, DMA_SxCR_PINC); + } else { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), + DMA_SxCR_PINC_ADDR_FIXED, DMA_SxCR_PINC); + } + clear_reg_bits(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_CIRC_Msk); + if (param->flow_control) { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), + DMA_SxCR_PFCTRL_PERIPH_FLOW_CONTROLLER, DMA_SxCR_PFCTRL); + } else { + set_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), + DMA_SxCR_PFCTRL_DMA_FLOW_CONTROLLER, DMA_SxCR_PFCTRL); + } + } +} + + +uint8_t soc_dma_reconf(enum dma_controller controller, + uint8_t stream, + dma_t *param, + dma_config_state_t configstate, + uint8_t mask) +{ + uint32_t size = 0; + /* + * In Direct mode, item size in the DMA bufsize register is + * calculated using the datasize unit, in FIFO/Circular mode, + * the increment is in bytes, and the size must stay in bytes too + */ + if (param->mode == DMA_DIRECT_MODE) { + switch (param->datasize) { + case DMA_DS_WORD: + size = param->size >> 2; // FIXME / + break; + case DMA_DS_HALFWORD: + size = param->size >> 1; // FIXME / + break; + default: + size = param->size; + } + } else { + size = param->size; + } + + soc_dma_disable(controller, stream); + + soc_dma_set_addresses(controller, stream, param, mask); + soc_dma_set_configuration(controller, stream, param, configstate, mask); + /* interrupts have already been declared by the caller */ + + if (configstate == DMA_INITIALIZE) { + set_reg_bits(r_CORTEX_M_DMA_SxCR(controller, stream), DMA_SxCR_TCIE_Msk + | DMA_SxCR_HTIE_Msk | DMA_SxCR_TEIE_Msk | DMA_SxCR_DMEIE_Msk); + } + if (param->flow_control != DMA_FLOWCTRL_DEV) { // FIXME == DMA_FLOWCTRL_DMA + set_reg(r_CORTEX_M_DMA_SxNDTR(controller, stream), size, DMA_SxNDTR_NDT); + } + if (mask & DMA_RECONF_MODE) { + if (param->mode & DMA_FIFO_MODE) { + /* FIFO mode instead of direct mode */ + set_reg_bits(r_CORTEX_M_DMA_SxFCR(controller, stream), + DMA_SxFCR_FEIE_Msk | DMA_SxFCR_DMDIS_Msk); + set_reg(r_CORTEX_M_DMA_SxFCR(controller, stream), + DMA_SxFCR_FTH_FULL, DMA_SxFCR_FTH); + } else { + clear_reg_bits(r_CORTEX_M_DMA_SxFCR(controller, stream), + DMA_SxFCR_FEIE_Msk); + } + + if (param->mode & DMA_CIRCULAR_MODE) { + if (param->dir == MEMORY_TO_MEMORY || !(param->mode & DMA_FIFO_MODE)) { // FIXME + dbg_log("DMA%x Circular mode forbidden\n", controller); + } else { + set_reg_bits(r_CORTEX_M_DMA_SxCR(controller, stream), + DMA_SxCR_CIRC_Msk); + } + } + /* + * activating IT... is made by userspace. This action depends on when the + * userspace want to be awoken by a DMA event. + * This example make the usespae being awoken in all various cases (same IRQ) + */ + if (param->mode & DMA_DIRECT_MODE) { + set_reg_bits(r_CORTEX_M_DMA_SxCR(controller, stream), DMA_SxCR_TCIE_Msk + | DMA_SxCR_TEIE_Msk | DMA_SxCR_DMEIE_Msk); + } else if (param->mode & DMA_FIFO_MODE) { + set_reg_bits(r_CORTEX_M_DMA_SxCR(controller, stream), DMA_SxCR_TCIE_Msk + | DMA_SxCR_TEIE_Msk); + } else { + set_reg_bits(r_CORTEX_M_DMA_SxCR(controller, stream), DMA_SxCR_TCIE_Msk + | DMA_SxCR_TEIE_Msk); + } + } + + return 0; +} + +uint8_t soc_dma_init(enum dma_controller controller, + uint8_t stream, + dma_t *param) +{ + soc_dma_reset_stream(controller, stream); + soc_dma_reconf(controller, stream, param, DMA_INITIALIZE, 0xff); + + return 0; +} + +/* should be a userspace function */ +void soc_dma_enable(uint8_t controller, uint8_t stream) +{ + DEBUG(DBG_DEBUG, "Enabling DMA Stream %x, controller %x\n", stream, + controller); + set_reg_bits(r_CORTEX_M_DMA_SxCR(controller, stream), DMA_SxCR_EN_Msk); +} + +void soc_dma_disable(uint8_t controller, uint8_t stream) +{ + DEBUG(DBG_DEBUG, "Disabling DMA Stream %x, controller %x\n", stream, + controller); + clear_reg_bits(r_CORTEX_M_DMA_SxCR(controller, stream), DMA_SxCR_EN_Msk); +} + + +void soc_dma_reset(void) +{ + for (enum dma_controller i = DMA1; i <= DMA2; ++i) { + for (uint8_t j = 0; j < DMA_NB_STREAM; ++j) { + soc_dma_reset_stream(i, j); + } + } +} + +#endif + +bool soc_is_dma_irq(uint8_t irq) +{ + bool ret = false; + if (irq >= DMA1_Stream0_IRQ && irq <= DMA1_Stream6_IRQ) { + ret = true; + } + if (irq == DMA1_Stream7_IRQ) { + ret = true; + } + if (irq >= DMA2_Stream0_IRQ && irq <= DMA2_Stream4_IRQ) { + ret = true; + } + if (irq >= DMA2_Stream5_IRQ && irq <= DMA2_Stream7_IRQ) { + ret = true; + } + return ret; +} + +void soc_dma_clean_int(enum dma_controller ctrl, uint8_t stream) +{ + if (stream < 4) { + if (get_reg(r_CORTEX_M_DMA_SxFCR(ctrl, stream), DMA_SxFCR_FEIE) + && get_reg_value(r_CORTEX_M_DMA_LISR(ctrl), + DMA_LISR_FEIFx_Msk(stream), + DMA_LISR_FEIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), + DMA_LIFCR_CFEIFx_Msk(stream)); + } + if (get_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_DMEIE) + && get_reg_value(r_CORTEX_M_DMA_LISR(ctrl), + DMA_LISR_DMEIFx_Msk(stream), + DMA_LISR_DMEIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), + DMA_LIFCR_CDMEIFx_Msk(stream)); + } + if (get_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_TEIE) && + get_reg_value(r_CORTEX_M_DMA_LISR(ctrl), + DMA_LISR_TEIFx_Msk(stream), + DMA_LISR_TEIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), + DMA_LIFCR_CTEIFx_Msk(stream)); + } + if (get_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_HTIE) && + get_reg_value(r_CORTEX_M_DMA_LISR(ctrl), + DMA_LISR_HTIFx_Msk(stream), + DMA_LISR_HTIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), + DMA_LIFCR_CHTIFx_Msk(stream)); + } + if (get_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_TCIE) && + get_reg_value(r_CORTEX_M_DMA_LISR(ctrl), + DMA_LISR_TCIFx_Msk(stream), + DMA_LISR_TCIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), + DMA_LIFCR_CTCIFx_Msk(stream)); + } + } else { + if (get_reg(r_CORTEX_M_DMA_SxFCR(ctrl, stream), DMA_SxFCR_FEIE) + && get_reg_value(r_CORTEX_M_DMA_HISR(ctrl), + DMA_HISR_FEIFx_Msk(stream), + DMA_HISR_FEIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), + DMA_HIFCR_CFEIFx_Msk(stream)); + } + if (get_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_DMEIE) + && get_reg_value(r_CORTEX_M_DMA_HISR(ctrl), + DMA_HISR_DMEIFx_Msk(stream), + DMA_HISR_DMEIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), + DMA_HIFCR_CDMEIFx_Msk(stream)); + } + if (get_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_TEIE) && + get_reg_value(r_CORTEX_M_DMA_HISR(ctrl), + DMA_HISR_TEIFx_Msk(stream), + DMA_HISR_TEIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), + DMA_HIFCR_CTEIFx_Msk(stream)); + } + if (get_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_HTIE) && + get_reg_value(r_CORTEX_M_DMA_HISR(ctrl), + DMA_HISR_HTIFx_Msk(stream), + DMA_HISR_HTIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), + DMA_HIFCR_CHTIFx_Msk(stream)); + } + if (get_reg(r_CORTEX_M_DMA_SxCR(ctrl, stream), DMA_SxCR_TCIE) && + get_reg_value(r_CORTEX_M_DMA_HISR(ctrl), + DMA_HISR_TCIFx_Msk(stream), + DMA_HISR_TCIFx_Pos(stream))) { + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), + DMA_HIFCR_CTCIFx_Msk(stream)); + } + } +} + +uint32_t soc_dma_get_status(enum dma_controller ctrl, uint8_t stream) +{ + uint32_t reg = 0; + + /* + ** TODO: we read the entire register here (4 streams status). A safer way + ** would be to read only the bits corresponding to the current stream, to + ** keep other streams status inaccessible to the current task + ** + ** We then clean the status bits. + */ + if (stream < 4) { + reg = read_reg_value(r_CORTEX_M_DMA_LISR(ctrl)); + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CFEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CDMEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CTEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CHTIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_LIFCR(ctrl), DMA_LIFCR_CTCIFx_Msk(stream)); + } else { + reg = read_reg_value(r_CORTEX_M_DMA_HISR(ctrl)); + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CFEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CDMEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CTEIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CHTIFx_Msk(stream)); + set_reg_bits(r_CORTEX_M_DMA_HIFCR(ctrl), DMA_HIFCR_CTCIFx_Msk(stream)); + } + return reg; +} + +#ifdef CONFIG_KERNEL_UNSAFE_DMA_ENABLE +/* +** When DMA is managed as a general purpose device, the kernel has no +** information about stream or controller. Nevertheless, the DMA status +** registers has to be cleared in Handler mode to avoid IRQ burst +** In that case, the kernel clear the status register to stop the DMA, +** waiting for the ISR to be executed. The status value is given in +** argument of the ISR +*/ + +static const struct { + uint8_t irq; + uint8_t ctrl; + uint8_t stream; +} dma_table[] = { + { + DMA1_Stream0_IRQ, DMA1, 0}, { + DMA1_Stream1_IRQ, DMA1, 1}, { + DMA1_Stream2_IRQ, DMA1, 2}, { + DMA1_Stream3_IRQ, DMA1, 3}, { + DMA1_Stream4_IRQ, DMA1, 4}, { + DMA1_Stream5_IRQ, DMA1, 5}, { + DMA1_Stream6_IRQ, DMA1, 6}, { + DMA1_Stream7_IRQ, DMA1, 7}, { + DMA2_Stream0_IRQ, DMA2, 0}, { + DMA2_Stream1_IRQ, DMA2, 1}, { + DMA2_Stream2_IRQ, DMA2, 2}, { + DMA2_Stream3_IRQ, DMA2, 3}, { + DMA2_Stream4_IRQ, DMA2, 4}, { + DMA2_Stream5_IRQ, DMA2, 5}, { + DMA2_Stream6_IRQ, DMA2, 6}, { + DMA2_Stream7_IRQ, DMA2, 7} +}; + +uint8_t soc_dma_get_controller(uint8_t irq) +{ + for (uint8_t i = 0; i < 16; ++i) { + if (dma_table[i].irq == irq) { + return dma_table[i].ctrl; + } + } + return 0; +} + +uint8_t soc_dma_get_stream(uint8_t irq) +{ + for (uint8_t i = 0; i < 16; ++i) { + if (dma_table[i].irq == irq) { + return dma_table[i].stream; + } + } + return 0; +} + +#endif diff --git a/arch/socs/stm32f439/soc-dma.h b/arch/socs/stm32f439/soc-dma.h new file mode 100644 index 0000000..97ed1d2 --- /dev/null +++ b/arch/socs/stm32f439/soc-dma.h @@ -0,0 +1,89 @@ +/* \file soc-dma.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_DMA_H_ +#define SOC_DMA_H_ + +#include "autoconf.h" +#include "types.h" +#include "exported/dmas.h" +#include "soc-interrupts.h" + +enum dma_controller { + DMA1 = 1, + DMA2 = 2 +}; + + +typedef enum { + DMA_INITIALIZE, + DMA_RECONFIGURE +} dma_config_state_t; + + + +#ifdef CONFIG_KERNEL_DMA_ENABLE +/* +** Only for secure DMA +*/ + +#define DMA_NB_CONTROLER 2 +#define DMA_NB_STREAM 8 + +void soc_dma_reset(void); + +void soc_dma_reset_stream(enum dma_controller ctrl, uint8_t stream); + +uint8_t soc_dma_init(enum dma_controller controller, + uint8_t stream, + dma_t *param); + +uint8_t soc_dma_reconf(enum dma_controller controller, + uint8_t stream, + dma_t *param, + dma_config_state_t configstate, + uint8_t mask); + +void soc_dma_enable(uint8_t controller, uint8_t stream); + +void soc_dma_disable(uint8_t controller, uint8_t stream); +#endif +/* +** Bellow functions are for all DMA cases (Secure & Unsecure) +*/ + +/* Say true if the current irq is a DMA interrupt */ +bool soc_is_dma_irq(uint8_t irq); + +void soc_dma_clean_int(enum dma_controller ctrl, uint8_t stream); + +uint32_t soc_dma_get_status(enum dma_controller ctrl, uint8_t stream); + +#ifdef CONFIG_KERNEL_UNSAFE_DMA_ENABLE + +uint8_t soc_dma_get_controller(uint8_t irq); + +uint8_t soc_dma_get_stream(uint8_t irq); + +#endif + +#endif /*! SOC_DMA_H_ */ diff --git a/arch/socs/stm32f439/soc-dma_regs.h b/arch/socs/stm32f439/soc-dma_regs.h new file mode 100644 index 0000000..e0b299e --- /dev/null +++ b/arch/socs/stm32f439/soc-dma_regs.h @@ -0,0 +1,208 @@ +/* \file soc-dma-regs.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_DMA_REGS_H +#define SOC_DMA_REGS_H + +/* TODO: DMA1 + DMA2 */ +#define DMA1_BASE 0x40026000 +#define DMA2_BASE 0x40026400 +#define DMA_BASE(n) (n == 1 ? DMA1_BASE : DMA2_BASE) + +#define r_CORTEX_M_DMA_LISR(ctrl) REG_ADDR(DMA_BASE(ctrl) + 0x00) +#define r_CORTEX_M_DMA_HISR(ctrl) REG_ADDR(DMA_BASE(ctrl) + 0x04) +#define r_CORTEX_M_DMA_LIFCR(ctrl) REG_ADDR(DMA_BASE(ctrl) + 0x08) +#define r_CORTEX_M_DMA_HIFCR(ctrl) REG_ADDR(DMA_BASE(ctrl) + 0x0c) +#define r_CORTEX_M_DMA_SxCR(ctrl, stream) REG_ADDR(DMA_BASE(ctrl) + 0x10 + (stream * 0x18)) +#define r_CORTEX_M_DMA_SxNDTR(ctrl, stream) REG_ADDR(DMA_BASE(ctrl) + 0x14 + (stream * 0x18)) +#define r_CORTEX_M_DMA_SxPAR(ctrl, stream) REG_ADDR(DMA_BASE(ctrl) + 0x18 + (stream * 0x18)) +#define r_CORTEX_M_DMA_SxM0AR(ctrl, stream) REG_ADDR(DMA_BASE(ctrl) + 0x1c + (stream * 0x18)) +#define r_CORTEX_M_DMA_SxM1AR(ctrl, stream) REG_ADDR(DMA_BASE(ctrl) + 0x20 + (stream * 0x18)) +/* Note: in the reference manual rev 12, the section 10.5.10 says that the + * offset of DMA_SxFCR register is 0x24 + 0x24 * stream. However, this is an + * error ! The offset is 0x24 + 0x18 * stream. This is verified in section + * 10.5.11 of the manual. + */ +#define r_CORTEX_M_DMA_SxFCR(ctrl, stream) REG_ADDR(DMA_BASE(ctrl) + 0x24 + (stream * 0x18)) + +/* DMA low interrupt status register */ +#define DMA_LISR_stream_base(stream) (stream == 0 ? 0 : (stream == 1 ? 6 : (stream == 2 ? 16 : 22))) + +#define DMA_LISR_FEIFx_Pos(stream) (DMA_LISR_stream_base(stream)) +#define DMA_LISR_FEIFx_Msk(stream) ((uint32_t)1 << DMA_LISR_FEIFx_Pos(stream)) +#define DMA_LISR_DMEIFx_Pos(stream) (DMA_LISR_stream_base(stream) + 2) +#define DMA_LISR_DMEIFx_Msk(stream) ((uint32_t)1 << DMA_LISR_DMEIFx_Pos(stream)) +#define DMA_LISR_TEIFx_Pos(stream) (DMA_LISR_stream_base(stream) + 3) +#define DMA_LISR_TEIFx_Msk(stream) ((uint32_t)1 << DMA_LISR_TEIFx_Pos(stream)) +#define DMA_LISR_HTIFx_Pos(stream) (DMA_LISR_stream_base(stream) + 4) +#define DMA_LISR_HTIFx_Msk(stream) ((uint32_t)1 << DMA_LISR_HTIFx_Pos(stream)) +#define DMA_LISR_TCIFx_Pos(stream) (DMA_LISR_stream_base(stream) + 5) +#define DMA_LISR_TCIFx_Msk(stream) ((uint32_t)1 << DMA_LISR_TCIFx_Pos(stream)) + +/* DMA high interrupt status register */ +#define DMA_HISR_stream_base(stream) (stream == 4 ? 0 : (stream == 5 ? 6 : (stream == 6 ? 16 : 22))) + +#define DMA_HISR_FEIFx_Pos(stream) (DMA_HISR_stream_base(stream)) +#define DMA_HISR_FEIFx_Msk(stream) ((uint32_t)1 << DMA_HISR_FEIFx_Pos(stream)) +#define DMA_HISR_DMEIFx_Pos(stream) (DMA_HISR_stream_base(stream) + 2) +#define DMA_HISR_DMEIFx_Msk(stream) ((uint32_t)1 << DMA_HISR_DMEIFx_Pos(stream)) +#define DMA_HISR_TEIFx_Pos(stream) (DMA_HISR_stream_base(stream) + 3) +#define DMA_HISR_TEIFx_Msk(stream) ((uint32_t)1 << DMA_HISR_TEIFx_Pos(stream)) +#define DMA_HISR_HTIFx_Pos(stream) (DMA_HISR_stream_base(stream) + 4) +#define DMA_HISR_HTIFx_Msk(stream) ((uint32_t)1 << DMA_HISR_HTIFx_Pos(stream)) +#define DMA_HISR_TCIFx_Pos(stream) (DMA_HISR_stream_base(stream) + 5) +#define DMA_HISR_TCIFx_Msk(stream) ((uint32_t)1 << DMA_HISR_TCIFx_Pos(stream)) + +/* DMA low interrupt flag clear register */ +#define DMA_LIFCR_stream_base(stream) (stream == 0 ? 0 : (stream == 1 ? 6 : (stream == 2 ? 16 : 22))) + +#define DMA_LIFCR_CFEIFx_Pos(stream) (DMA_LIFCR_stream_base(stream)) +#define DMA_LIFCR_CFEIFx_Msk(stream) ((uint32_t)1 << DMA_LIFCR_CFEIFx_Pos(stream)) +#define DMA_LIFCR_CDMEIFx_Pos(stream) (DMA_LIFCR_stream_base(stream) + 2) +#define DMA_LIFCR_CDMEIFx_Msk(stream) ((uint32_t)1 << DMA_LIFCR_CDMEIFx_Pos(stream)) +#define DMA_LIFCR_CTEIFx_Pos(stream) (DMA_LIFCR_stream_base(stream) + 3) +#define DMA_LIFCR_CTEIFx_Msk(stream) ((uint32_t)1 << DMA_LIFCR_CTEIFx_Pos(stream)) +#define DMA_LIFCR_CHTIFx_Pos(stream) (DMA_LIFCR_stream_base(stream) + 4) +#define DMA_LIFCR_CHTIFx_Msk(stream) ((uint32_t)1 << DMA_LIFCR_CHTIFx_Pos(stream)) +#define DMA_LIFCR_CTCIFx_Pos(stream) (DMA_LIFCR_stream_base(stream) + 5) +#define DMA_LIFCR_CTCIFx_Msk(stream) ((uint32_t)1 << DMA_LIFCR_CTCIFx_Pos(stream)) + +/* DMA high interrupt flag clear register */ +#define DMA_HIFCR_stream_base(stream) (stream == 4 ? 0 : (stream == 5 ? 6 : (stream == 6 ? 16 : 22))) + +#define DMA_HIFCR_CFEIFx_Pos(stream) (DMA_HIFCR_stream_base(stream)) +#define DMA_HIFCR_CFEIFx_Msk(stream) ((uint32_t)1 << DMA_HIFCR_CFEIFx_Pos(stream)) +#define DMA_HIFCR_CDMEIFx_Pos(stream) (DMA_HIFCR_stream_base(stream) + 2) +#define DMA_HIFCR_CDMEIFx_Msk(stream) ((uint32_t)1 << DMA_HIFCR_CDMEIFx_Pos(stream)) +#define DMA_HIFCR_CTEIFx_Pos(stream) (DMA_HIFCR_stream_base(stream) + 3) +#define DMA_HIFCR_CTEIFx_Msk(stream) ((uint32_t)1 << DMA_HIFCR_CTEIFx_Pos(stream)) +#define DMA_HIFCR_CHTIFx_Pos(stream) (DMA_HIFCR_stream_base(stream) + 4) +#define DMA_HIFCR_CHTIFx_Msk(stream) ((uint32_t)1 << DMA_HIFCR_CHTIFx_Pos(stream)) +#define DMA_HIFCR_CTCIFx_Pos(stream) (DMA_HIFCR_stream_base(stream) + 5) +#define DMA_HIFCR_CTCIFx_Msk(stream) ((uint32_t)1 << DMA_HIFCR_CTCIFx_Pos(stream)) + +/* DMA stream x configuration register */ +#define DMA_SxCR_EN_Pos 0 +#define DMA_SxCR_EN_Msk ((uint32_t)1 << DMA_SxCR_EN_Pos) +#define DMA_SxCR_DMEIE_Pos 1 +#define DMA_SxCR_DMEIE_Msk ((uint32_t)1 << DMA_SxCR_DMEIE_Pos) +#define DMA_SxCR_TEIE_Pos 2 +#define DMA_SxCR_TEIE_Msk ((uint32_t)1 << DMA_SxCR_TEIE_Pos) +#define DMA_SxCR_HTIE_Pos 3 +#define DMA_SxCR_HTIE_Msk ((uint32_t)1 << DMA_SxCR_HTIE_Pos) +#define DMA_SxCR_TCIE_Pos 4 +#define DMA_SxCR_TCIE_Msk ((uint32_t)1 << DMA_SxCR_TCIE_Pos) +#define DMA_SxCR_PFCTRL_Pos 5 +#define DMA_SxCR_PFCTRL_Msk ((uint32_t)1 << DMA_SxCR_PFCTRL_Pos) +# define DMA_SxCR_PFCTRL_DMA_FLOW_CONTROLLER 0 +# define DMA_SxCR_PFCTRL_PERIPH_FLOW_CONTROLLER 1 +#define DMA_SxCR_DIR_Pos 6 +#define DMA_SxCR_DIR_Msk ((uint32_t)3 << DMA_SxCR_DIR_Pos) +# define DMA_SxCR_DIR_PERIPH_TO_MEM 0 +# define DMA_SxCR_DIR_MEM_TO_PERIPH 1 +# define DMA_SxCR_DIR_MEM_TO_MEM 2 +#define DMA_SxCR_CIRC_Pos 8 +#define DMA_SxCR_CIRC_Msk ((uint32_t)1 << DMA_SxCR_CIRC_Pos) +#define DMA_SxCR_PINC_Pos 9 +#define DMA_SxCR_PINC_Msk ((uint32_t)1 << DMA_SxCR_PINC_Pos) +# define DMA_SxCR_PINC_ADDR_FIXED 0 +# define DMA_SxCR_PINC_ADDR_INCREMENTED 1 +#define DMA_SxCR_MINC_Pos 10 +#define DMA_SxCR_MINC_Msk ((uint32_t)1 << DMA_SxCR_MINC_Pos) +# define DMA_SxCR_MINC_ADDR_FIXED 0 +# define DMA_SxCR_MINC_ADDR_INCREMENTED 1 +#define DMA_SxCR_PSIZE_Pos 11 +#define DMA_SxCR_PSIZE_Msk ((uint32_t)3 << DMA_SxCR_PSIZE_Pos) +# define DMA_SxCR_PSIZE_BYTE 0 +# define DMA_SxCR_PSIZE_HALF_WORD 1 +# define DMA_SxCR_PSIZE_WORD 2 +#define DMA_SxCR_MSIZE_Pos 13 +#define DMA_SxCR_MSIZE_Msk ((uint32_t)3 << DMA_SxCR_MSIZE_Pos) +# define DMA_SxCR_MSIZE_BYTE 0 +# define DMA_SxCR_MSIZE_HALF_WORD 1 +# define DMA_SxCR_MSIZE_WORD 2 +#define DMA_SxCR_PINCOS_Pos 15 +#define DMA_SxCR_PINCOS_Msk ((uint32_t)1 << DMA_SxCR_PINCOS_Pos) +# define DMA_SxCR_PINCOS_LINKED_PSIZE 0 +# define DMA_SxCR_PINCOS_FIXED_4 1 +#define DMA_SxCR_PL_Pos 16 +#define DMA_SxCR_PL_Msk ((uint32_t)3 << DMA_SxCR_PL_Pos) +# define DMA_SxCR_PL_LOW 0 +# define DMA_SxCR_PL_MEDIUM 1 +# define DMA_SxCR_PL_HIGH 2 +# define DMA_SxCR_PL_VERY_HIGH 3 +#define DMA_SxCR_DBM_Pos 18 +#define DMA_SxCR_DBM_Msk ((uint32_t)1 << DMA_SxCR_DBM_Pos) +#define DMA_SxCR_CT_Pos 19 +#define DMA_SxCR_CT_Msk ((uint32_t)1 << DMA_SxCR_CT_Pos) +#define DMA_SxCR_PBURST_Pos 21 +#define DMA_SxCR_PBURST_Msk ((uint32_t)3 << DMA_SxCR_PBURST_Pos) +# define DMA_SxCR_PBURST_SINGLE 0 +# define DMA_SxCR_PBURST_INCR4 1 +# define DMA_SxCR_PBURST_INCR8 2 +# define DMA_SxCR_PBURST_INCR16 3 +#define DMA_SxCR_MBURST_Pos 23 +#define DMA_SxCR_MBURST_Msk ((uint32_t)3 << DMA_SxCR_MBURST_Pos) +# define DMA_SxCR_MBURST_SINGLE 0 +# define DMA_SxCR_MBURST_INCR4 1 +# define DMA_SxCR_MBURST_INCR8 2 +# define DMA_SxCR_MBURST_INCR16 3 +#define DMA_SxCR_CHSEL_Pos 25 +#define DMA_SxCR_CHSEL_Msk ((uint32_t)7 << DMA_SxCR_CHSEL_Pos) + +/* DMA stream x number of data register */ +#define DMA_SxNDTR_NDT_Pos 0 +#define DMA_SxNDTR_NDT_Msk ((uint32_t)0xffff << DMA_SxNDTR_NDT_Pos) + +/* DMA stream x peripheral adderss register */ +#define DMA_SxPAR_PAR_Pos 0 +#define DMA_SxPAR_PAR_Msk ((uint32_t)0xffffffff << DMA_SxPAR_PAR_Pos) + +/* DMA stream x memory 0 address register */ +#define DMA_SxM0AR_M0A_Pos 0 +#define DMA_SxM0AR_M0A_Msk ((uint32_t)0xffffffff << DMA_SxM0AR_M0A_Pos) + +/* DMA stream x memory 1 address register */ +#define DMA_SxM1AR_M1A_Pos 0 +#define DMA_SxM1AR_M1A_Msk ((uint32_t)0xffffffff << DMA_SxM1A_M1AR_Pos) + +/* DMA stream x FIFO control register */ +#define DMA_SxFCR_FTH_Pos 0 +#define DMA_SxFCR_FTH_Msk ((uint32_t)3 << DMA_SxFCR_FTH_Pos) +# define DMA_SxFCR_FTH_1DIV4_FULL 0 +# define DMA_SxFCR_FTH_1DIV2_FULL 1 +# define DMA_SxFCR_FTH_3DIV4_FULL 2 +# define DMA_SxFCR_FTH_FULL 3 +#define DMA_SxFCR_DMDIS_Pos 2 +#define DMA_SxFCR_DMDIS_Msk ((uint32_t)1 << DMA_SxFCR_DMDIS_Pos) +#define DMA_SxFCR_FS_Pos 3 +#define DMA_SxFCR_FS_Msk ((uint32_t)7 << DMA_SxFCR_FS_Pos) +# define DMA_SxFCR_FS_LESS_1DIV4 0 +# define DMA_SxFCR_FS_LESS_1DIV2 1 +# define DMA_SxFCR_FS_LESS_3DIV4 2 +# define DMA_SxFCR_FS_LESS_FULL 3 +# define DMA_SxFCR_FS_EMPTY 4 +# define DMA_SxFCR_FS_FULL 5 +#define DMA_SxFCR_FEIE_Pos 7 +#define DMA_SxFCR_FEIE_Msk ((uint32_t)1 << DMA_SxFCR_FEIE_Pos) + +#endif /* !SOC_DMA_REGS_H */ diff --git a/arch/socs/stm32f439/soc-dwt.c b/arch/socs/stm32f439/soc-dwt.c new file mode 100644 index 0000000..def0421 --- /dev/null +++ b/arch/socs/stm32f439/soc-dwt.c @@ -0,0 +1,83 @@ +/* \file soc-dwt.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "soc-dwt.h" + +static uint32_t last_dwt = 0; + +static volatile uint64_t cyccnt_loop = 0; + +static volatile physaddr_t DWT_CONTROL = (physaddr_t) 0xE0001000; +static volatile physaddr_t SCB_DEMCR = (physaddr_t) 0xE000EDFC; +static volatile physaddr_t LAR = (physaddr_t) 0xE0001FB0; + +void soc_dwt_reset_timer(void) +{ + *(volatile uint32_t *)SCB_DEMCR = *(uint32_t *) SCB_DEMCR | 0x01000000; + *(volatile uint32_t *)LAR = 0xC5ACCE55; + *(volatile uint32_t *)DWT_CYCCNT = 0; // reset the counter + *(volatile uint32_t *)DWT_CONTROL = 0; +} + +void soc_dwt_start_timer(void) +{ + *(volatile uint32_t *)DWT_CONTROL = *(uint32_t *) DWT_CONTROL | 1; // enable the counter +} + +void soc_dwt_stop_timer(void) +{ + *(volatile uint32_t *)DWT_CONTROL = *(uint32_t *) DWT_CONTROL | 0; // disable the counter +} + +uint32_t soc_dwt_getcycles(void) +{ + return *(uint32_t *) DWT_CYCCNT; +} + +uint64_t soc_dwt_getcycles_64(void) +{ + uint64_t val = *(uint32_t *) DWT_CYCCNT; + val += cyccnt_loop << 32; + return val; +} + + +void soc_dwt_ovf_manage(void) +{ + uint32_t dwt = soc_dwt_getcycles(); + + /* + * DWT cycle count overflow: we increment cyccnt_loop counter. + */ + if (dwt < last_dwt) { + cyccnt_loop++; + } + + last_dwt = dwt; +} + +void soc_dwt_init(void) +{ + soc_dwt_reset_timer(); + soc_dwt_start_timer(); +} diff --git a/arch/socs/stm32f439/soc-dwt.h b/arch/socs/stm32f439/soc-dwt.h new file mode 100644 index 0000000..07005e6 --- /dev/null +++ b/arch/socs/stm32f439/soc-dwt.h @@ -0,0 +1,45 @@ +/* \file soc-dwt.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_DWT_H +#define SOC_DWT_H + +#include "types.h" + + +static volatile physaddr_t DWT_CYCCNT = (physaddr_t) 0xE0001004; + +void soc_dwt_init(void); + +void soc_dwt_reset_timer(void); + +void soc_dwt_start_timer(void); + +void soc_dwt_stop_timer(void); + +uint32_t soc_dwt_getcycles(void); + +uint64_t soc_dwt_getcycles_64(void); + +void soc_dwt_ovf_manage(void); + +#endif /*!SOC_DWT_H */ diff --git a/arch/socs/stm32f439/soc-exti.c b/arch/socs/stm32f439/soc-exti.c new file mode 100644 index 0000000..cfaf83a --- /dev/null +++ b/arch/socs/stm32f439/soc-exti.c @@ -0,0 +1,369 @@ +/* \file soc-exti.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "soc-exti.h" +#include "soc-nvic.h" +#include "soc-interrupts.h" +#include "soc-rcc.h" +#include "exported/devices.h" + +#define EXTI REG_ADDR(EXTI_BASE) +#define EXTI_IMR REG_ADDR(EXTI_BASE + 0x00) /*!< Interrupt mask register */ +#define EXTI_EMR REG_ADDR(EXTI_BASE + 0x04) /*!< Event mask register */ +#define EXTI_RTSR REG_ADDR(EXTI_BASE + 0x08) /*!< Rising trigger selection register */ +#define EXTI_FTSR REG_ADDR(EXTI_BASE + 0x0C) /*!< Falling trigger selection register */ +#define EXTI_SWIER REG_ADDR(EXTI_BASE + 0x10) /*!< Software interrupt event register */ +#define EXTI_PR REG_ADDR(EXTI_BASE + 0x14) /*!< Pending register */ + +#define EXTI_IMR_DEFAUT ((uint32_t)0x00000000) +#define EXTI_EMR_DEFAUT ((uint32_t)0x00000000) +#define EXTI_RTSR_DEFAUT ((uint32_t)0x00000000) +#define EXTI_FTSR_DEFAUT ((uint32_t)0x00000000) +#define EXTI_SWIER_DEFAUT ((uint32_t)0x00000000) + +/* + * EXTI allows one and only one EXTI line per pin, whatever the port is. + * There is 16 EXTI lines for 16 pin (0 => 15). + * + * SYSCFG_CR1 manages config for pin 0 => 3 + * SYSCFG_CR2 manages config for pin 4 => 7 + * SYSCFG_CR3 manages config for pin 8 => 11 + * SYSCFG_CR4 manages config for pin 12 => 15 + * + * This function returns the corresponding EXTI register + */ +static uint32_t *soc_exti_get_SYSCFG_EXTICR(uint8_t pin) +{ + switch (pin) { + case 0: + case 1: + case 2: + case 3: + return SYSCFG_EXTICR1; + break; + case 4: + case 5: + case 6: + case 7: + return SYSCFG_EXTICR2; + break; + case 8: + case 9: + case 10: + case 11: + return SYSCFG_EXTICR3; + break; + case 12: + case 13: + case 14: + case 15: + return SYSCFG_EXTICR4; + break; + default: + return 0; + } + +} + +/* + * EXTI allows one and only one EXTI line per pin, whatever the port is. + * There is 16 EXTI lines for 16 pin (0 => 15). + * + * SYSCFG_CR1 manages config for pin 0 => 3 + * SYSCFG_CR2 manages config for pin 4 => 7 + * SYSCFG_CR3 manages config for pin 8 => 11 + * SYSCFG_CR4 manages config for pin 12 => 15 + * + * This function return the register field position + */ +static uint8_t soc_exti_get_pos(uint8_t pin) +{ + switch (pin) { + case 0: + case 4: + case 8: + case 12: + return 0; + break; + case 1: + case 5: + case 9: + case 13: + return 4; + break; + case 2: + case 6: + case 10: + case 14: + return 8; + break; + case 3: + case 7: + case 11: + case 15: + return 12; + break; + default: + return 0; + } +} + + + +/* + * Return the bit (or the bitfield) of the pending IT lines of the + * EXTI for the corresponding IRQ + */ +uint32_t soc_exti_get_pending_lines(uint8_t irq) +{ + switch (irq) { + case EXTI0_IRQ: + return get_reg_value(EXTI_PR, 0x1, 0); + break; + case EXTI1_IRQ: + return get_reg_value(EXTI_PR, 0x1 << 1, 1); + break; + case EXTI2_IRQ: + return get_reg_value(EXTI_PR, 0x1 << 2, 2); + break; + case EXTI3_IRQ: + return get_reg_value(EXTI_PR, 0x1 << 3, 3); + break; + case EXTI4_IRQ: + return get_reg_value(EXTI_PR, 0x1 << 4, 4); + break; + case EXTI9_5_IRQ: + return get_reg_value(EXTI_PR, 0x1f << 5, 5); + break; + case EXTI15_10_IRQ: + return get_reg_value(EXTI_PR, 0x3f << 10, 10); + break; + default: + return 0; + } +} + +bool soc_exti_is_line_pending (uint8_t line) +{ + if (get_reg_value(EXTI_PR, 0x1 << line, line) > 0) { + return true; + } else { + return false; + } +} + +/* + * From the pin number, return the corresponding EXTI line configured GPIO + * port. + * CAUTION: this function doesn't check that the EXTI line has been previously + * configured + */ +uint8_t soc_exti_get_syscfg_exticr_port(uint8_t pin) +{ + uint32_t *regaddr = NULL; + uint8_t pos = 0; + + regaddr = soc_exti_get_SYSCFG_EXTICR(pin); + pos = soc_exti_get_pos(pin); + + if (regaddr) { + return get_reg_value(regaddr, 0xf << pos, pos); + } + return 0xF; +} + +/* + * Clean EXTI line pending bit + */ +void soc_exti_clear_pending(uint8_t pin) +{ + set_reg_bits(EXTI_PR, (0x1 << pin)); +} + +/* + * Configure an EXTI line for a given GPIO + * if the EXTI line for this pin is already set, return 1, otherwhise + * set it and return 0. + * This function does not enable the corresponding NVIC line neither the + * EXTI IMR bit (this is done using soc_exti_enable() function) + * + */ +uint8_t soc_exti_config(dev_gpio_info_t *gpio) +{ + volatile uint32_t *reg = 0; + uint8_t pos = 0; + uint8_t field = 0; + + /**************************************************** + * Initial input checks + ***************************************************/ + + /* If EXTI mask not set, just return */ + if (!(gpio->mask & GPIO_MASK_SET_EXTI)) { + return 0; + } + + /* Mask set but no EXTI use, just return */ + if (gpio->exti_trigger == GPIO_EXTI_TRIGGER_NONE) { + return 0; + } + + /* If EXTI line is not free, return with an error */ + if (!soc_exti_is_free(gpio->kref)) { + return 2; + } + + /**************************************************** + * Effective configuration + ***************************************************/ + + /* Get EXTICRx register addr */ + reg = soc_exti_get_SYSCFG_EXTICR(gpio->kref.pin); + + /* Invalid register ! input pin value incorrect */ + if (!reg) { + return 1; + } + + /* Get EXTICRx field position in register */ + pos = soc_exti_get_pos(gpio->kref.pin); + + /* + * Switching on GPIO port, to generate the field value for EXTICRx register. + * In the datasheet (STM-RM0090, it seems that port num (starting with 0) + * == field value. See STM-RM0090 §9.3.3. + * + * i.e. port 0 (A) -> field = 0, port 1 (B) -> field = 0x1, etc. + */ + field = gpio->kref.port; + set_reg_bits(reg, field << pos); + + /* + * Configure Rising Trigger for current GPIO (if needed) + */ + if (gpio->exti_trigger == GPIO_EXTI_TRIGGER_RISE || + gpio->exti_trigger == GPIO_EXTI_TRIGGER_BOTH) + { + set_reg_bits(EXTI_RTSR, 0x1 << gpio->kref.pin); + } + + /* + * Configure Falling Trigger for current GPIO (if needed) + */ + if (gpio->exti_trigger == GPIO_EXTI_TRIGGER_FALL || + gpio->exti_trigger == GPIO_EXTI_TRIGGER_BOTH) + { + set_reg_bits(EXTI_FTSR, 0x1 << gpio->kref.pin); + } + + return 0; +} + +/** + * return true if the EXTI line associated to the GPIO pin is not + * already set + */ +bool soc_exti_is_free(gpioref_t kref) +{ + uint32_t exti_line_im = get_reg_value(EXTI_IMR, 0x1 << kref.pin, kref.pin); + if (exti_line_im == 1) { + /** + * The Interrupt Mask for this EXTI line is set to 1, this means that + * it as already been set previously. + * This line is busy and can't be overridden. + */ + return false; + } + return true; +} + +/* + * Disable the EXTI line. This only clear the IMR EXTI register bit (NVIC + * stays untouched as some EXTI lines are shared in a signe IRQ + */ +void soc_exti_disable(gpioref_t kref) +{ + /* + * First, unable the Interrupt Mask Register for this line + */ + clear_reg_bits(EXTI_IMR, 0x1 << kref.pin); +} + +/* + * Enable the EXTI line. This means: + * 1) Activate the EXTI_IMR bit of the corresponding pin + * 2) Enable the corresponding IRQ line in the NVIC(may be already done for + * multiplexed EXTI IRQs) + */ +uint8_t soc_exti_enable(gpioref_t kref) +{ + /* + * First, unable the Interrupt Mask Register for this line + */ + set_reg_bits(EXTI_IMR, 0x1 << kref.pin); + + /* + * Then enable the corresponding EXTI NVIC line + */ + switch (kref.pin) { + case 0: + NVIC_EnableIRQ(EXTI0_IRQ - 0x10); + break; + case 1: + NVIC_EnableIRQ(EXTI1_IRQ - 0x10); + break; + case 2: + NVIC_EnableIRQ(EXTI2_IRQ - 0x10); + break; + case 3: + NVIC_EnableIRQ(EXTI3_IRQ - 0x10); + break; + case 4: + NVIC_EnableIRQ(EXTI4_IRQ - 0x10); + break; + case 5: + case 6: + case 7: + case 8: + case 9: + NVIC_EnableIRQ(EXTI9_5_IRQ - 0x10); + break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + NVIC_EnableIRQ(EXTI15_10_IRQ - 0x10); + break; + default: + break; /* Should never happend with 0xf mask */ + } + return 0; +} + + +void soc_exti_init(void) +{ + /* Enable the Syscfg, needed by EXTI */ + set_reg_bits(r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_SYSCFGEN); +} diff --git a/arch/socs/stm32f439/soc-exti.h b/arch/socs/stm32f439/soc-exti.h new file mode 100644 index 0000000..c3a90a6 --- /dev/null +++ b/arch/socs/stm32f439/soc-exti.h @@ -0,0 +1,89 @@ +/* \file soc-exti.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SOC_EXTI_H +#define SOC_EXTI_H + +#include "soc-core.h" +#include "soc-syscfg.h" +#include "exported/gpio.h" + +/* + * Return the bit (or the bitfield) of the pending IT lines of the + * EXTI for the corresponding IRQ + */ +uint32_t soc_exti_get_pending_lines(uint8_t irq); + +/* Return true if there's an interrupt pending on the line */ +bool soc_exti_is_line_pending (uint8_t line); + +/* + * From the pin number, return the corresponding EXTI line configured GPIO + * port that has been configured. + * CAUTION: this function doesn't check that the EXTI line has been previously + * configured + */ +uint8_t soc_exti_get_syscfg_exticr_port(uint8_t pin); + +/* + * Configure an EXTI line for a given GPIO + * if the EXTI line for this pin is already set, return 1, otherwhise + * set it and return 0. + * This function does not enable the corresponding NVIC line neither the + * EXTI IMR bit (this is done using soc_exti_enable() function) + * + */ +uint8_t soc_exti_config(dev_gpio_info_t *gpio); + +/** + * return true if the EXTI line associated to the GPIO pin is not + * already set + */ +bool soc_exti_is_free(gpioref_t kref); + +/* + * Enable the EXTI line. This means: + * 1) Activate the EXTI_IMR bit of the corresponding pin + * 2) Enable the corresponding IRQ line in the NVIC(may be already done for + * multiplexed EXTI IRQs) + */ +uint8_t soc_exti_enable(gpioref_t kref); + +/* + * Disable the EXTI line. This only clear the IMR EXTI register bit (NVIC + * stays untouched as some EXTI lines are shared in a signe IRQ + */ +void soc_exti_disable(gpioref_t kref); + +/* + * Clean EXTI line pending bit + */ +void soc_exti_clear_pending(uint8_t pin); + + +/* + * Initialize EXTI, enable APB2 Syscfg RCC clock + */ +void soc_exti_init(void); + +#endif /*!SOC_EXTI_H */ diff --git a/arch/socs/stm32f439/soc-flash.h b/arch/socs/stm32f439/soc-flash.h new file mode 100644 index 0000000..9cdb27f --- /dev/null +++ b/arch/socs/stm32f439/soc-flash.h @@ -0,0 +1,282 @@ +/* \file soc-flash.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_FLASH_H +#define SOC_FLASH_H + +#include "soc-core.h" + +#define r_CORTEX_M_FLASH REG_ADDR(AHB1PERIPH_BASE + (uint32_t)0x3C00) + +#define r_CORTEX_M_FLASH_ACR (r_CORTEX_M_FLASH + (uint32_t)0x00) /* FLASH access control register */ +#define r_CORTEX_M_FLASH_KEYR (r_CORTEX_M_FLASH + (uint32_t)0x01) /* FLASH key register 1 */ +#define r_CORTEX_M_FLASH_OPTKEYR (r_CORTEX_M_FLASH + (uint32_t)0x02) /* FLASH option key register */ +#define r_CORTEX_M_FLASH_SR (r_CORTEX_M_FLASH + (uint32_t)0x03) /* FLASH status register */ +#define r_CORTEX_M_FLASH_CR (r_CORTEX_M_FLASH + (uint32_t)0x04) /* FLASH control register */ +#define r_CORTEX_M_FLASH_OPTCR (r_CORTEX_M_FLASH + (uint32_t)0x05) /* FLASH option control register */ +#ifdef STM32F429 /* FLASH option control register 1 (only on f42xxx/43xxx) */ +#define r_CORTEX_M_FLASH_OPTCR1 (r_CORTEX_M_FLASH + (uint32_t)0x06) +#endif + +/******************* FLASH_ACR register *****************/ +#define FLASH_ACR_LATENCY_Pos 0 +#define FLASH_ACR_LATENCY_Msk ((uint32_t)7 << FLASH_ACR_LATENCY_Pos) +#define FLASH_ACR_PRFTEN_Pos 8 +#define FLASH_ACR_PRFTEN_Msk ((uint32_t)1 << FLASH_ACR_PRFTEN_Pos) +#define FLASH_ACR_ICEN_Pos 9 +#define FLASH_ACR_ICEN_Msk ((uint32_t)1 << FLASH_ACR_ICEN_Pos) +#define FLASH_ACR_DCEN_Pos 10 +#define FLASH_ACR_DCEN_Msk ((uint32_t)1 << FLASH_ACR_DCEN_Pos) +#define FLASH_ACR_ICRST_Pos 11 +#define FLASH_ACR_ICRST_Msk ((uint32_t)1 << FLASH_ACR_ICRST_Pos) +#define FLASH_ACR_DCRST_Pos 12 +#define FLASH_ACR_DCRST_Msk ((uint32_t)1 << FLASH_ACR_DCRST_Pos) + +/******************* Flash key register ***************/ +#define KEY1 ((uint32_t)0x45670123) +#define KEY2 ((uint32_t)0xCDEF89AB) + +/******************* Flash option key register ***************/ +#define OPTKEY1 ((uint32_t)0x08192A3B) +#define OPTKEY2 ((uint32_t)0x4C5D6E7F) + +/******************* FLASH_SR register ******************/ +#define FLASH_SR_EOP_Pos 0 +#define FLASH_SR_EOP_Msk ((uint32_t)1 << FLASH_SR_EOP_Pos) +#define FLASH_SR_OPERR_Pos 1 +#define FLASH_SR_OPERR_Msk ((uint32_t)1 << FLASH_SR_OPERR_Pos) +#define FLASH_SR_WRPERR_Pos 4 +#define FLASH_SR_WRPERR_Msk ((uint32_t)1 << FLASH_SR_WRPERR_Pos) +#define FLASH_SR_PGAERR_Pos 5 +#define FLASH_SR_PGAERR_Msk ((uint32_t)1 << FLASH_SR_PGAERR_Pos) +#define FLASH_SR_PGPERR_Pos 6 +#define FLASH_SR_PGPERR_Msk ((uint32_t)1 << FLASH_SR_PGPERR_Pos) +#define FLASH_SR_PGSERR_Pos 7 +#define FLASH_SR_PGSERR_Msk ((uint32_t)1 << FLASH_SR_PGSERR_Pos) +#ifdef STM32F429 /* RDERR only on f42xxx/43xxx */ +#define FLASH_SR_RDERR_Pos 8 +#define FLASH_SR_RDERR_Msk ((uint32_t)1 << FLASH_SR_RDERR_Pos) +#endif +#define FLASH_SR_BSY_Pos 16 +#define FLASH_SR_BSY_Msk ((uint32_t)1 << FLASH_SR_BSY_Pos) + +/******************* FLASH_CR register ******************/ +#define FLASH_CR_PG_Pos 0 +#define FLASH_CR_PG_Msk ((uint32_t)1 << FLASH_CR_PG_Pos) +#define FLASH_CR_SER_Pos 1 +#define FLASH_CR_SER_Msk ((uint32_t)1 << FLASH_CR_SER_Pos) +#define FLASH_CR_MER_Pos 2 +#define FLASH_CR_MER_Msk ((uint32_t)1 << FLASH_CR_MER_Pos) +#define FLASH_CR_SNB_Pos 3 +#define FLASH_CR_SNB_Msk ((uint32_t)0xF << FLASH_CR_SNB_Pos) +#define FLASH_CR_PSIZE_Pos 8 +#define FLASH_CR_PSIZE_Msk ((uint32_t)3 << FLASH_CR_PSIZE_Pos) +#ifdef STM32F429 /* MER1 only on f42xxx/43xxx */ +#define FLASH_CR_MER1_Pos 15 +#define FLASH_CR_MER1_Msk ((uint32_t)1 << FLASH_CR_MER1_Pos) +#endif +#define FLASH_CR_STRT_Pos 16 +#define FLASH_CR_STRT_Msk ((uint32_t)1 << FLASH_CR_STRT_Pos) +#define FLASH_CR_EOPIE_Pos 24 +#define FLASH_CR_EOPIE_Msk ((uint32_t)1 << FLASH_CR_EOPIE_Pos) +#define FLASH_CR_ERRIE_Pos 25 +#define FLASH_CR_ERRIE_Msk ((uint32_t)1 << FLASH_CR_ERRIE_Pos) +#define FLASH_CR_LOCK_Pos 31 +#define FLASH_CR_LOCK_Msk ((uint32_t)1 << FLASH_CR_LOCK_Pos) + +/******************* FLASH_OPTCR register ***************/ +#define FLASH_OPTCR_OPTLOCK_Pos 0 +#define FLASH_OPTCR_OPTLOCK_Msk ((uint32_t)1 << FLASH_OPTCR_OPTLOCK_Pos) +#define FLASH_OPTCR_OPTSTRT_Pos 1 +#define FLASH_OPTCR_OPTSTRT_Msk ((uint32_t)1 << FLASH_OPTCR_OPTSTRT_Pos) +#define FLASH_OPTCR_BOR_LEV_Pos 2 +#define FLASH_OPTCR_BOR_LEV_Msk ((uint32_t)3 << FLASH_OPTCR_BOR_LEV_Pos) +#ifdef STM32F429 /* BFB2 only on f42xxx/43xxx */ +#define FLASH_OPTCR_BFB2_Pos 4 +#define FLASH_OPTCR_BFB2_Msk ((uint32_t)1 << FLASH_OPTCR_BFB2_Pos) +#endif +#define FLASH_OPTCR_WDG_SW_Pos 5 +#define FLASH_OPTCR_WDG_SW_Msk ((uint32_t)1 << FLASH_OPTCR_WDG_SW_Pos) +#define FLASH_OPTCR_nRST_STOP_Pos 6 +#define FLASH_OPTCR_nRST_STOP_Msk ((uint32_t)1 << FLASH_OPTCR_nRST_STOP_Pos) +#define FLASH_OPTCR_nRST_STDBY_Pos 7 +#define FLASH_OPTCR_nRST_STDBY_Msk ((uint32_t)1 << FLASH_OPTCR_nRST_STDBY_Pos) +#define FLASH_OPTCR_RDP_Pos 8 +#define FLASH_OPTCR_RDP_Msk ((uint32_t)0xFF << FLASH_OPTCR_RDP_Pos) +#define FLASH_OPTCR_nWRP_Pos 16 +#define FLASH_OPTCR_nWRP_Msk ((uint32_t)0x0FFF << FLASH_OPTCR_nWRP_Pos) +#ifdef STM32F429 /* STM32F42xxx/STM32F43xxx only */ +#define FLASH_OPTCR_DB1M_Pos 30 +#define FLASH_OPTCR_DB1M_Msk ((uint32_t)1 << FLASH_OPTCR_DB1M_Pos) +#define FLASH_OPTCR_SPRMOD_Pos 31 +#define FLASH_OPTCR_SPRMOD_Msk ((uint32_t)1 << FLASH_OPTCR_SPRMOD_Pos) +#endif + +/******************* FLASH_OPTCR1 register ***************/ +#ifdef STM32F429 /**** Only on f42xxx/43xxx ****/ +#define FLASH_OPTCR1_nWRP_Pos 16 +#define FLASH_OPTCR1_nWRP_Msk ((uint32_t)0x0FFF << FLASH_OPTCR1_nWRP_Pos) +#endif + +/****** Adress definition for flash memory sectors ******/ +/*** Single bank configuration ***/ +#define FLASH_SECTOR_0 ((uint32_t) 0x08000000) /* 16 kB */ +#define FLASH_SECTOR_0_END ((uint32_t) 0x08003FFF) +#define FLASH_SECTOR_1 ((uint32_t) 0x08004000) /* 16 kB */ +#define FLASH_SECTOR_1_END ((uint32_t) 0x08007FFF) +#define FLASH_SECTOR_2 ((uint32_t) 0x08008000) /* 16 kB */ +#define FLASH_SECTOR_2_END ((uint32_t) 0x0800BFFF) +#define FLASH_SECTOR_3 ((uint32_t) 0x0800C000) /* 16 kB */ +#define FLASH_SECTOR_3_END ((uint32_t) 0x0800FFFF) +#define FLASH_SECTOR_4 ((uint32_t) 0x08010000) /* 64 kB */ +#define FLASH_SECTOR_4_END ((uint32_t) 0x0801FFFF) +#define FLASH_SECTOR_5 ((uint32_t) 0x08020000) /* 128 kB */ +#define FLASH_SECTOR_5_END ((uint32_t) 0x0803FFFF) +#define FLASH_SECTOR_6 ((uint32_t) 0x08040000) /* 128 kB */ +#define FLASH_SECTOR_6_END ((uint32_t) 0x0805FFFF) +#define FLASH_SECTOR_7 ((uint32_t) 0x08060000) /* 128 kB */ +#define FLASH_SECTOR_7_END ((uint32_t) 0x0807FFFF) +#define FLASH_SECTOR_8 ((uint32_t) 0x08080000) /* 128 kB */ +#define FLASH_SECTOR_8_END ((uint32_t) 0x0809FFFF) +#define FLASH_SECTOR_9 ((uint32_t) 0x080A0000) /* 128 kB */ +#define FLASH_SECTOR_9_END ((uint32_t) 0x080BFFFF) +#define FLASH_SECTOR_10 ((uint32_t) 0x080C0000) /* 128 kB */ +#define FLASH_SECTOR_10_END ((uint32_t) 0x080DFFFF) +#define FLASH_SECTOR_11 ((uint32_t) 0x080E0000) /* 128 kB */ +#define FLASH_SECTOR_11_END ((uint32_t) 0x080FFFFF) +#define FLASH_SECTOR_SYSTEM_MEM ((uint32_t) 0x1FFF0000) /* 30 kB */ +#define FLASH_SECTOR_SYSTEM_MEM_END ((uint32_t) 0x1FFF77FF) +#define FLASH_SECTOR_OPT_AREA ((uint32_t) 0x1FFF7800) /* 528 B */ +#define FLASH_SECTOR_OPT_AREA_END ((uint32_t) 0x1FFF7A0F) +#define FLASH_OPTION_BYTES ((uint32_t) 0x1FFFC000) /* 16 B */ +#define FLASH_OPTION_BYTES_END ((uint32_t) 0x1FFFC00F) +#ifdef STM32F429 /* ! Only in f42xxx/43xxx ! */ +#define FLASH_OPTION_BYTES_SGL ((uint32_t) 0x1FFEC000) /* 16 B */ +#define FLASH_OPTION_BYTES_SGL_END ((uint32_t) 0x1FFEC00F) +#endif + +/*** 1MB Dual bank memory configuration (8 first sector & opt bytes unchanged) ***/ +#define FLASH_SECTOR_12 ((uint32_t) 0x08080000) /* 16 kB */ +#define FLASH_SECTOR_12_END ((uint32_t) 0x08083FFF) +#define FLASH_SECTOR_13 ((uint32_t) 0x08084000) /* 16 kB */ +#define FLASH_SECTOR_13_END ((uint32_t) 0x08087FFF) +#define FLASH_SECTOR_14 ((uint32_t) 0x08088000) /* 16 kB */ +#define FLASH_SECTOR_14_END ((uint32_t) 0x0808BFFF) +#define FLASH_SECTOR_15 ((uint32_t) 0x0808C000) /* 16 kB */ +#define FLASH_SECTOR_15_END ((uint32_t) 0x0808FFFF) +#define FLASH_SECTOR_16 ((uint32_t) 0x08090000) /* 64 kB */ +#define FLASH_SECTOR_16_END ((uint32_t) 0x0809FFFF) +#define FLASH_SECTOR_17 ((uint32_t) 0x080A0000) /* 128 kB */ +#define FLASH_SECTOR_17_END ((uint32_t) 0x080BFFFF) +#define FLASH_SECTOR_18 ((uint32_t) 0x080A0000) /* 128 kB */ +#define FLASH_SECTOR_18_END ((uint32_t) 0x080BFFFF) +#define FLASH_SECTOR_19 ((uint32_t) 0x080C0000) /* 128 kB */ +#define FLASH_SECTOR_19_END ((uint32_t) 0x080DFFFF) +#define FLASH_OPTION_BYTES_BK1 ((uint32_t) 0x1FFFC000) /* 16 B */ +#define FLASH_OPTION_BYTES_BK1_END ((uint32_t) 0x1FFFC00F) +#define FLASH_OPTION_BYTES_BK2 ((uint32_t) 0x1FFEC000) /* 16 B */ +#define FLASH_OPTION_BYTES_BK2_END ((uint32_t) 0x1FFEC00F) + +#define IS_IN_FLASH(addr) (addr >= FLASH_SECTOR_0) && \ + (addr <= FLASH_SECTOR_11_END) + +#define IS_IN_FLASH_DUAL(addr) (addr >= FLASH_SECTOR_0) && \ + (addr <= FLASH_SECTOR_11_END) || \ + (addr >= FLASH_SECTOR_12) && \ + (addr <= FLASH_SECTOR_19_END) + +//#define START_SECTOR(SECTOR) (uint32_t)FLASH_SECTOR_##SECTOR +//#define END_SECTOR(SECTOR) (uint32_t)FLASH_SECTOR_##SECTOR##_END + +/******************* Bits definition for FLASH_ACR register *****************/ +#define FLASH_ACR_LATENCY ((uint32_t)0x00000007) +#define FLASH_ACR_LATENCY_0WS ((uint32_t)0x00000000) +#define FLASH_ACR_LATENCY_1WS ((uint32_t)0x00000001) +#define FLASH_ACR_LATENCY_2WS ((uint32_t)0x00000002) +#define FLASH_ACR_LATENCY_3WS ((uint32_t)0x00000003) +#define FLASH_ACR_LATENCY_4WS ((uint32_t)0x00000004) +#define FLASH_ACR_LATENCY_5WS ((uint32_t)0x00000005) +#define FLASH_ACR_LATENCY_6WS ((uint32_t)0x00000006) +#define FLASH_ACR_LATENCY_7WS ((uint32_t)0x00000007) + +#define FLASH_ACR_PRFTEN ((uint32_t)0x00000100) +#define FLASH_ACR_ICEN ((uint32_t)0x00000200) +#define FLASH_ACR_DCEN ((uint32_t)0x00000400) +#define FLASH_ACR_ICRST ((uint32_t)0x00000800) +#define FLASH_ACR_DCRST ((uint32_t)0x00001000) +#define FLASH_ACR_BYTE0_ADDRESS ((uint32_t)0x40023C00) +#define FLASH_ACR_BYTE2_ADDRESS ((uint32_t)0x40023C03) + +/******************* Bits definition for FLASH_SR register ******************/ +#define FLASH_SR_EOP ((uint32_t)0x00000001) +#define FLASH_SR_SOP ((uint32_t)0x00000002) +#define FLASH_SR_WRPERR ((uint32_t)0x00000010) +#define FLASH_SR_PGAERR ((uint32_t)0x00000020) +#define FLASH_SR_PGPERR ((uint32_t)0x00000040) +#define FLASH_SR_PGSERR ((uint32_t)0x00000080) +#define FLASH_SR_BSY ((uint32_t)0x00010000) + +/******************* Bits definition for FLASH_CR register ******************/ +#define FLASH_CR_PG ((uint32_t)0x00000001) +#define FLASH_CR_SER ((uint32_t)0x00000002) +#define FLASH_CR_MER ((uint32_t)0x00000004) +#define FLASH_CR_SNB_0 ((uint32_t)0x00000008) +#define FLASH_CR_SNB_1 ((uint32_t)0x00000010) +#define FLASH_CR_SNB_2 ((uint32_t)0x00000020) +#define FLASH_CR_SNB_3 ((uint32_t)0x00000040) +#define FLASH_CR_PSIZE_0 ((uint32_t)0x00000100) +#define FLASH_CR_PSIZE_1 ((uint32_t)0x00000200) +#define FLASH_CR_STRT ((uint32_t)0x00010000) +#define FLASH_CR_EOPIE ((uint32_t)0x01000000) +#define FLASH_CR_LOCK ((uint32_t)0x80000000) + +/******************* Bits definition for FLASH_OPTCR register ***************/ +#define FLASH_OPTCR_OPTLOCK ((uint32_t)0x00000001) +#define FLASH_OPTCR_OPTSTRT ((uint32_t)0x00000002) +#define FLASH_OPTCR_BOR_LEV_0 ((uint32_t)0x00000004) +#define FLASH_OPTCR_BOR_LEV_1 ((uint32_t)0x00000008) +#define FLASH_OPTCR_BOR_LEV ((uint32_t)0x0000000C) +#define FLASH_OPTCR_WDG_SW ((uint32_t)0x00000020) +#define FLASH_OPTCR_nRST_STOP ((uint32_t)0x00000040) +#define FLASH_OPTCR_nRST_STDBY ((uint32_t)0x00000080) +#define FLASH_OPTCR_RDP_0 ((uint32_t)0x00000100) +#define FLASH_OPTCR_RDP_1 ((uint32_t)0x00000200) +#define FLASH_OPTCR_RDP_2 ((uint32_t)0x00000400) +#define FLASH_OPTCR_RDP_3 ((uint32_t)0x00000800) +#define FLASH_OPTCR_RDP_4 ((uint32_t)0x00001000) +#define FLASH_OPTCR_RDP_5 ((uint32_t)0x00002000) +#define FLASH_OPTCR_RDP_6 ((uint32_t)0x00004000) +#define FLASH_OPTCR_RDP_7 ((uint32_t)0x00008000) +#define FLASH_OPTCR_nWRP_0 ((uint32_t)0x00010000) +#define FLASH_OPTCR_nWRP_1 ((uint32_t)0x00020000) +#define FLASH_OPTCR_nWRP_2 ((uint32_t)0x00040000) +#define FLASH_OPTCR_nWRP_3 ((uint32_t)0x00080000) +#define FLASH_OPTCR_nWRP_4 ((uint32_t)0x00100000) +#define FLASH_OPTCR_nWRP_5 ((uint32_t)0x00200000) +#define FLASH_OPTCR_nWRP_6 ((uint32_t)0x00400000) +#define FLASH_OPTCR_nWRP_7 ((uint32_t)0x00800000) +#define FLASH_OPTCR_nWRP_8 ((uint32_t)0x01000000) +#define FLASH_OPTCR_nWRP_9 ((uint32_t)0x02000000) +#define FLASH_OPTCR_nWRP_10 ((uint32_t)0x04000000) +#define FLASH_OPTCR_nWRP_11 ((uint32_t)0x08000000) + +#endif /* !SOC_FLASH_H */ diff --git a/arch/socs/stm32f439/soc-gpio.c b/arch/socs/stm32f439/soc-gpio.c new file mode 100644 index 0000000..24b92ef --- /dev/null +++ b/arch/socs/stm32f439/soc-gpio.c @@ -0,0 +1,231 @@ +/* \file soc-gpio.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "types.h" +#include "exported/devices.h" +#include "exported/gpio.h" +#include "soc-gpio.h" + +/* +** Convert a port num (0x0 = GPIOA, 0x1 = GPIOB...) into port base address +*/ +static uint32_t soc_gpio_get_port_base (gpioref_t kref) +{ + uint32_t port_base; + switch (kref.port) { + case GPIO_PA: port_base = GPIOA_BASE; break; + case GPIO_PB: port_base = GPIOB_BASE; break; + case GPIO_PC: port_base = GPIOC_BASE; break; + case GPIO_PD: port_base = GPIOD_BASE; break; + case GPIO_PE: port_base = GPIOE_BASE; break; + case GPIO_PF: port_base = GPIOF_BASE; break; + case GPIO_PG: port_base = GPIOG_BASE; break; + case GPIO_PH: port_base = GPIOH_BASE; break; + case GPIO_PI: port_base = GPIOI_BASE; break; + default: + port_base = 0; + break; + } + return port_base; +} + +void soc_gpio_set_mode(volatile uint32_t * gpioX_moder, uint8_t pin, + uint8_t mode) +{ + set_reg_value(gpioX_moder, mode, 0x3 << (2 * pin), 2 * pin); +} + +void soc_gpio_set_type(volatile uint32_t * gpioX_otyper, uint8_t pin, + uint8_t type) +{ + set_reg_value(gpioX_otyper, type, 1 << pin, pin); +} + +void soc_gpio_set_speed(volatile uint32_t * gpioX_ospeedr, uint8_t pin, + uint8_t speed) +{ + set_reg_value(gpioX_ospeedr, speed, 0x3 << (2 * pin), 2 * pin); +} + +void soc_gpio_set_pupd(volatile uint32_t * gpioX_pupdr, uint8_t pin, + uint8_t pupd) +{ + set_reg_value(gpioX_pupdr, pupd, 0x3 << (2 * pin), 2 * pin); +} + +void soc_gpio_set_od(volatile uint32_t * gpioX_odr, uint8_t pin, uint8_t od) +{ + set_reg_value(gpioX_odr, od, 1 << pin, pin); +} + +void soc_gpio_set_bsr_r(volatile uint32_t * gpioX_bsrr_r, uint8_t pin, + uint8_t reset) +{ + set_reg_value(gpioX_bsrr_r, reset, 1 << pin, pin); +} + +void soc_gpio_set_bsr_s(volatile uint32_t * gpioX_bsrr_r, uint8_t pin, + uint8_t set) +{ + set_reg_value(gpioX_bsrr_r, set, 1 << pin, pin); +} + +void soc_gpio_set_lck(volatile uint32_t * gpioX_lckr, uint8_t pin, + uint8_t value) +{ + set_reg_value(gpioX_lckr, value, 1 << pin, pin); +} + +void soc_gpio_set_afr(volatile uint32_t * gpioX_afr, uint8_t pin, + uint8_t function) +{ + if (pin > 7) + set_reg_value(gpioX_afr + 1, function, 0xf << (4 * (pin - 8)), + 4 * (pin - 8)); + else + set_reg_value(gpioX_afr, function, 0xf << (4 * pin), 4 * pin); +} + +#define GPIO_CONFIG(port) \ + set_reg_bits(r_CORTEX_M_RCC_AHB1ENR, RCC_AHB1ENR_GPIO##port##EN);\ + gpioX_moder = GPIO_MODER(GPIO##port##_BASE);\ + gpioX_otyper = GPIO_OTYPER(GPIO##port##_BASE);\ + gpioX_ospeedr = GPIO_OSPEEDR(GPIO##port##_BASE);\ + gpioX_pupdr = GPIO_PUPDR(GPIO##port##_BASE);\ + gpioX_idr = GPIO_IDR(GPIO##port##_BASE); \ + gpioX_odr = GPIO_ODR(GPIO##port##_BASE);\ + gpioX_bsrr_r = GPIO_BSRR_R(GPIO##port##_BASE);\ + gpioX_bsrr_s = GPIO_BSRR_S(GPIO##port##_BASE);\ + gpioX_lckr = GPIO_LCKR(GPIO##port##_BASE);\ + gpioX_afr_l = GPIO_AFR_L(GPIO##port##_BASE);\ + gpioX_afr_h = GPIO_AFR_H(GPIO##port##_BASE) + +uint8_t soc_gpio_set_config(const dev_gpio_info_t * gpio) +{ + volatile uint32_t *gpioX_moder, *gpioX_otyper, *gpioX_ospeedr, + *gpioX_pupdr, *gpioX_idr, *gpioX_odr, + *gpioX_bsrr_r, *gpioX_bsrr_s, *gpioX_lckr, + *gpioX_afr_l, *gpioX_afr_h; + + physaddr_t portaddr = soc_gpio_get_port_base(gpio->kref); + + /* Does the port exist? */ + if (portaddr == 0) { + return 1; + } + + switch (portaddr) { + case GPIOA_BASE: GPIO_CONFIG(A); break; + case GPIOB_BASE: GPIO_CONFIG(B); break; + case GPIOC_BASE: GPIO_CONFIG(C); break; + case GPIOD_BASE: GPIO_CONFIG(D); break; + case GPIOE_BASE: GPIO_CONFIG(E); break; + case GPIOF_BASE: GPIO_CONFIG(F); break; + case GPIOG_BASE: GPIO_CONFIG(G); break; + case GPIOH_BASE: GPIO_CONFIG(H); break; + case GPIOI_BASE: GPIO_CONFIG(I); break; + default: + return 1; + } + + /* Set the appropriate values according to the mask */ + if (gpio->mask & GPIO_MASK_SET_MODE) { + soc_gpio_set_mode(gpioX_moder, gpio->kref.pin, gpio->mode); + } + if (gpio->mask & GPIO_MASK_SET_TYPE) { + soc_gpio_set_type(gpioX_otyper, gpio->kref.pin, gpio->type); + } + if (gpio->mask & GPIO_MASK_SET_SPEED) { + soc_gpio_set_speed(gpioX_ospeedr, gpio->kref.pin, gpio->speed); + } + if (gpio->mask & GPIO_MASK_SET_PUPD) { + soc_gpio_set_pupd(gpioX_pupdr, gpio->kref.pin, gpio->pupd); + } + if (gpio->mask & GPIO_MASK_SET_BSR_R) { + soc_gpio_set_bsr_r(gpioX_bsrr_r, gpio->kref.pin, gpio->bsr_r); + } + if (gpio->mask & GPIO_MASK_SET_BSR_S) { + soc_gpio_set_bsr_s(gpioX_bsrr_r, gpio->kref.pin, gpio->bsr_s); + } + if (gpio->mask & GPIO_MASK_SET_LCK) { + soc_gpio_set_lck(gpioX_lckr, gpio->kref.pin, gpio->lck); + } + if (gpio->mask & GPIO_MASK_SET_AFR) { + soc_gpio_set_afr(gpioX_afr_l, gpio->kref.pin, gpio->afr); + } + + return 0; +} + +uint8_t soc_gpio_configure + (uint8_t port, uint8_t pin, gpio_mode_t mode, gpio_type_t type, + gpio_speed_t speed, gpio_pupd_t pupd, gpio_af_t afr) +{ + volatile uint32_t *gpioX_moder, *gpioX_otyper, *gpioX_ospeedr, + *gpioX_pupdr, *gpioX_idr, *gpioX_odr, + *gpioX_bsrr_r, *gpioX_bsrr_s, *gpioX_lckr, + *gpioX_afr_l, *gpioX_afr_h; + + switch (port) { + case GPIO_PA: GPIO_CONFIG(A); break; + case GPIO_PB: GPIO_CONFIG(B); break; + case GPIO_PC: GPIO_CONFIG(C); break; + case GPIO_PD: GPIO_CONFIG(D); break; + case GPIO_PE: GPIO_CONFIG(E); break; + case GPIO_PF: GPIO_CONFIG(F); break; + case GPIO_PG: GPIO_CONFIG(G); break; + case GPIO_PH: GPIO_CONFIG(H); break; + case GPIO_PI: GPIO_CONFIG(I); break; + default: + return 1; + } + + soc_gpio_set_mode(gpioX_moder, pin, mode); + soc_gpio_set_type(gpioX_otyper, pin, type); + soc_gpio_set_speed(gpioX_ospeedr, pin, speed); + soc_gpio_set_pupd(gpioX_pupdr, pin, pupd); + soc_gpio_set_afr(gpioX_afr_l, pin, afr); + + return 0; +} + +void soc_gpio_set_value(gpioref_t kref, uint8_t value) +{ + physaddr_t portaddr = soc_gpio_get_port_base(kref); + soc_gpio_set_od(GPIO_ODR(portaddr), kref.pin, !!value); +} + +void soc_gpio_set(gpioref_t kref) +{ + soc_gpio_set_value(kref, 1); +} + +void soc_gpio_clear(gpioref_t kref) +{ + soc_gpio_set_value(kref, 0); +} + +uint8_t soc_gpio_get(gpioref_t kref) +{ + physaddr_t portaddr = soc_gpio_get_port_base(kref); + return !!get_reg_value(GPIO_IDR(portaddr), 1 << (kref.pin), kref.pin); +} diff --git a/arch/socs/stm32f439/soc-gpio.h b/arch/socs/stm32f439/soc-gpio.h new file mode 100644 index 0000000..102f15a --- /dev/null +++ b/arch/socs/stm32f439/soc-gpio.h @@ -0,0 +1,370 @@ +/* \file soc-gpio.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_GPIO_H +#define SOC_GPIO_H + +#include "regutils.h" +#include "soc-core.h" +#include "soc-rcc.h" +#include "exported/devices.h" +#include "exported/gpio.h" + +#define GPIO_MODER(g) REG_ADDR(g + 0x00) /*!< GPIO port mode register */ +#define GPIO_OTYPER(g) REG_ADDR(g + 0x04) /*!< GPIO port output type register */ +#define GPIO_OSPEEDR(g) REG_ADDR(g + 0x08) /*!< GPIO port output speed register */ +#define GPIO_PUPDR(g) REG_ADDR(g + 0x0C) /*!< GPIO port pull-up/pull-down register */ +#define GPIO_IDR(g) REG_ADDR(g + 0x10) /*!< GPIO port input data register */ +#define GPIO_ODR(g) REG_ADDR(g + 0x14) /*!< GPIO port output data register */ +#define GPIO_BSRR_R(g) REG_ADDR(g + 0x18) /*!< GPIO port bit set/reset reset register */ +#define GPIO_BSRR_S(g) REG_ADDR(g + 0x1A) /*!< GPIO port bit set/reset set register */ +#define GPIO_LCKR(g) REG_ADDR(g + 0x1C) /*!< GPIO port configuration lock register */ +#define GPIO_AFR_L(g) REG_ADDR(g + 0x20) /*!< GPIO alternate function registers, low part */ +#define GPIO_AFR_H(g) REG_ADDR(g + 0x24) /*!< GPIO alternate function registers, high part */ + +#define GPIOA REG_ADDR(GPIOA_BASE) +#define GPIOA_MODER GPIO_MODER(GPIOA_BASE) +#define GPIOA_OTYPER GPIO_OTYPER(GPIOA_BASE) +#define GPIOA_OSPEEDR GPIO_OSPEEDR(GPIOA_BASE) +#define GPIOA_PUPDR GPIO_PUPDR(GPIOA_BASE) +#define GPIOA_IDR GPIO_IDR(GPIOA_BASE) +#define GPIOA_ODR GPIO_ODR(GPIOA_BASE) +#define GPIOA_BSRR_R GPIO_BSRR_R(GPIOA_BASE) +#define GPIOA_BSRR_S GPIO_BSRR_S(GPIOA_BASE) +#define GPIOA_LCKR GPIO_LCKR(GPIOA_BASE) +#define GPIOA_AFR_L GPIO_AFR_L(GPIOA_BASE) +#define GPIOA_AFR_H GPIO_AFR_H(GPIOA_BASE) + +#define GPIOB REG_ADDR(GPIOB_BASE) +#define GPIOB_MODER GPIO_MODER(GPIOB_BASE) +#define GPIOB_OTYPER GPIO_OTYPER(GPIOB_BASE) +#define GPIOB_OSPEEDR GPIO_OSPEEDR(GPIOB_BASE) +#define GPIOB_PUPDR GPIO_PUPDR(GPIOB_BASE) +#define GPIOB_IDR GPIO_IDR(GPIOB_BASE) +#define GPIOB_ODR GPIO_ODR(GPIOB_BASE) +#define GPIOB_BSRR_R GPIO_BSRR_R(GPIOB_BASE) +#define GPIOB_BSRR_S GPIO_BSRR_S(GPIOB_BASE) +#define GPIOB_LCKR GPIO_LCKR(GPIOB_BASE) +#define GPIOB_AFR_L GPIO_AFR_L(GPIOB_BASE) +#define GPIOB_AFR_H GPIO_AFR_H(GPIOB_BASE) + +#define GPIOC REG_ADDR(GPIOC_BASE) +#define GPIOC_MODER GPIO_MODER(GPIOC_BASE) +#define GPIOC_OTYPER GPIO_OTYPER(GPIOC_BASE) +#define GPIOC_OSPEEDR GPIO_OSPEEDR(GPIOC_BASE) +#define GPIOC_PUPDR GPIO_PUPDR(GPIOC_BASE) +#define GPIOC_IDR GPIO_IDR(GPIOC_BASE) +#define GPIOC_ODR GPIO_ODR(GPIOC_BASE) +#define GPIOC_BSRR_R GPIO_BSRR_R(GPIOC_BASE) +#define GPIOC_BSRR_S GPIO_BSRR_S(GPIOC_BASE) +#define GPIOC_LCKR GPIO_LCKR(GPIOC_BASE) +#define GPIOC_AFR_L GPIO_AFR_L(GPIOC_BASE) +#define GPIOC_AFR_H GPIO_AFR_H(GPIOC_BASE) + +#define GPIOD REG_ADDR(GPIOD_BASE) +#define GPIOD_MODER GPIO_MODER(GPIOD_BASE) +#define GPIOD_OTYPER GPIO_OTYPER(GPIOD_BASE) +#define GPIOD_OSPEEDR GPIO_OSPEEDR(GPIOD_BASE) +#define GPIOD_PUPDR GPIO_PUPDR(GPIOD_BASE) +#define GPIOD_IDR GPIO_IDR(GPIOD_BASE) +#define GPIOD_ODR GPIO_ODR(GPIOD_BASE) +#define GPIOD_BSRR_R GPIO_BSRR_R(GPIOD_BASE) +#define GPIOD_BSRR_S GPIO_BSRR_S(GPIOD_BASE) +#define GPIOD_LCKR GPIO_LCKR(GPIOD_BASE) +#define GPIOD_AFR_L GPIO_AFR_L(GPIOD_BASE) +#define GPIOD_AFR_H GPIO_AFR_H(GPIOD_BASE) + +#define GPIOE REG_ADDR(GPIOE_BASE) +#define GPIOE_MODER GPIO_MODER(GPIOE_BASE) +#define GPIOE_OTYPER GPIO_OTYPER(GPIOE_BASE) +#define GPIOE_OSPEEDR GPIO_OSPEEDR(GPIOE_BASE) +#define GPIOE_PUPDR GPIO_PUPDR(GPIOE_BASE) +#define GPIOE_IDR GPIO_IDR(GPIOE_BASE) +#define GPIOE_ODR GPIO_ODR(GPIOE_BASE) +#define GPIOE_BSRR_R GPIO_BSRR_R(GPIOE_BASE) +#define GPIOE_BSRR_S GPIO_BSRR_S(GPIOE_BASE) +#define GPIOE_LCKR GPIO_LCKR(GPIOE_BASE) +#define GPIOE_AFR_L GPIO_AFR_L(GPIOE_BASE) +#define GPIOE_AFR_H GPIO_AFR_H(GPIOE_BASE) + +#define GPIOF REG_ADDR(GPIOF_BASE) +#define GPIOF_MODER GPIO_MODER(GPIOF_BASE) +#define GPIOF_OTYPER GPIO_OTYPER(GPIOF_BASE) +#define GPIOF_OSPEEDR GPIO_OSPEEDR(GPIOF_BASE) +#define GPIOF_PUPDR GPIO_PUPDR(GPIOF_BASE) +#define GPIOF_IDR GPIO_IDR(GPIOF_BASE) +#define GPIOF_ODR GPIO_ODR(GPIOF_BASE) +#define GPIOF_BSRR_R GPIO_BSRR_R(GPIOF_BASE) +#define GPIOF_BSRR_S GPIO_BSRR_S(GPIOF_BASE) +#define GPIOF_LCKR GPIO_LCKR(GPIOF_BASE) +#define GPIOF_AFR_L GPIO_AFR_L(GPIOF_BASE) +#define GPIOF_AFR_H GPIO_AFR_H(GPIOF_BASE) + +#define GPIOG REG_ADDR(GPIOG_BASE) +#define GPIOG_MODER GPIO_MODER(GPIOG_BASE) +#define GPIOG_OTYPER GPIO_OTYPER(GPIOG_BASE) +#define GPIOG_OSPEEDR GPIO_OSPEEDR(GPIOG_BASE) +#define GPIOG_PUPDR GPIO_PUPDR(GPIOG_BASE) +#define GPIOG_IDR GPIO_IDR(GPIOG_BASE) +#define GPIOG_ODR GPIO_ODR(GPIOG_BASE) +#define GPIOG_BSRR_R GPIO_BSRR_R(GPIOG_BASE) +#define GPIOG_BSRR_S GPIO_BSRR_S(GPIOG_BASE) +#define GPIOG_LCKR GPIO_LCKR(GPIOG_BASE) +#define GPIOG_AFR_L GPIO_AFR_L(GPIOG_BASE) +#define GPIOG_AFR_H GPIO_AFR_H(GPIOG_BASE) + +#define GPIOH REG_ADDR(GPIOH_BASE) +#define GPIOH_MODER GPIO_MODER(GPIOH_BASE) +#define GPIOH_OTYPER GPIO_OTYPER(GPIOH_BASE) +#define GPIOH_OSPEEDR GPIO_OSPEEDR(GPIOH_BASE) +#define GPIOH_PUPDR GPIO_PUPDR(GPIOH_BASE) +#define GPIOH_IDR GPIO_IDR(GPIOH_BASE) +#define GPIOH_ODR GPIO_ODR(GPIOH_BASE) +#define GPIOH_BSRR_R GPIO_BSRR_R(GPIOH_BASE) +#define GPIOH_BSRR_S GPIO_BSRR_S(GPIOH_BASE) +#define GPIOH_LCKR GPIO_LCKR(GPIOH_BASE) +#define GPIOH_AFR_L GPIO_AFR_L(GPIOH_BASE) +#define GPIOH_AFR_H GPIO_AFR_H(GPIOH_BASE) + +#define GPIOI REG_ADDR(GPIOI_BASE) +#define GPIOI_MODER GPIO_MODER(GPIOI_BASE) +#define GPIOI_OTYPER GPIO_OTYPER(GPIOI_BASE) +#define GPIOI_OSPEEDR GPIO_OSPEEDR(GPIOI_BASE) +#define GPIOI_PUPDR GPIO_PUPDR(GPIOI_BASE) +#define GPIOI_IDR GPIO_IDR(GPIOI_BASE) +#define GPIOI_ODR GPIO_ODR(GPIOI_BASE) +#define GPIOI_BSRR_R GPIO_BSRR_R(GPIOI_BASE) +#define GPIOI_BSRR_S GPIO_BSRR_S(GPIOI_BASE) +#define GPIOI_LCKR GPIO_LCKR(GPIOI_BASE) +#define GPIOI_AFR_L GPIO_AFR_L(GPIOI_BASE) +#define GPIOI_AFR_H GPIO_AFR_H(GPIOI_BASE) + +#define GPIO_PIN_0 ((uint16_t)0x0001) +#define GPIO_PIN_1 ((uint16_t)0x0002) +#define GPIO_PIN_2 ((uint16_t)0x0004) +#define GPIO_PIN_3 ((uint16_t)0x0008) +#define GPIO_PIN_4 ((uint16_t)0x0010) +#define GPIO_PIN_5 ((uint16_t)0x0020) +#define GPIO_PIN_6 ((uint16_t)0x0040) +#define GPIO_PIN_7 ((uint16_t)0x0080) +#define GPIO_PIN_8 ((uint16_t)0x0100) +#define GPIO_PIN_9 ((uint16_t)0x0200) +#define GPIO_PIN_10 ((uint16_t)0x0400) +#define GPIO_PIN_11 ((uint16_t)0x0800) +#define GPIO_PIN_12 ((uint16_t)0x1000) +#define GPIO_PIN_13 ((uint16_t)0x2000) +#define GPIO_PIN_14 ((uint16_t)0x4000) +#define GPIO_PIN_15 ((uint16_t)0x8000) +#define GPIO_PIN_ALL ((uint16_t)0xFFFF) + +/* RESET VALUES REGISTERS */ +#define GPIOA_MODER_RESET ((uint32_t)0xA8000000) +#define GPIOB_MODER_RESET ((uint32_t)0x00000280) +#define GPIOC_MODER_RESET ((uint32_t)0x00000000) +#define GPIOD_MODER_RESET ((uint32_t)0x00000000) +#define GPIOE_MODER_RESET ((uint32_t)0x00000000) +#define GPIOF_MODER_RESET ((uint32_t)0x00000000) +#define GPIOG_MODER_RESET ((uint32_t)0x00000000) +#define GPIOH_MODER_RESET ((uint32_t)0x00000000) +#define GPIOI_MODER_RESET ((uint32_t)0x00000000) + +#define GPIOA_OTYPER_RESET ((uint32_t)0x00000000) +#define GPIOB_OTYPER_RESET ((uint32_t)0x00000000) +#define GPIOC_OTYPER_RESET ((uint32_t)0x00000000) +#define GPIOD_OTYPER_RESET ((uint32_t)0x00000000) +#define GPIOE_OTYPER_RESET ((uint32_t)0x00000000) +#define GPIOF_OTYPER_RESET ((uint32_t)0x00000000) +#define GPIOG_OTYPER_RESET ((uint32_t)0x00000000) +#define GPIOH_OTYPER_RESET ((uint32_t)0x00000000) +#define GPIOI_OTYPER_RESET ((uint32_t)0x00000000) + +#define GPIOA_OSPEEDER_RESET ((uint32_t)0x0C000000) +#define GPIOB_OSPEEDER_RESET ((uint32_t)0x000000C0) +#define GPIOC_OSPEEDER_RESET ((uint32_t)0x00000000) +#define GPIOD_OSPEEDER_RESET ((uint32_t)0x00000000) +#define GPIOE_OSPEEDER_RESET ((uint32_t)0x00000000) +#define GPIOF_OSPEEDER_RESET ((uint32_t)0x00000000) +#define GPIOG_OSPEEDER_RESET ((uint32_t)0x00000000) +#define GPIOH_OSPEEDER_RESET ((uint32_t)0x00000000) +#define GPIOI_OSPEEDER_RESET ((uint32_t)0x00000000) + +#define GPIOA_PUPDR_RESET ((uint32_t)0x64000000) +#define GPIOB_PUPDR_RESET ((uint32_t)0x00000100) +#define GPIOC_PUPDR_RESET ((uint32_t)0x00000000) +#define GPIOD_PUPDR_RESET ((uint32_t)0x00000000) +#define GPIOE_PUPDR_RESET ((uint32_t)0x00000000) +#define GPIOF_PUPDR_RESET ((uint32_t)0x00000000) +#define GPIOG_PUPDR_RESET ((uint32_t)0x00000000) +#define GPIOH_PUPDR_RESET ((uint32_t)0x00000000) +#define GPIOI_PUPDR_RESET ((uint32_t)0x00000000) + +#define GPIOA_ODR_RESET ((uint32_t)0x00000000) +#define GPIOB_ODR_RESET ((uint32_t)0x00000000) +#define GPIOC_ODR_RESET ((uint32_t)0x00000000) +#define GPIOD_ODR_RESET ((uint32_t)0x00000000) +#define GPIOE_ODR_RESET ((uint32_t)0x00000000) +#define GPIOF_ODR_RESET ((uint32_t)0x00000000) +#define GPIOG_ODR_RESET ((uint32_t)0x00000000) +#define GPIOH_ODR_RESET ((uint32_t)0x00000000) +#define GPIOI_ODR_RESET ((uint32_t)0x00000000) + +#define GPIOA_BSRR_RESET ((uint32_t)0x00000000) +#define GPIOB_BSRR_RESET ((uint32_t)0x00000000) +#define GPIOC_BSRR_RESET ((uint32_t)0x00000000) +#define GPIOD_BSRR_RESET ((uint32_t)0x00000000) +#define GPIOE_BSRR_RESET ((uint32_t)0x00000000) +#define GPIOF_BSRR_RESET ((uint32_t)0x00000000) +#define GPIOG_BSRR_RESET ((uint32_t)0x00000000) +#define GPIOH_BSRR_RESET ((uint32_t)0x00000000) +#define GPIOI_BSSR_RESET ((uint32_t)0x00000000) + +#define GPIOA_LCKR_RESET ((uint32_t)0x00000000) +#define GPIOB_LCKR_RESET ((uint32_t)0x00000000) +#define GPIOC_LCKR_RESET ((uint32_t)0x00000000) +#define GPIOD_LCKR_RESET ((uint32_t)0x00000000) +#define GPIOE_LCKR_RESET ((uint32_t)0x00000000) +#define GPIOF_LCKR_RESET ((uint32_t)0x00000000) +#define GPIOG_LCKR_RESET ((uint32_t)0x00000000) +#define GPIOH_LCKR_RESET ((uint32_t)0x00000000) +#define GPIOI_LCKR_RESET ((uint32_t)0x00000000) + +#define GPIOA_AFRL_RESET ((uint32_t)0x00000000) +#define GPIOB_AFRL_RESET ((uint32_t)0x00000000) +#define GPIOC_AFRL_RESET ((uint32_t)0x00000000) +#define GPIOD_AFRL_RESET ((uint32_t)0x00000000) +#define GPIOE_AFRL_RESET ((uint32_t)0x00000000) +#define GPIOF_AFRL_RESET ((uint32_t)0x00000000) +#define GPIOG_AFRL_RESET ((uint32_t)0x00000000) +#define GPIOH_AFRL_RESET ((uint32_t)0x00000000) +#define GPIOI_AFRL_RESET ((uint32_t)0x00000000) + +#define GPIOA_AFRH_RESET ((uint32_t)0x00000000) +#define GPIOB_AFRH_RESET ((uint32_t)0x00000000) +#define GPIOC_AFRH_RESET ((uint32_t)0x00000000) +#define GPIOD_AFRH_RESET ((uint32_t)0x00000000) +#define GPIOE_AFRH_RESET ((uint32_t)0x00000000) +#define GPIOF_AFRH_RESET ((uint32_t)0x00000000) +#define GPIOG_AFRH_RESET ((uint32_t)0x00000000) +#define GPIOH_AFRH_RESET ((uint32_t)0x00000000) +#define GPIOI_AFRH_RESET ((uint32_t)0x00000000) + +/* Definition of the alternate functions used + * for GPIOs. See Figure 14 "Selecting an alternate function" + * in the datasheet. + */ +/* AF0 (system) */ +#define GPIO_AF_AF0 0x0 +#define GPIO_AF_SYSTEM GPIO_AF_AF0 +/* AF1 (TIM1/TIM2) */ +#define GPIO_AF_AF1 0x1 +#define GPIO_AF_TIM1 GPIO_AF_AF1 +#define GPIO_AF_TIM2 GPIO_AF_AF1 +/* AF2 (TIM3..5) */ +#define GPIO_AF_AF2 0x2 +#define GPIO_AF_TIM3 GPIO_AF_AF2 +#define GPIO_AF_TIM4 GPIO_AF_AF2 +#define GPIO_AF_TIM5 GPIO_AF_AF2 +/* AF3 (TIM8..11) */ +#define GPIO_AF_AF3 0x3 +#define GPIO_AF_TIM8 GPIO_AF_AF3 +#define GPIO_AF_TIM9 GPIO_AF_AF3 +#define GPIO_AF_TIM10 GPIO_AF_AF3 +#define GPIO_AF_TIM11 GPIO_AF_AF3 +/* AF4 (I2C1..3) */ +#define GPIO_AF_AF4 0x4 +#define GPIO_AF_I2C1 GPIO_AF_AF4 +#define GPIO_AF_I2C2 GPIO_AF_AF4 +#define GPIO_AF_I2C3 GPIO_AF_AF4 +/* AF5 (SPI1/SPI2) */ +#define GPIO_AF_AF5 0x5 +#define GPIO_AF_SPI1 GPIO_AF_AF5 +#define GPIO_AF_SPI2 GPIO_AF_AF5 +/* AF6 (SPI3) */ +#define GPIO_AF_AF6 0x6 +#define GPIO_AF_SPI3 GPIO_AF_AF6 +/* AF7 (USART1..3) */ +#define GPIO_AF_AF7 0x7 +#define GPIO_AF_USART1 GPIO_AF_AF7 +#define GPIO_AF_USART2 GPIO_AF_AF7 +#define GPIO_AF_USART3 GPIO_AF_AF7 +/* AF8 (USART4..6) */ +#define GPIO_AF_AF8 0x8 +#define GPIO_AF_USART4 GPIO_AF_AF8 +#define GPIO_AF_UART4 GPIO_AF_AF8 +#define GPIO_AF_USART5 GPIO_AF_AF8 +#define GPIO_AF_UART5 GPIO_AF_AF8 +#define GPIO_AF_USART6 GPIO_AF_AF8 +/* AF9 (CAN1/CAN2, TIM12..14) */ +#define GPIO_AF_AF9 0x9 +#define GPIO_AF_CAN1 GPIO_AF_AF9 +#define GPIO_AF_CAN2 GPIO_AF_AF9 +#define GPIO_AF_TIM12 GPIO_AF_AF9 +#define GPIO_AF_TIM13 GPIO_AF_AF9 +#define GPIO_AF_TIM14 GPIO_AF_AF9 +/* AF10 (OTG_FS, OTG_HS) */ +#define GPIO_AF_AF10 0xa +#define GPIO_AF_OTG_FS GPIO_AF_AF10 +#define GPIO_AF_OTG_HS GPIO_AF_AF10 +/* AF11 (ETH) */ +#define GPIO_AF_AF11 0xb +#define GPIO_AF_ETH GPIO_AF_AF11 +/* AF12 (FSMC, SDIO, OTG_HS_FS) */ +#define GPIO_AF_AF12 0xc +#define GPIO_AF_FSMC GPIO_AF_AF12 +#define GPIO_AF_SDIO GPIO_AF_AF12 +#define GPIO_AF_OTG_HS_FS GPIO_AF_AF12 +/* AF13 (DCMI) */ +#define GPIO_AF_AF13 0xd +#define GPIO_AF_DCMI GPIO_AF_AF13 +/* AF14 */ +#define GPIO_AF_AF14 0xe +/* AF15 (EVENTOUT) */ +#define GPIO_AF_AF15 0xf +#define GPIO_AF_EVENTOUT GPIO_AF_AF15 + +/* + * Configure a GPIO given an associated structure, including + * a configuration mask + */ +uint8_t soc_gpio_set_config(const dev_gpio_info_t * gpio); + +uint8_t soc_gpio_configure + (uint8_t port, uint8_t pin, + gpio_mode_t mode, + gpio_type_t type, + gpio_speed_t speed, + gpio_pupd_t pupd, + gpio_af_t afr); + +/* + * GPIO value accessors (set, get, clear) + */ +void soc_gpio_set_value(gpioref_t kref, + uint8_t value); + +void soc_gpio_set(gpioref_t kref); + +uint8_t soc_gpio_get(gpioref_t kref); + +void soc_gpio_clear(gpioref_t kref); + +#endif/*!SOC_GPIO_H */ diff --git a/arch/socs/stm32f439/soc-init.c b/arch/socs/stm32f439/soc-init.c new file mode 100644 index 0000000..91dc53f --- /dev/null +++ b/arch/socs/stm32f439/soc-init.c @@ -0,0 +1,71 @@ +/* \file soc-init.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "m4-cpu.h" +#include "soc-init.h" +#include "soc-flash.h" +#include "soc-pwr.h" +#include "soc-scb.h" +#include "soc-rcc.h" +#include "product.h" +#include "debug.h" +#include "autoconf.h" + +/* + * \brief Configure the Vector Table location and offset address + * + * WARNING : No interrupts here => IRQs disabled + * => No LOGs here + */ +void set_vtor(uint32_t addr) +{ + + __DMB(); /* Data Memory Barrier */ +#ifdef CONFIG_STM32F4 + write_reg_value(r_CORTEX_M_SCB_VTOR, addr); +#endif + __DSB(); /* + * Data Synchronization Barrier to ensure all + * subsequent instructions use the new configuration + */ +} + +/* void system_init(void) + * \brief Setup the microcontroller system + * + * Initialize the Embedded Flash Interface, the PLL and update the + * SystemFrequency variable. + */ +void system_init(uint32_t addr) +{ +#ifdef CONFIG_STM32F4 + soc_rcc_reset(); + /* + * Configure the System clock source, PLL Multiplier and Divider factors, + * AHB/APBx prescalers and Flash settings + */ + soc_rcc_setsysclock(); +#endif + + //set_vtor(FLASH_BASE|VECT_TAB_OFFSET); + set_vtor(addr); +} diff --git a/arch/socs/stm32f439/soc-init.h b/arch/socs/stm32f439/soc-init.h new file mode 100644 index 0000000..560ab39 --- /dev/null +++ b/arch/socs/stm32f439/soc-init.h @@ -0,0 +1,45 @@ +/* \file soc-init.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_INIT_H +#define SOC_INIT_H + +#include "types.h" +#include "product.h" +#include "soc-rcc.h" +#include "soc-rcc.h" + +#define RESET 0 +#define SET 1 + +#if !defined (HSE_STARTUP_TIMEOUT) +#define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500) +#endif /* !HSE_STARTUP_TIMEOUT */ + +#if !defined (HSI_STARTUP_TIMEOUT) +#define HSI_STARTUP_TIMEOUT ((uint16_t)0x0500) +#endif /* !HSI_STARTUP_TIMEOUT */ + +void set_vtor(uint32_t); +void system_init(uint32_t); + +#endif/*!SOC_INIT_H*/ diff --git a/arch/socs/stm32f439/soc-interrupts.c b/arch/socs/stm32f439/soc-interrupts.c new file mode 100644 index 0000000..ac47d78 --- /dev/null +++ b/arch/socs/stm32f439/soc-interrupts.c @@ -0,0 +1,196 @@ +/* \file soc-interrupts.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "m4-systick.h" +#include "m4-core.h" +#include "soc-interrupts.h" +#include "soc-dwt.h" +#include "soc-nvic.h" +#include "soc-scb.h" +#include "devices-shared.h" +#include "debug.h" +#include "kernel.h" +#include "isr.h" +#include "default_handlers.h" + +#ifdef KERNEL +#include "tasks.h" +#include "sched.h" +#include "layout.h" +#endif + +/* +** Default IRQ mapping. This permit to each handler to detect +** if the effective IRQ handling has to be executed by a userspace task that +** have registered the IRQ as its own. If yes, the handler must: +** 1) update the memory mapping to be conform to the task memory mapping constraints +** 2) Change mode to usermode and execute fn +** 3) when coming back from fn, reloading the kernel memory map +** +** Some handlers are set here to be correctly set at boot time (e.g. Systick handler) +*/ +static s_irq irq_table[] = { + // ARM VTORS start with reset Stack (MSP) + {ESTACK, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + // Should never be called from here + {RESET_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {NMI_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {HARDFAULT_IRQ, HardFault_Handler, ID_UNUSED, ID_DEV_UNUSED, 0}, + {MEMMANAGE_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {BUSFAULT_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {USAGEFAULT_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {VOID1_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {VOID2_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {VOID3_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {VOID4_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {SVC_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DEBUGON_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {VOID5_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {PENDSV_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {SYSTICK_IRQ, core_systick_handler, ID_UNUSED, ID_DEV_UNUSED, 0}, + {WWDG_IRQ, WWDG_IRQ_Handler, ID_UNUSED, ID_DEV_UNUSED, 0}, // 0x10 + {PVD_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TAMP_STAMP_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {RTC_WKUP_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {FLASH_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {RCC_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {EXTI0_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {EXTI1_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {EXTI2_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {EXTI3_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {EXTI4_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA1_Stream0_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA1_Stream1_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA1_Stream2_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA1_Stream3_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA1_Stream4_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA1_Stream5_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, // 0x20 + {DMA1_Stream6_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {ADC_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {CAN1_TX_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {CAN1_RX0_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {CAN1_RX1_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {CAN1_SCE_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {EXTI9_5_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM1_BRK_TIM9_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM1_UP_TIM10_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM1_TRG_COM_TIM11_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM1_CC_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM2_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM3_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM4_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {I2C1_EV_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {I2C1_ER_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, // 0x30 + {I2C2_EV_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {I2C2_ER_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {SPI1_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {SPI2_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {USART1_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {USART2_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {USART3_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {EXTI15_10_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {RTC_Alarm_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {OTG_FS_WKUP_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM8_BRK_TIM12_IRQ,NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM8_UP_TIM13_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM8_TRG_COM_TIM14_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM8_CC_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA1_Stream7_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {FSMC_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, // 0x40 + {SDIO_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM5_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {SPI3_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {UART4_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {UART5_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM6_DAC_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {TIM7_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA2_Stream0_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA2_Stream1_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA2_Stream2_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA2_Stream3_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA2_Stream4_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {ETH_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {ETH_WKUP_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {CAN2_TX_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {CAN2_RX0_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, // 0x50 + {CAN2_RX1_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {CAN2_SCE_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {OTG_FS_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA2_Stream5_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA2_Stream6_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DMA2_Stream7_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {USART6_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {I2C3_EV_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {I2C3_ER_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {OTG_HS_EP1_OUT_IRQ,NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {OTG_HS_EP1_IN_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {OTG_HS_WKUP_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {OTG_HS_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {DCMI_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {CRYP_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, + {HASH_RNG_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, // 0x60 + {FPU_IRQ, NULL, ID_UNUSED, ID_DEV_UNUSED, 0}, +}; + +bool is_interrupt_already_used (e_irq_id id) +{ + if (irq_table[id].task_id != ID_UNUSED) { + return true; + } else { + return false; + } +} + +/* +** Register a custom handler for a given interrupt +*/ +uint8_t set_interrupt_handler + (e_irq_id id, const void *irq_handler, e_task_id task_id, e_device_id dev_id) +{ + if (irq_handler == NULL) { + return 1; + } + + if (irq_table[id].irq_handler != NULL) { + KERNLOG(DBG_DEBUG, "INT %d irq_handler_set(): replacing an existing handler (%x) by a new handler in %x\n", + id, irq_table[id].irq_handler, irq_handler); + dbg_flush(); + } + + /* Registering task's handler */ + irq_table[id].irq_handler = irq_handler; + irq_table[id].task_id = task_id; + irq_table[id].device_id = dev_id; + + return 0; +} + +e_device_id get_device_from_interrupt(e_irq_id id) +{ + return irq_table[id].device_id; +} + +s_irq* get_cell_from_interrupt(e_irq_id id) +{ + return &irq_table[id]; +} + diff --git a/arch/socs/stm32f439/soc-interrupts.h b/arch/socs/stm32f439/soc-interrupts.h new file mode 100644 index 0000000..6a868eb --- /dev/null +++ b/arch/socs/stm32f439/soc-interrupts.h @@ -0,0 +1,175 @@ +/* \file soc_irq.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_IRQ_ +#define SOC_IRQ_ + +#include "types.h" +#include "../../../tasks-shared.h" +#include "../../../devices-shared.h" + +/* +** That structure points to the saved registers on the caller +** (mostly a user task) stack. +*/ + +typedef struct { + uint32_t r4, r5, r6, r7, r8, r9, r10, r11, lr; + uint32_t r0, r1, r2, r3, r12, prev_lr, pc, xpsr; +} __attribute__ ((packed)) stack_frame_t; + +/* +** This permit the bellowing table to be used by a given IRQ handler +** e.g. s_irq[USART1_IRQ].fn give the custom handler pointer if it exists +*/ +typedef enum { + ESTACK = 0, + RESET_IRQ, + NMI_IRQ, + HARDFAULT_IRQ, + MEMMANAGE_IRQ, + BUSFAULT_IRQ, + USAGEFAULT_IRQ, + VOID1_IRQ, + VOID2_IRQ, + VOID3_IRQ, + VOID4_IRQ, + SVC_IRQ, + DEBUGON_IRQ, + VOID5_IRQ, + PENDSV_IRQ, + SYSTICK_IRQ, + WWDG_IRQ, + PVD_IRQ, + TAMP_STAMP_IRQ, + RTC_WKUP_IRQ, + FLASH_IRQ, + RCC_IRQ, + EXTI0_IRQ, + EXTI1_IRQ, + EXTI2_IRQ, + EXTI3_IRQ, + EXTI4_IRQ, + DMA1_Stream0_IRQ, + DMA1_Stream1_IRQ, + DMA1_Stream2_IRQ, + DMA1_Stream3_IRQ, + DMA1_Stream4_IRQ, + DMA1_Stream5_IRQ, + DMA1_Stream6_IRQ, + ADC_IRQ, + CAN1_TX_IRQ, + CAN1_RX0_IRQ, + CAN1_RX1_IRQ, + CAN1_SCE_IRQ, + EXTI9_5_IRQ, + TIM1_BRK_TIM9_IRQ, + TIM1_UP_TIM10_IRQ, + TIM1_TRG_COM_TIM11_IRQ, + TIM1_CC_IRQ, + TIM2_IRQ, + TIM3_IRQ, + TIM4_IRQ, + I2C1_EV_IRQ, + I2C1_ER_IRQ, + I2C2_EV_IRQ, + I2C2_ER_IRQ, + SPI1_IRQ, + SPI2_IRQ, + USART1_IRQ, + USART2_IRQ, + USART3_IRQ, + EXTI15_10_IRQ, + RTC_Alarm_IRQ, + OTG_FS_WKUP_IRQ, + TIM8_BRK_TIM12_IRQ, + TIM8_UP_TIM13_IRQ, + TIM8_TRG_COM_TIM14_IRQ, + TIM8_CC_IRQ, + DMA1_Stream7_IRQ, + FSMC_IRQ, + SDIO_IRQ, + TIM5_IRQ, + SPI3_IRQ, + UART4_IRQ, + UART5_IRQ, + TIM6_DAC_IRQ, + TIM7_IRQ, + DMA2_Stream0_IRQ, + DMA2_Stream1_IRQ, + DMA2_Stream2_IRQ, + DMA2_Stream3_IRQ, + DMA2_Stream4_IRQ, + ETH_IRQ, + ETH_WKUP_IRQ, + CAN2_TX_IRQ, + CAN2_RX0_IRQ, + CAN2_RX1_IRQ, + CAN2_SCE_IRQ, + OTG_FS_IRQ, + DMA2_Stream5_IRQ, + DMA2_Stream6_IRQ, + DMA2_Stream7_IRQ, + USART6_IRQ, + I2C3_EV_IRQ, + I2C3_ER_IRQ, + OTG_HS_EP1_OUT_IRQ, + OTG_HS_EP1_IN_IRQ, + OTG_HS_WKUP_IRQ, + OTG_HS_IRQ, + DCMI_IRQ, + CRYP_IRQ, + HASH_RNG_IRQ, + FPU_IRQ, +} e_irq_id; + +static const e_irq_id USER_IRQ_MIN = PVD_IRQ; +static const e_irq_id USER_IRQ_MAX = HASH_RNG_IRQ; + +typedef stack_frame_t *(*irq_handler_t) (stack_frame_t *); + +typedef struct { + e_irq_id irq; /* IRQ number */ + irq_handler_t irq_handler; /* IRQ handler */ + e_task_id task_id; + e_device_id device_id; + uint32_t count; /* How many times that IRQ interrupted the CPU ? */ +} s_irq; + +#define interrupt_get_num(intr) { asm volatile ("mrs r1, ipsr\n\t" \ + "mov %0, r1\n\t" \ + : "=r" (intr) :: "r1" ); } + +/* Return true if a task has already registered an interrupt handler */ +bool is_interrupt_already_used (e_irq_id id); + +/* +** Register a custom handler for a given interrupt +*/ +uint8_t set_interrupt_handler + (e_irq_id id, const void *irq_handler, e_task_id task_id, e_device_id dev_id); + +e_device_id get_device_from_interrupt(e_irq_id id); + +s_irq* get_cell_from_interrupt(e_irq_id id); + +#endif /*!SOC_IRQ_ */ diff --git a/arch/socs/stm32f439/soc-iwdg.c b/arch/socs/stm32f439/soc-iwdg.c new file mode 100644 index 0000000..8537477 --- /dev/null +++ b/arch/socs/stm32f439/soc-iwdg.c @@ -0,0 +1,64 @@ +/* \file soc-iwdg.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "debug.h" +#include "soc-iwdg.h" + +void soc_iwdg_start(void) +{ + set_reg(r_CORTEX_M_IWDG_KR, IWDG_KR_KEY_START, IWDG_KR_KEY); + LOG("Watchdog started"); +} + +void soc_iwdg_feed(void) +{ + set_reg(r_CORTEX_M_IWDG_KR, IWDG_KR_KEY_FEED, IWDG_KR_KEY); +} + +void soc_iwdg_set_prescaler(uint32_t prescaler) +{ + assert(prescaler >= 4 && prescaler <= 256); + uint32_t first_power_of_two = 0; + + set_reg(r_CORTEX_M_IWDG_KR, IWDG_KR_KEY_WRITE_ACCESS, IWDG_KR_KEY); + while (get_reg(r_CORTEX_M_IWDG_SR, IWDG_SR_PVU)) + continue; + + while (first_power_of_two <= 8 && !(prescaler & 1)) { + prescaler >>= 1; + first_power_of_two++; + } + + prescaler = first_power_of_two - 2; + set_reg(r_CORTEX_M_IWDG_PR, prescaler, IWDG_PR_PR); + LOG("New prescaler is %x", prescaler); +} + +void soc_iwdg_set_reload_value(uint32_t value) +{ + set_reg(r_CORTEX_M_IWDG_KR, IWDG_KR_KEY_WRITE_ACCESS, IWDG_KR_KEY); + while (get_reg(r_CORTEX_M_IWDG_SR, IWDG_SR_RVU)) + continue; + set_reg(r_CORTEX_M_IWDG_RLR, value, IWDG_RLR_RL); + LOG("New reload value is %x", value); +} diff --git a/arch/socs/stm32f439/soc-iwdg.h b/arch/socs/stm32f439/soc-iwdg.h new file mode 100644 index 0000000..6a8157b --- /dev/null +++ b/arch/socs/stm32f439/soc-iwdg.h @@ -0,0 +1,59 @@ +/* \file soc-iwdg.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_IWDG_H +#define SOC_IWDG_H + +#include "soc-core.h" + +#define r_CORTEX_M_IWDG_KR REG_ADDR(IWDG_BASE + 0x0) +#define r_CORTEX_M_IWDG_PR REG_ADDR(IWDG_BASE + 0x4) +#define r_CORTEX_M_IWDG_RLR REG_ADDR(IWDG_BASE + 0x8) +#define r_CORTEX_M_IWDG_SR REG_ADDR(IWDG_BASE + 0xc) + +/* Key register */ +#define IWDG_KR_KEY_Pos 0 +#define IWDG_KR_KEY_Msk ((uint32_t)0xffff << IWDG_KR_KEY_Pos) +# define IWDG_KR_KEY_FEED 0xaaaa +# define IWDG_KR_KEY_WRITE_ACCESS 0x5555 +# define IWDG_KR_KEY_START 0xcccc + +/* Prescaler register */ +#define IWDG_PR_PR_Pos 0 +#define IWDG_PR_PR_Msk ((uint32_t)0x7 << IWDG_PR_PR_Pos) + +/* Reload register */ +#define IWDG_RLR_RL_Pos 0 +#define IWDG_RLR_RL_Msk ((uint32_t)0xfff << IWDG_RLR_RL_Pos) + +/* Status register */ +#define IWDG_SR_RVU_Pos 0 +#define IWDG_SR_RVU_Msk ((uint32_t)1 << IWDG_SR_RVU_Pos) +#define IWDG_SR_PVU_Pos 1 +#define IWDG_SR_PVU_Msk ((uint32_t)1 << IWDG_SR_PVU_Pos) + +void soc_iwdg_start(void); +void soc_iwdg_feed(void); +void soc_iwdg_set_prescaler(uint32_t prescaler); +void soc_iwdg_set_reload_value(uint32_t value); + +#endif /* !STM32F4XX_IWDG_H */ diff --git a/arch/socs/stm32f439/soc-layout.h b/arch/socs/stm32f439/soc-layout.h new file mode 100644 index 0000000..41282ef --- /dev/null +++ b/arch/socs/stm32f439/soc-layout.h @@ -0,0 +1,226 @@ +/* \file soc-layout.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_LAYOUT_H +#define SOC_LAYOUT_H + +#include "autoconf.h" +#include "m4-mpu-regions.h" + +/* +** About the mapping: here is the flash layout described below +** +** +----------------+0x0800 0000 +** | LDR (32k) | +** +----------------+0x0800 8000 +** | SHR (32k) | +** +----------------+0x0801 0000 +** | DFU1_k (64k) | +** + - - - - - - - -+0x0802 0000 +** | DFU1_u (64k) | +** +----------------+0x0803 0000 +** | FW1_k (64k) | +** + - - - - - - - -+0x0804 0000 +** | | +** | FW1_u (256k) | +** | | +** +----------------+0x0808 0000 +** | | +** | FW2_u (256k) | +** | | +** + - - - - - - - -+0x080c 0000 +** | FW2_k (64k) | +** +----------------+0x080d 0000 +** | DFU2_k (64k) | +** + - - - - - - - -+0x080e 0000 +** | DFU2_u (64k) | +** +----------------+0x080f 0000 +** +** This "mirror" mapping of FW1 & FW2 is due to the MPU constraint that +** requires that the MPU region base address should be a multiple of its +** size 0x0804 0000 & 0x0808 0000 are the lonely multiple of 256k. +** +*/ + +#ifdef CONFIG_STM32F4 +#define NB_MEM_BANK 1 +#elif defined CONFIG_STM32F42X +#define NB_MEM_BANK 2 +#else +#error "unknown SoC reference layout" +#endif + + +#define KBYTE 1024 +#define FLASH_SIZE 1024*KBYTE +#define VTORS_SIZE 0x188 + +/* + * Mapping + */ +#define LDR_BASE 0x08000000 /* loader */ +#define SHR_BASE 0x08008000 /* shared memory */ + +#define RAM2_BASE 0x10000000 +#define RAM_KERN_BASE 0x10000000 /* 96k user RAM (div by 8 subregions, 12*8, 24*4), starting at RAM size + 32k */ + +/* User tasks */ +#define RAM_BASE 0x20000000 /* 24k kernel RAM + 8k empty */ +#define RAM_USER_BASE RAM_BASE /* 96k user RAM (div by 8 subregions, 12*8, 24*4), starting at RAM size + 32k */ +#define RAM_USER_REGION_SIZE MPU_REGION_SIZE_128Kb /* 96k user RAM (div by 8 subregions, 12*8, 24*4), starting at RAM size + 32k */ + +#define RAM_USER_APPS_BASE RAM_BASE +#define RAM_USER_SIZE 16*KBYTE +#define RAM_USER_APP1_BASE RAM_USER_APPS_BASE +#define RAM_USER_APP2_BASE RAM_USER_APP1_BASE + RAM_USER_SIZE +#define RAM_USER_APP3_BASE RAM_USER_APP2_BASE + RAM_USER_SIZE +#define RAM_USER_APP4_BASE RAM_USER_APP3_BASE + RAM_USER_SIZE +#define RAM_USER_APP5_BASE RAM_USER_APP4_BASE + RAM_USER_SIZE +#define RAM_USER_APP6_BASE RAM_USER_APP5_BASE + RAM_USER_SIZE +#define RAM_USER_APP7_BASE RAM_USER_APP6_BASE + RAM_USER_SIZE +#define RAM_USER_APP8_BASE RAM_USER_APP7_BASE + RAM_USER_SIZE + +#define FW1_APP1_BASE 0x08080000 +#define FW1_APP2_BASE 0x08090000 +#define FW1_APP3_BASE 0x080a0000 +#define FW1_APP4_BASE 0x080b0000 +#define FW1_APP5_BASE 0x080c0000 +#define FW1_APP6_BASE 0x080d0000 +#define FW1_APP7_BASE 0x080e0000 +#define FW1_APP8_BASE 0x080f0000 + +#define FW2_APP1_BASE 0x09080000 +#define FW2_APP2_BASE 0x09090000 +#define FW2_APP3_BASE 0x090a0000 +#define FW2_APP4_BASE 0x090b0000 +#define FW2_APP5_BASE 0x090c0000 +#define FW2_APP6_BASE 0x090d0000 +#define FW2_APP7_BASE 0x090e0000 +#define FW2_APP8_BASE 0x090f0000 + +#define DFU1_APP1_BASE 0x08040000 +#define DFU1_APP2_BASE 0x08048000 +#define DFU1_APP3_BASE 0x08050000 +#define DFU1_APP4_BASE 0x08058000 +#define DFU1_APP5_BASE 0x08060000 +#define DFU1_APP6_BASE 0x08068000 +#define DFU1_APP7_BASE 0x08070000 +#define DFU1_APP8_BASE 0x08078000 + +#define DFU2_APP1_BASE 0x09040000 +#define DFU2_APP2_BASE 0x09048000 +#define DFU2_APP3_BASE 0x09050000 +#define DFU2_APP4_BASE 0x09058000 +#define DFU2_APP5_BASE 0x09060000 +#define DFU2_APP6_BASE 0x09068000 +#define DFU2_APP7_BASE 0x09070000 +#define DFU2_APP8_BASE 0x09078000 + + +/* LDR is in the last sub-region (slot 8) */ +#define RAM_LDR_BASE 0x2001c000 +#define RAM_LDR_SIZE 20*KBYTE + +/* + * STM32F4 + */ + +/* Flip bank */ + +#define FW1_SIZE 576*KBYTE + +#define FW1_KERN_BASE 0x08020000 +#define FW1_KERN_SIZE 64*KBYTE +#define FW1_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb + +#define FW1_USER_BASE 0x08080000 +#define FW1_USER_SIZE 512*KBYTE +#define FW1_USER_REGION_SIZE MPU_REGION_SIZE_512Kb + +/**** DFU 1 ****/ + +#define DFU1_SIZE 320*KBYTE + +#define DFU1_KERN_BASE 0x08030000 +#define DFU1_USER_BASE 0x08040000 + +#define DFU1_KERN_SIZE 64*KBYTE +#define DFU1_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb +#define DFU1_USER_SIZE 256*KBYTE +#define DFU1_USER_REGION_SIZE MPU_REGION_SIZE_256Kb + + +/* Flop bank */ + +#define FW2_SIZE 576*KBYTE + +#define FW2_KERN_SIZE 64*KBYTE +#define FW2_KERN_BASE 0x09020000 +#define FW2_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb +#define FW2_USER_BASE 0x09080000 +#define FW2_USER_SIZE 512*KBYTE +# define FW2_USER_REGION_SIZE MPU_REGION_SIZE_512Kb + +/**** DFU 2 ****/ +#define DFU2_SIZE 320*KBYTE + +#define DFU2_KERN_BASE 0x09030000 +#define DFU2_KERN_SIZE 64*KBYTE + +#define DFU2_USER_BASE 0x09040000 +#define DFU2_USER_SIZE 256*KBYTE +#define DFU2_KERN_REGION_SIZE MPU_REGION_SIZE_256Kb + + + +#define RAM2_SIZE 64*KBYTE +#define RAM_KERN_SIZE RAM2_SIZE +#define RAM_KERN_REGION_SIZE MPU_REGION_SIZE_64Kb +#define LDR_SIZE 128*KBYTE + + +#define MB1_BASE 0x60000000 +#define MB2_BASE 0x60000000 +#define MB1_SIZE 0 +#define MB2_SIZE 0 + + +#define FW1_START FW1_KERN_BASE + VTORS_SIZE + 1 + +#define FW2_START FW2_KERN_BASE + VTORS_SIZE + 1 + +#define DFU1_START DFU1_KERN_BASE + VTORS_SIZE + 1 + +#define DFU2_START DFU2_KERN_BASE + VTORS_SIZE + 1 + +#define FW_MAX_USER_SIZE 64*KBYTE +#define DFU_MAX_USER_SIZE 32*KBYTE + + +/**** Shared mem ****/ +#define SHR_SIZE 32*KBYTE + +/**** SRAM ****/ +#define RAM_SIZE 128*KBYTE + + +#endif /*!SOC_LAYOUT_H*/ diff --git a/arch/socs/stm32f439/soc-nvic.h b/arch/socs/stm32f439/soc-nvic.h new file mode 100644 index 0000000..6ab6a10 --- /dev/null +++ b/arch/socs/stm32f439/soc-nvic.h @@ -0,0 +1,247 @@ +/* \file soc-nvic.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_NVIC_H +#define SOC_NVIC_H + +#include "m4-cpu.h" +#include "soc-core.h" +#include "soc-exti.h" +#include "soc-scb.h" + +/* + * NVIC register block is 0xE000E100. The NVIC_STIR register is located in a separate block at 0xE000EF00. + * + * The NVIC supports: + * • Up to 81 interrupts (interrupt number depends on the STM32 device type; + * refer to the datasheets) + * + * • A programmable priority level of 0-15 for each interrupt. + * A higher level corresponds to a lower priority, so level 0 is the highest interrupt priority + * + * • Level and pulse detection of interrupt signals + * + * • Dynamic reprioritization of interrupts + * + * • Grouping of priority values into group priority and subpriority fields + * + * • Interrupt tail-chaining + * + * • An external Non-maskable interrupt (NMI) + * + * The processor automatically stacks its state on exception entry and unstacks this state on + * exception exit, with no instruction overhead. + */ + +/* 0xE000E100-0xE000E10B NVIC_ISER0-NVIC_ISER2 (RW Privileged) Interrupt set-enable registers */ +#define r_CORTEX_M_NVIC_ISER0 REG_ADDR(NVIC_BASE + (uint32_t)0x00) +#define r_CORTEX_M_NVIC_ISER1 REG_ADDR(NVIC_BASE + (uint32_t)0x04) +#define r_CORTEX_M_NVIC_ISER2 REG_ADDR(NVIC_BASE + (uint32_t)0x08) +/* 0XE000E180-0xE000E18B NVIC_ICER0-NVIC_ICER2 (RW Privileged) Interrupt clear-enable registers */ +#define r_CORTEX_M_NVIC_ICER0 REG_ADDR(NVIC_BASE + (uint32_t)0x80) +#define r_CORTEX_M_NVIC_ICER1 REG_ADDR(NVIC_BASE + (uint32_t)0x84) +#define r_CORTEX_M_NVIC_ICER2 REG_ADDR(NVIC_BASE + (uint32_t)0x88) +/* 0XE000E200-0xE000E20B NVIC_ISPR0-NVIC_ISPR2 (RW Privileged) Interrupt set-pending registers */ +#define r_CORTEX_M_NVIC_ISPR0 REG_ADDR(NVIC_BASE + (uint32_t)0x100) +#define r_CORTEX_M_NVIC_ISPR1 REG_ADDR(NVIC_BASE + (uint32_t)0x104) +#define r_CORTEX_M_NVIC_ISPR2 REG_ADDR(NVIC_BASE + (uint32_t)0x108) +/* 0XE000E280-0xE000E29C NVIC_ICPR0-NVIC_ICPR2 (RW Privileged) Interrupt clear-pending registers */ +#define r_CORTEX_M_NVIC_ICPR0 REG_ADDR(NVIC_BASE + (uint32_t)0x180) +#define r_CORTEX_M_NVIC_ICPR1 REG_ADDR(NVIC_BASE + (uint32_t)0x184) +#define r_CORTEX_M_NVIC_ICPR2 REG_ADDR(NVIC_BASE + (uint32_t)0x188) +/* 0xE000E300-0xE000E31C NVIC_IABR0-NVIC_IABR2 (RW Privileged) Interrupt active bit registers */ +#define r_CORTEX_M_NVIC_IABR0 REG_ADDR(NVIC_BASE + (uint32_t)0x200) +#define r_CORTEX_M_NVIC_IABR1 REG_ADDR(NVIC_BASE + (uint32_t)0x204) +#define r_CORTEX_M_NVIC_IABR2 REG_ADDR(NVIC_BASE + (uint32_t)0x208) +/* 0xE000E400-0xE000E503 NVIC_IPR0-NVIC_IPR20 (RW Privileged)Interrupt priority registers */ +#define r_CORTEX_M_NVIC_IPR0 REG_ADDR(NVIC_BASE + (uint32_t)0x300) +#define r_CORTEX_M_NVIC_IPR1 REG_ADDR(NVIC_BASE + (uint32_t)0x301) +#define r_CORTEX_M_NVIC_IPR2 REG_ADDR(NVIC_BASE + (uint32_t)0x302) +#define r_CORTEX_M_NVIC_IPR3 REG_ADDR(NVIC_BASE + (uint32_t)0x303) +#define r_CORTEX_M_NVIC_IPR4 REG_ADDR(NVIC_BASE + (uint32_t)0x304) +#define r_CORTEX_M_NVIC_IPR5 REG_ADDR(NVIC_BASE + (uint32_t)0x305) +#define r_CORTEX_M_NVIC_IPR6 REG_ADDR(NVIC_BASE + (uint32_t)0x306) +#define r_CORTEX_M_NVIC_IPR7 REG_ADDR(NVIC_BASE + (uint32_t)0x307) +#define r_CORTEX_M_NVIC_IPR8 REG_ADDR(NVIC_BASE + (uint32_t)0x308) +#define r_CORTEX_M_NVIC_IPR9 REG_ADDR(NVIC_BASE + (uint32_t)0x309) +#define r_CORTEX_M_NVIC_IPR10 REG_ADDR(NVIC_BASE + (uint32_t)0x310) +#define r_CORTEX_M_NVIC_IPR11 REG_ADDR(NVIC_BASE + (uint32_t)0x311) +#define r_CORTEX_M_NVIC_IPR12 REG_ADDR(NVIC_BASE + (uint32_t)0x312) +#define r_CORTEX_M_NVIC_IPR13 REG_ADDR(NVIC_BASE + (uint32_t)0x313) +#define r_CORTEX_M_NVIC_IPR14 REG_ADDR(NVIC_BASE + (uint32_t)0x314) +#define r_CORTEX_M_NVIC_IPR15 REG_ADDR(NVIC_BASE + (uint32_t)0x315) +#define r_CORTEX_M_NVIC_IPR16 REG_ADDR(NVIC_BASE + (uint32_t)0x316) +#define r_CORTEX_M_NVIC_IPR17 REG_ADDR(NVIC_BASE + (uint32_t)0x317) +#define r_CORTEX_M_NVIC_IPR18 REG_ADDR(NVIC_BASE + (uint32_t)0x318) +#define r_CORTEX_M_NVIC_IPR19 REG_ADDR(NVIC_BASE + (uint32_t)0x310) +#define r_CORTEX_M_NVIC_IPR20 REG_ADDR(NVIC_BASE + (uint32_t)0x320) +#define r_CORTEX_M_NIVIC_STIR REG_ADDR(NVIC_STIR_BASE) /* 0xE000EF00 (WO Configurable) Software trigger interrupt register */ + +/* Interrupt set-enable registers (NVIC_ISERx) */ +#define NVIC_ISER_SETENA REG_ADDR(r_CORTEX_M_NVIC_ISER0) + +/* Interrupt clear-enable registers (NVIC_ICERx) */ +#define NVIC_ICER REG_ADDR(r_CORTEX_M_NVIC_ICER0) + +/* Interrupt set-pending registers (NVIC_ISPRx) */ +#define NVIC_ISPR REG_ADDR(r_CORTEX_M_NVIC_ISPR0) + +/* Interrupt clear-pending registers (NVIC_ICPRx) */ +#define NVIC_ICPR REG_ADDR(r_CORTEX_M_NVIC_ICPR0) + +/* Interrupt active bit registers (NVIC_IABRx) */ +#define NVIC_IABR REG_ADDR(r_CORTEX_M_NVIC_IABR0) + +/* Interrupt priority registers (NVIC_IPRx) */ +#define NVIC_IPR REG_ADDR(r_CORTEX_M_NVIC_IPR0) + +/* Software trigger interrupt register (NVIC_STIR) */ +#define NVIC_STIR REG_ADDR(r_CORTEX_M_NIVIC_STIR) + +/* Interrupt set-enable registers */ +#define NVIC_ISER REG_ADDR(r_CORTEX_M_NVIC_ISER0) + +/* ########################## NVIC functions #################################### */ +/* \ingroup CMSIS_Core_FunctionInterface + * \defgroup CMSIS_Core_NVICFunctions CMSIS Core NVIC Functions + * @{ + */ + +/* \brief Set Priority Grouping + * This function sets the priority grouping field using the required unlock sequence. + * The parameter PriorityGroup is assigned to the field SCB_AIRCR [10:8] PRIGROUP field. + * Only values from 0..7 are used. + * In case of a conflict between priority grouping and available + * priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + * \param [in] PriorityGroup Priority grouping field + */ +__INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t) 0x07); /* only values 0..7 are used */ + + reg_value = *r_CORTEX_M_SCB_AIRCR; /* read old register configuration */ + reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk); /* clear bits to change */ + /* Insert write key and priority group */ + reg_value = + (reg_value | ((uint32_t) 0x5FA << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << 8)); + *r_CORTEX_M_SCB_AIRCR = reg_value; +} + +/* \brief Get Priority Grouping + * This function gets the priority grouping from NVIC Interrupt Controller. + * Priority grouping is SCB->AIRCR [10:8] PRIGROUP field. + * \return Priority grouping field + */ +__INLINE uint32_t NVIC_GetPriorityGrouping(void) +{ + return ((*r_CORTEX_M_SCB_AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos); /* read priority grouping field */ +} + +/* \brief Enable External Interrupt + * This function enables a device specific interrupt in the NVIC interrupt controller. + * The interrupt number cannot be a negative value. + * \param [in] IRQn Number of the external interrupt to enable + */ +__INLINE void NVIC_EnableIRQ(uint32_t IRQn) +{ + /* NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); enable interrupt */ + NVIC_ISER[(uint32_t) ((int32_t) IRQn) >> 5] = + (uint32_t) (1 << ((uint32_t) ((int32_t) IRQn) & (uint32_t) 0x1F)); +} + +/* \brief Disable External Interrupt + * This function disables a device specific interrupt in the NVIC interrupt controller. + * The interrupt number cannot be a negative value. + * \param [in] IRQn Number of the external interrupt to disable + */ +__INLINE void NVIC_DisableIRQ(uint32_t IRQn) +{ + NVIC_ICER[((uint32_t) (IRQn) >> 5)] = (uint32_t) (1 << ((uint32_t) (IRQn) & 0x1F)); /* disable interrupt */ +} + +/* \brief Get Pending Interrupt + * This function reads the pending register in the NVIC and returns the pending bit + * for the specified interrupt. + * \param [in] IRQn Number of the interrupt for get pending + * \return 0 Interrupt status is not pending + * \return 1 Interrupt status is pending + */ +__INLINE uint32_t NVIC_GetPendingIRQ(uint32_t IRQn) +{ + /* Return 1 if pending else 0 */ + return ((uint32_t) + ((NVIC_ISPR[(uint32_t) (IRQn) >> 5] & + (uint32_t) (1 << ((uint32_t) (IRQn) & 0x1F))) ? 1 : 0)); +} + +/* \brief Set Pending Interrupt + * + * This function sets the pending bit for the specified interrupt. + * The interrupt number cannot be a negative value. + * \param [in] IRQn Number of the interrupt for set pending + */ +__INLINE void NVIC_SetPendingIRQ(uint32_t IRQn) +{ + NVIC_ISPR[((uint32_t) (IRQn) >> 5)] = (uint32_t) (1 << ((uint32_t) (IRQn) & 0x1F)); /* set interrupt pending */ +} + +/* \brief Clear Pending Interrupt + * This function clears the pending bit for the specified interrupt. + * The interrupt number cannot be a negative value. + * \param [in] IRQn Number of the interrupt for clear pending + */ +__INLINE void NVIC_ClearPendingIRQ(uint32_t IRQn) +{ + NVIC_ICPR[((uint32_t) (IRQn) >> 5)] = (uint32_t) (1 << ((uint32_t) (IRQn) & 0x1F)); /* Clear pending interrupt */ +} + +/* \brief Get Active Interrupt + * This function reads the active register in NVIC and returns the active bit. + * \param [in] IRQn Number of the interrupt for get active + * \return 0 Interrupt status is not active + * \return 1 Interrupt status is active + */ +__INLINE uint32_t NVIC_GetActive(uint32_t IRQn) +{ + /* Return 1 if active else 0 */ + return ((uint32_t) + ((NVIC_IABR[(uint32_t) (IRQn) >> 5] & + (uint32_t) (1 << ((uint32_t) (IRQn) & 0x1F))) ? 1 : 0)); +} + +/* \brief System Reset + * This function initiate a system reset request to reset the MCU. + */ +__INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */ + *r_CORTEX_M_SCB_AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | (*r_CORTEX_M_SCB_AIRCR & SCB_AIRCR_PRIGROUP_Msk) | SCB_AIRCR_SYSRESETREQ_Msk); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + while (1) + continue; /* wait until reset */ +} + +/*@} end of CMSIS_Core_NVICFunctions */ + +#endif /*!SOC_NVIC_H */ diff --git a/arch/socs/stm32f439/soc-pwr.h b/arch/socs/stm32f439/soc-pwr.h new file mode 100644 index 0000000..d4db94b --- /dev/null +++ b/arch/socs/stm32f439/soc-pwr.h @@ -0,0 +1,80 @@ +/* \file soc-pwr.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_PWR_H +#define SOC_PWR_H + +#include "soc-core.h" + +/* + * XXX: These registers are defined for STM32F405xx/407xx and STM32F415xx/417xx + * only. Please refer to the programming manual section 5.5 for STM32F42xxx and + * STM32F43xxx). + */ +#define r_CORTEX_M_PWR_CR REG_ADDR(PWR_BASE + 0x00) +#define r_CORTEX_M_PWR_CSR REG_ADDR(PWR_BASE + 0x04) + +/* Power control register */ +#define PWR_CR_LPDS_Pos 0 +#define PWR_CR_LPDS_Msk ((uint32_t)1 << PWR_CR_LPDS_Pos) +#define PWR_CR_PDDS_Pos 1 +#define PWR_CR_PDDS_Msk ((uint32_t)1 << PWR_CR_PDDS_Pos) +#define PWR_CR_CWUF_Pos 2 +#define PWR_CR_CWUF_Msk ((uint32_t)1 << PWR_CR_CWUF_Pos) +#define PWR_CR_CSBF_Pos 3 +#define PWR_CR_CSBF_Msk ((uint32_t)1 << PWR_CR_CSBF_Pos) +#define PWR_CR_PVDE_Pos 4 +#define PWR_CR_PVDE_Msk ((uint32_t)1 << PWR_CR_PVDE_Pos) +#define PWR_CR_PLS_Pos 5 +#define PWR_CR_PLS_Msk ((uint32_t)7 << PWR_CR_PLS_Pos) +# define PWR_CR_PLS_2_0V 0 +# define PWR_CR_PLS_2_1V 1 +# define PWR_CR_PLS_2_3V 2 +# define PWR_CR_PLS_2_5V 3 +# define PWR_CR_PLS_2_6V 4 +# define PWR_CR_PLS_2_7V 5 +# define PWR_CR_PLS_2_8V 6 +# define PWR_CR_PLS_2_9V 7 +#define PWR_CR_DBP_Pos 8 +#define PWR_CR_DBP_Msk ((uint32_t)1 << PWR_CR_DBP_Pos) +#define PWR_CR_FPDS_Pos 9 +#define PWR_CR_FPDS_Msk ((uint32_t)1 << PWR_CR_FPDS_Pos) +#define PWR_CR_VOS_Pos 14 +#define PWR_CR_VOS_Msk ((uint32_t)1 << PWR_CR_VOS_Pos) + +/* Power control/status register */ +#define PWR_CSR_WUF_Pos 0 +#define PWR_CSR_WUF_Msk ((uint32_t)1 << PWR_CSR_WUF_Pos) +#define PWR_CSR_SBF_Pos 1 +#define PWR_CSR_SBF_Msk ((uint32_t)1 << PWR_CSR_SBF_Pos) +#define PWR_CSR_PVDO_Pos 2 +#define PWR_CSR_PVDO_Msk ((uint32_t)1 << PWR_CSR_PVDO_Pos) +#define PWR_CSR_BRR_Pos 3 +#define PWR_CSR_BRR_Msk ((uint32_t)1 << PWR_CSR_BRR_Pos) +#define PWR_CSR_EWUP_Pos 8 +#define PWR_CSR_EWUP_Msk ((uint32_t)1 << PWR_CSR_EWUP_Pos) +#define PWR_CSR_BRE_Pos 9 +#define PWR_CSR_BRE_Msk ((uint32_t)1 << PWR_CSR_BRE_Pos) +#define PWR_CSR_VOSRDY_Pos 14 +#define PWR_CSR_VOSRDY_Msk ((uint32_t)1 << PWR_CSR_VOSRDY_Pos) + +#endif /*!SOC_PWR_H */ diff --git a/arch/socs/stm32f439/soc-rcc.c b/arch/socs/stm32f439/soc-rcc.c new file mode 100644 index 0000000..5802d75 --- /dev/null +++ b/arch/socs/stm32f439/soc-rcc.c @@ -0,0 +1,132 @@ +/* \file soc-rcc.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "regutils.h" +#include "autoconf.h" +#include "soc-rcc.h" +#include "soc-pwr.h" +#include "soc-flash.h" + +void soc_rcc_reset(void) +{ +/* TODO: some of the bellowing code should be M4 generic. Yet, check if all these registers + are M4 generic or STM32F4 core specific + */ + /* Reset the RCC clock configuration to the default reset state */ + /* Set HSION bit */ + set_reg_bits(r_CORTEX_M_RCC_CR, RCC_CR_HSION); + + /* Reset CFGR register */ + write_reg_value(r_CORTEX_M_RCC_CFGR, 0x00000000); + + /* Reset HSEON, CSSON and PLLON bits */ + clear_reg_bits(r_CORTEX_M_RCC_CR, + RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLLON); + + /* Reset PLLCFGR register */ + write_reg_value(r_CORTEX_M_RCC_PLLCFGR, 0x24003010); + + /* Reset HSEBYP bit */ + clear_reg_bits(r_CORTEX_M_RCC_CR, RCC_CR_HSEBYP); + + /* Reset all interrupts */ + write_reg_value(r_CORTEX_M_RCC_CIR, 0x00000000); +} + +void soc_rcc_setsysclock(void) +{ + uint32_t StartUpCounter = 0, status = 0; + /******************************************************************************/ + /* PLL (clocked by HSE/HSI) used as System clock source */ + /******************************************************************************/ +#ifdef PROD_ENABLE_HSE /* Enable HSE */ + set_reg_bits(r_CORTEX_M_RCC_CR, RCC_CR_HSEON); + do { + status = read_reg_value(r_CORTEX_M_RCC_CR) & RCC_CR_HSERDY; + StartUpCounter++; + } while ((status == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); +#else /* Enable HSI */ + set_reg_bits(r_CORTEX_M_RCC_CR, RCC_CR_HSION); + do { + status = read_reg_value(r_CORTEX_M_RCC_CR) & RCC_CR_HSIRDY; + StartUpCounter++; + } while ((status == 0) && (StartUpCounter != HSI_STARTUP_TIMEOUT)); +#endif + + if (status != RESET) { + /* Enable high performance mode, System frequency up to 168 MHz */ + set_reg_bits(r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_PWREN); + /* This bit controls the main internal voltage regulator output + * voltage to achieve a trade-off between performance and power + * consumption when the device does not operate at the maximum + * frequency. (DocID018909 Rev 15 - page 141) + * PWR_CR_VOS = 1 => Scale 1 mode (default value at reset) + */ + set_reg_bits(r_CORTEX_M_PWR_CR, PWR_CR_VOS_Msk); + + /* Set clock dividers */ + set_reg_bits(r_CORTEX_M_RCC_CFGR, PROD_HCLK); + set_reg_bits(r_CORTEX_M_RCC_CFGR, PROD_PCLK2); + set_reg_bits(r_CORTEX_M_RCC_CFGR, PROD_PCLK1); + +#ifdef PROD_ENABLE_PLL +#ifdef PROD_ENABLE_HSE + + /* Configure the main PLL */ + write_reg_value(r_CORTEX_M_RCC_PLLCFGR, PROD_PLL_M | (PROD_PLL_N << 6) + | (((PROD_PLL_P >> 1) - 1) << 16) + | (RCC_PLLCFGR_PLLSRC_HSE) | (PROD_PLL_Q << 24)); +#else + write_reg_value(r_CORTEX_M_RCC_PLLCFGR, PROD_PLL_M | (PROD_PLL_N << 6) + | (((PROD_PLL_P >> 1) - 1) << 16) + | (RCC_PLLCFGR_PLLSRC_HSI) | (PROD_PLL_Q << 24)); +#endif + + /* Enable the main PLL */ + set_reg_bits(r_CORTEX_M_RCC_CR, RCC_CR_PLLON); + + /* Wait till the main PLL is ready */ + while ((read_reg_value(r_CORTEX_M_RCC_CR) & RCC_CR_PLLRDY) == 0) + continue; +#endif + + /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ + write_reg_value(r_CORTEX_M_FLASH_ACR, FLASH_ACR_ICEN + | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS); + +#ifdef PROD_ENABLE_PLL + /* Select the main PLL as system clock source */ + clear_reg_bits(r_CORTEX_M_RCC_CFGR, RCC_CFGR_SW); + set_reg_bits(r_CORTEX_M_RCC_CFGR, RCC_CFGR_SW_PLL); +#endif + /* Wait till the main PLL is used as system clock source */ + while ((read_reg_value(r_CORTEX_M_RCC_CFGR) & (uint32_t) + RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) + continue; + + } else { + /* If HSE/I fails to start-up, the application will have wrong + * clock configuration. User can add here some code to deal + * with this error. + */ + } +} diff --git a/arch/socs/stm32f439/soc-rcc.h b/arch/socs/stm32f439/soc-rcc.h new file mode 100644 index 0000000..f96866e --- /dev/null +++ b/arch/socs/stm32f439/soc-rcc.h @@ -0,0 +1,751 @@ +/* \file soc-rcc.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_RCC_H +#define SOC_RCC_H + +#include "soc-init.h" +#include "soc-core.h" + +#define r_CORTEX_M_RCC_CR REG_ADDR(RCC_BASE + (uint32_t) 0x00) +#define r_CORTEX_M_RCC_PLLCFGR REG_ADDR(RCC_BASE + (uint32_t) 0x04) +#define r_CORTEX_M_RCC_CFGR REG_ADDR(RCC_BASE + (uint32_t) 0x08) +#define r_CORTEX_M_RCC_CIR REG_ADDR(RCC_BASE + (uint32_t) 0x0C) +#define r_CORTEX_M_RCC_AHB1RSTR REG_ADDR(RCC_BASE + (uint32_t) 0x10) +#define r_CORTEX_M_RCC_AHB2RSTR REG_ADDR(RCC_BASE + (uint32_t) 0x14) +#define r_CORTEX_M_RCC_AHB3RSTR REG_ADDR(RCC_BASE + (uint32_t) 0x18) +#define r_CORTEX_M_RCC_APB1RSTR REG_ADDR(RCC_BASE + (uint32_t) 0x20) +#define r_CORTEX_M_RCC_APB2RSTR REG_ADDR(RCC_BASE + (uint32_t) 0x24) +#define r_CORTEX_M_RCC_AHB1ENR REG_ADDR(RCC_BASE + (uint32_t) 0x30) +#define r_CORTEX_M_RCC_AHB2ENR REG_ADDR(RCC_BASE + (uint32_t) 0x34) +#define r_CORTEX_M_RCC_AHB3ENR REG_ADDR(RCC_BASE + (uint32_t) 0x38) +#define r_CORTEX_M_RCC_APB1ENR REG_ADDR(RCC_BASE + (uint32_t) 0x40) +#define r_CORTEX_M_RCC_APB2ENR REG_ADDR(RCC_BASE + (uint32_t) 0x44) +#define r_CORTEX_M_RCC_AHB1LPENR REG_ADDR(RCC_BASE + (uint32_t) 0x50) +#define r_CORTEX_M_RCC_AHB2LPENR REG_ADDR(RCC_BASE + (uint32_t) 0x54) +#define r_CORTEX_M_RCC_AHB3LPENR REG_ADDR(RCC_BASE + (uint32_t) 0x58) +#define r_CORTEX_M_RCC_APB1LPENR REG_ADDR(RCC_BASE + (uint32_t) 0x60) +#define r_CORTEX_M_RCC_APB2LPENR REG_ADDR(RCC_BASE + (uint32_t) 0x64) +#define r_CORTEX_M_RCC_BDCR REG_ADDR(RCC_BASE + (uint32_t) 0x70) +#define r_CORTEX_M_RCC_CSR REG_ADDR(RCC_BASE + (uint32_t) 0x74) +#define r_CORTEX_M_RCC_SSCGR REG_ADDR(RCC_BASE + (uint32_t) 0x80) +#define r_CORTEX_M_RCC_PLLI2SCFGR REG_ADDR(RCC_BASE + (uint32_t) 0x84) +#define r_CORTEX_M_RCC_PLLSAICFGR REG_ADDR(RCC_BASE + (uint32_t) 0x88) +#define r_CORTEX_M_RCC_DCKCFGR REG_ADDR(RCC_BASE + (uint32_t) 0x8C) + +/* RCC clock control register (RCC_CR) */ +#define RCC_CR_HSION ((uint32_t) 0x00000001) +#define RCC_CR_HSIRDY ((uint32_t) 0x00000002) + +#define RCC_CR_HSITRIM ((uint32_t) 0x000000F8) +#define RCC_CR_HSITRIM_0 ((uint32_t) 0x00000008) /*Bit 0 */ +#define RCC_CR_HSITRIM_1 ((uint32_t) 0x00000010) /*Bit 1 */ +#define RCC_CR_HSITRIM_2 ((uint32_t) 0x00000020) /*Bit 2 */ +#define RCC_CR_HSITRIM_3 ((uint32_t) 0x00000040) /*Bit 3 */ +#define RCC_CR_HSITRIM_4 ((uint32_t) 0x00000080) /*Bit 4 */ + +#define RCC_CR_HSICAL ((uint32_t) 0x0000FF00) +#define RCC_CR_HSICAL_0 ((uint32_t) 0x00000100) /*Bit 0 */ +#define RCC_CR_HSICAL_1 ((uint32_t) 0x00000200) /*Bit 1 */ +#define RCC_CR_HSICAL_2 ((uint32_t) 0x00000400) /*Bit 2 */ +#define RCC_CR_HSICAL_3 ((uint32_t) 0x00000800) /*Bit 3 */ +#define RCC_CR_HSICAL_4 ((uint32_t) 0x00001000) /*Bit 4 */ +#define RCC_CR_HSICAL_5 ((uint32_t) 0x00002000) /*Bit 5 */ +#define RCC_CR_HSICAL_6 ((uint32_t) 0x00004000) /*Bit 6 */ +#define RCC_CR_HSICAL_7 ((uint32_t) 0x00008000) /*Bit 7 */ + +#define RCC_CR_HSEON ((uint32_t) 0x00010000) +#define RCC_CR_HSERDY ((uint32_t) 0x00020000) +#define RCC_CR_HSEBYP ((uint32_t) 0x00040000) +#define RCC_CR_CSSON ((uint32_t) 0x00080000) +#define RCC_CR_PLLON ((uint32_t) 0x01000000) +#define RCC_CR_PLLRDY ((uint32_t) 0x02000000) +#define RCC_CR_PLLI2SON ((uint32_t) 0x04000000) +#define RCC_CR_PLLI2SRDY ((uint32_t) 0x08000000) + +/* RCC PLL configuration register (RCC_PLLCFGR) */ +#define RCC_PLLCFGR_PLLM ((uint32_t) 0x0000003F) +#define RCC_PLLCFGR_PLLM_0 ((uint32_t) 0x00000001) +#define RCC_PLLCFGR_PLLM_1 ((uint32_t) 0x00000002) +#define RCC_PLLCFGR_PLLM_2 ((uint32_t) 0x00000004) +#define RCC_PLLCFGR_PLLM_3 ((uint32_t) 0x00000008) +#define RCC_PLLCFGR_PLLM_4 ((uint32_t) 0x00000010) +#define RCC_PLLCFGR_PLLM_5 ((uint32_t) 0x00000020) + +#define RCC_PLLCFGR_PLLN ((uint32_t) 0x00007FC0) +#define RCC_PLLCFGR_PLLN_0 ((uint32_t) 0x00000040) +#define RCC_PLLCFGR_PLLN_1 ((uint32_t) 0x00000080) +#define RCC_PLLCFGR_PLLN_2 ((uint32_t) 0x00000100) +#define RCC_PLLCFGR_PLLN_3 ((uint32_t) 0x00000200) +#define RCC_PLLCFGR_PLLN_4 ((uint32_t) 0x00000400) +#define RCC_PLLCFGR_PLLN_5 ((uint32_t) 0x00000800) +#define RCC_PLLCFGR_PLLN_6 ((uint32_t) 0x00001000) +#define RCC_PLLCFGR_PLLN_7 ((uint32_t) 0x00002000) +#define RCC_PLLCFGR_PLLN_8 ((uint32_t) 0x00004000) + +#define RCC_PLLCFGR_PLLP ((uint32_t) 0x00030000) +#define RCC_PLLCFGR_PLLP_0 ((uint32_t) 0x00010000) +#define RCC_PLLCFGR_PLLP_1 ((uint32_t) 0x00020000) + +#define RCC_PLLCFGR_PLLSRC ((uint32_t) 0x00400000) +#define RCC_PLLCFGR_PLLSRC_HSE ((uint32_t) 0x00400000) +#define RCC_PLLCFGR_PLLSRC_HSI ((uint32_t) 0x00000000) + +#define RCC_PLLCFGR_PLLQ ((uint32_t) 0x0F000000) +#define RCC_PLLCFGR_PLLQ_0 ((uint32_t) 0x01000000) +#define RCC_PLLCFGR_PLLQ_1 ((uint32_t) 0x02000000) +#define RCC_PLLCFGR_PLLQ_2 ((uint32_t) 0x04000000) +#define RCC_PLLCFGR_PLLQ_3 ((uint32_t) 0x08000000) + +/* RCC clock configuration register (RCC_CFGR) */ +#define RCC_CFGR_SW ((uint32_t) 0x00000003) /* SW[1:0] bits (System clock Switch) */ +#define RCC_CFGR_SW_0 ((uint32_t) 0x00000001) /* Bit 0 */ +#define RCC_CFGR_SW_1 ((uint32_t) 0x00000002) /* Bit 1 */ + +#define RCC_CFGR_SW_HSI ((uint32_t) 0x00000000) /* HSI selected as system clock */ +#define RCC_CFGR_SW_HSE ((uint32_t) 0x00000001) /* HSE selected as system clock */ +#define RCC_CFGR_SW_PLL ((uint32_t) 0x00000002) /* PLL selected as system clock */ + +/* SWS configuration */ +#define RCC_CFGR_SWS ((uint32_t) 0x0000000C) /* SWS[1:0] bits (System Clock Switch Status) */ +#define RCC_CFGR_SWS_0 ((uint32_t) 0x00000004) /* Bit 0 */ +#define RCC_CFGR_SWS_1 ((uint32_t) 0x00000008) /* Bit 1 */ + +#define RCC_CFGR_SWS_HSI ((uint32_t) 0x00000000) /* HSI oscillator used as system clock */ +#define RCC_CFGR_SWS_HSE ((uint32_t) 0x00000004) /* HSE oscillator used as system clock */ +#define RCC_CFGR_SWS_PLL ((uint32_t) 0x00000008) /* PLL used as system clock */ + +/* HPRE configuration */ +#define RCC_CFGR_HPRE ((uint32_t) 0x000000F0) /* HPRE[3:0] bits (AHB prescaler) */ +#define RCC_CFGR_HPRE_0 ((uint32_t) 0x00000010) /* Bit 0 */ +#define RCC_CFGR_HPRE_1 ((uint32_t) 0x00000020) /* Bit 1 */ +#define RCC_CFGR_HPRE_2 ((uint32_t) 0x00000040) /* Bit 2 */ +#define RCC_CFGR_HPRE_3 ((uint32_t) 0x00000080) /* Bit 3 */ + +#define RCC_CFGR_HPRE_DIV1 ((uint32_t) 0x00000000) /* SYSCLK not divided */ +#define RCC_CFGR_HPRE_DIV2 ((uint32_t) 0x00000080) /* SYSCLK divided by 2 */ +#define RCC_CFGR_HPRE_DIV4 ((uint32_t) 0x00000090) /* SYSCLK divided by 4 */ +#define RCC_CFGR_HPRE_DIV8 ((uint32_t) 0x000000A0) /* SYSCLK divided by 8 */ +#define RCC_CFGR_HPRE_DIV16 ((uint32_t) 0x000000B0) /* SYSCLK divided by 16 */ +#define RCC_CFGR_HPRE_DIV64 ((uint32_t) 0x000000C0) /* SYSCLK divided by 64 */ +#define RCC_CFGR_HPRE_DIV128 ((uint32_t) 0x000000D0) /* SYSCLK divided by 128 */ +#define RCC_CFGR_HPRE_DIV256 ((uint32_t) 0x000000E0) /* SYSCLK divided by 256 */ +#define RCC_CFGR_HPRE_DIV512 ((uint32_t) 0x000000F0) /* SYSCLK divided by 512 */ + +/* PPRE1 configuration */ +#define RCC_CFGR_HPRE1 ((uint32_t) 0x00001C00) /* PRE1[2:0] bits (APB1 prescaler) */ +#define RCC_CFGR_HPRE1_0 ((uint32_t) 0x00000400) /* Bit 0 */ +#define RCC_CFGR_HPRE1_1 ((uint32_t) 0x00000800) /* Bit 1 */ +#define RCC_CFGR_HPRE1_2 ((uint32_t) 0x00001000) /* Bit 2 */ + +#define RCC_CFGR_HPRE1_DIV1 ((uint32_t) 0x00000000) /* HCLK not divided */ +#define RCC_CFGR_HPRE1_DIV2 ((uint32_t) 0x00001000) /* HCLK divided by 2 */ +#define RCC_CFGR_HPRE1_DIV4 ((uint32_t) 0x00001400) /* HCLK divided by 4 */ +#define RCC_CFGR_HPRE1_DIV8 ((uint32_t) 0x00001800) /* HCLK divided by 8 */ +#define RCC_CFGR_HPRE1_DIV16 ((uint32_t) 0x00001C00) /* HCLK divided by 16 */ + +/* PPRE2 configuration */ +#define RCC_CFGR_HPRE2 ((uint32_t) 0x0000E000) /* PRE2[2:0] bits (APB2 prescaler) */ +#define RCC_CFGR_HPRE2_0 ((uint32_t) 0x00002000) /* Bit 0 */ +#define RCC_CFGR_HPRE2_1 ((uint32_t) 0x00004000) /* Bit 1 */ +#define RCC_CFGR_HPRE2_2 ((uint32_t) 0x00008000) /* Bit 2 */ + +#define RCC_CFGR_HPRE2_DIV1 ((uint32_t) 0x00000000) /* HCLK not divided */ +#define RCC_CFGR_HPRE2_DIV2 ((uint32_t) 0x00008000) /* HCLK divided by 2 */ +#define RCC_CFGR_HPRE2_DIV4 ((uint32_t) 0x0000A000) /* HCLK divided by 4 */ +#define RCC_CFGR_HPRE2_DIV8 ((uint32_t) 0x0000C000) /* HCLK divided by 8 */ +#define RCC_CFGR_HPRE2_DIV16 ((uint32_t) 0x0000E000) /* HCLK divided by 16 */ + +/* RTCPRE configuration */ +#define RCC_CFGR_RTCPRE ((uint32_t) 0x001F0000) +#define RCC_CFGR_RTCPRE_0 ((uint32_t) 0x00010000) +#define RCC_CFGR_RTCPRE_1 ((uint32_t) 0x00020000) +#define RCC_CFGR_RTCPRE_2 ((uint32_t) 0x00040000) +#define RCC_CFGR_RTCPRE_3 ((uint32_t) 0x00080000) +#define RCC_CFGR_RTCPRE_4 ((uint32_t) 0x00100000) + +/* MCO1 configuration */ +#define RCC_CFGR_MCO1 ((uint32_t) 0x00600000) +#define RCC_CFGR_MCO1_0 ((uint32_t) 0x00200000) +#define RCC_CFGR_MCO1_1 ((uint32_t) 0x00400000) + +#define RCC_CFGR_I2SSRC ((uint32_t) 0x00800000) + +#define RCC_CFGR_MCO1PRE ((uint32_t) 0x07000000) +#define RCC_CFGR_MCO1PRE_0 ((uint32_t) 0x01000000) +#define RCC_CFGR_MCO1PRE_1 ((uint32_t) 0x02000000) +#define RCC_CFGR_MCO1PRE_2 ((uint32_t) 0x04000000) + +#define RCC_CFGR_MCO2PRE ((uint32_t) 0x38000000) +#define RCC_CFGR_MCO2PRE_0 ((uint32_t) 0x08000000) +#define RCC_CFGR_MCO2PRE_1 ((uint32_t) 0x10000000) +#define RCC_CFGR_MCO2PRE_2 ((uint32_t) 0x20000000) + +#define RCC_CFGR_MCO2 ((uint32_t) 0xC0000000) +#define RCC_CFGR_MCO2_0 ((uint32_t) 0x40000000) +#define RCC_CFGR_MCO2_1 ((uint32_t) 0x80000000) + +/* RCC clock interrupt register (RCC_CIR) */ +#define RCC_CIR_LSIRDYF ((uint32_t) 0x00000001) +#define RCC_CIR_LSERDYF ((uint32_t) 0x00000002) +#define RCC_CIR_HSIRDYF ((uint32_t) 0x00000004) +#define RCC_CIR_HSERDYF ((uint32_t) 0x00000008) +#define RCC_CIR_PLLRDYF ((uint32_t) 0x00000010) +#define RCC_CIR_PLLI2SRDYF ((uint32_t) 0x00000020) +#define RCC_CIR_CSSF ((uint32_t) 0x00000080) +#define RCC_CIR_LSIRDYIE ((uint32_t) 0x00000100) +#define RCC_CIR_LSERDYIE ((uint32_t) 0x00000200) +#define RCC_CIR_HSIRDYIE ((uint32_t) 0x00000400) +#define RCC_CIR_HSERDYIE ((uint32_t) 0x00000800) +#define RCC_CIR_PLLRDYIE ((uint32_t) 0x00001000) +#define RCC_CIR_PLLI2SRDYIE ((uint32_t) 0x00002000) +#define RCC_CIR_LSIRDYC ((uint32_t) 0x00010000) +#define RCC_CIR_LSERDYC ((uint32_t) 0x00020000) +#define RCC_CIR_HSIRDYC ((uint32_t) 0x00040000) +#define RCC_CIR_HSERDYC ((uint32_t) 0x00080000) +#define RCC_CIR_PLLRDYC ((uint32_t) 0x00100000) +#define RCC_CIR_PLLI2SRDYC ((uint32_t) 0x00200000) +#define RCC_CIR_CSSC ((uint32_t) 0x00800000) + +/* RCC AHB1 peripheral reset register (RCC_AHB1RSTR) */ +#define RCC_AHB1RSTR_GPIOARST ((uint32_t) 0x00000001) +#define RCC_AHB1RSTR_GPIOBRST ((uint32_t) 0x00000002) +#define RCC_AHB1RSTR_GPIOCRST ((uint32_t) 0x00000004) +#define RCC_AHB1RSTR_GPIODRST ((uint32_t) 0x00000008) +#define RCC_AHB1RSTR_GPIOERST ((uint32_t) 0x00000010) +#define RCC_AHB1RSTR_GPIOFRST ((uint32_t) 0x00000020) +#define RCC_AHB1RSTR_GPIOGRST ((uint32_t) 0x00000040) +#define RCC_AHB1RSTR_GPIOHRST ((uint32_t) 0x00000080) +#define RCC_AHB1RSTR_GPIOIRST ((uint32_t) 0x00000100) +#define RCC_AHB1RSTR_CRCRST ((uint32_t) 0x00001000) +#define RCC_AHB1RSTR_DMA1RST ((uint32_t) 0x00200000) +#define RCC_AHB1RSTR_DMA2RST ((uint32_t) 0x00400000) +#define RCC_AHB1RSTR_ETHMACRST ((uint32_t) 0x02000000) +#define RCC_AHB1RSTR_OTGHRST ((uint32_t) 0x10000000) + +/* RCC AHB2 peripheral reset register (RCC_AHB2RSTR) */ +#define RCC_AHB2RSTR_DCMIRST ((uint32_t) 0x00000001) +#define RCC_AHB2RSTR_CRYPRST ((uint32_t) 0x00000010) +#define RCC_AHB2RSTR_HSAHRST ((uint32_t) 0x00000020) +#define RCC_AHB2RSTR_RNGRST ((uint32_t) 0x00000040) +#define RCC_AHB2RSTR_OTGFSRST ((uint32_t) 0x00000080) + +/* RCC AHB3 peripheral reset register (RCC_AHB3RSTR) */ +#define RCC_AHB3RSTR_FSMCRST ((uint32_t) 0x00000001 + +/* RCC AHB1 peripheral clock register (RCC_AHB1ENR) */ +#define RCC_AHB1ENR_GPIOAEN ((uint32_t) 0x00000001) +#define RCC_AHB1ENR_GPIOBEN ((uint32_t) 0x00000002) +#define RCC_AHB1ENR_GPIOCEN ((uint32_t) 0x00000004) +#define RCC_AHB1ENR_GPIODEN ((uint32_t) 0x00000008) +#define RCC_AHB1ENR_GPIOEEN ((uint32_t) 0x00000010) +#define RCC_AHB1ENR_GPIOFEN ((uint32_t) 0x00000020) +#define RCC_AHB1ENR_GPIOGEN ((uint32_t) 0x00000040) +#define RCC_AHB1ENR_GPIOHEN ((uint32_t) 0x00000080) +#define RCC_AHB1ENR_GPIOIEN ((uint32_t) 0x00000100) +#define RCC_AHB1ENR_CRCEN ((uint32_t) 0x00001000) +#define RCC_AHB1ENR_BKPSRAMEN ((uint32_t) 0x00040000) +#define RCC_AHB1ENR_CCMDATARAMEN ((uint32_t) 0x00100000) +#define RCC_AHB1ENR_DMA1EN ((uint32_t) 0x00200000) +#define RCC_AHB1ENR_DMA2EN ((uint32_t) 0x00400000) +#define RCC_AHB1ENR_ETHMACEN ((uint32_t) 0x02000000) +#define RCC_AHB1ENR_ETHMACTXEN ((uint32_t) 0x04000000) +#define RCC_AHB1ENR_ETHMACRXEN ((uint32_t) 0x08000000) +#define RCC_AHB1ENR_ETHMACPTPEN ((uint32_t) 0x10000000) +#define RCC_AHB1ENR_OTGHSEN ((uint32_t) 0x20000000) +#define RCC_AHB1ENR_OTGHSULPIEN ((uint32_t) 0x40000000) + +/* RCC AHB2 peripheral clock enable register (RCC_AHB2ENR)*/ +#define RCC_AHB2ENR_DCMIEN ((uint32_t) 0x00000001) +#define RCC_AHB2ENR_CRYPEN ((uint32_t) 0x00000010) +#define RCC_AHB2ENR_HASHEN ((uint32_t) 0x00000020) +#define RCC_AHB2ENR_RNGEN ((uint32_t) 0x00000040) +#define RCC_AHB2ENR_OTGFSEN ((uint32_t) 0x00000080) + +/* RCC AHB3 peripheral clock enable register (RCC_AHB3ENR)*/ +#define RCC_AHB3ENR_FSMCEN ((uint32_t) 0x00000001) + +/* RCC APB1 peripheral clock enable register (RCC_APB1ENR)*/ +#define RCC_APB1ENR_TIM2EN ((uint32_t) 0x00000001) +#define RCC_APB1ENR_TIM3EN ((uint32_t) 0x00000002) +#define RCC_APB1ENR_TIM4EN ((uint32_t) 0x00000004) +#define RCC_APB1ENR_TIM5EN ((uint32_t) 0x00000008) +#define RCC_APB1ENR_TIM6EN ((uint32_t) 0x00000010) +#define RCC_APB1ENR_TIM7EN ((uint32_t) 0x00000020) +#define RCC_APB1ENR_TIM12EN ((uint32_t) 0x00000040) +#define RCC_APB1ENR_TIM13EN ((uint32_t) 0x00000080) +#define RCC_APB1ENR_TIM14EN ((uint32_t) 0x00000100) +#define RCC_APB1ENR_WWDGEN ((uint32_t) 0x00000800) +#define RCC_APB1ENR_SPI2EN ((uint32_t) 0x00004000) +#define RCC_APB1ENR_SPI3EN ((uint32_t) 0x00008000) +#define RCC_APB1ENR_USART2EN ((uint32_t) 0x00020000) +#define RCC_APB1ENR_USART3EN ((uint32_t) 0x00040000) +#define RCC_APB1ENR_UART4EN ((uint32_t) 0x00080000) +#define RCC_APB1ENR_UART5EN ((uint32_t) 0x00100000) +#define RCC_APB1ENR_I2C1EN ((uint32_t) 0x00200000) +#define RCC_APB1ENR_I2C2EN ((uint32_t) 0x00400000) +#define RCC_APB1ENR_I2C3EN ((uint32_t) 0x00800000) +#define RCC_APB1ENR_CAN1EN ((uint32_t) 0x02000000) +#define RCC_APB1ENR_CAN2EN ((uint32_t) 0x04000000) +#define RCC_APB1ENR_PWREN ((uint32_t) 0x10000000) +#define RCC_APB1ENR_DACEN ((uint32_t) 0x20000000) + +/* RCC APB2 peripheral clock enable register (RCC_APB2ENR) */ +#define RCC_APB2ENR_TIM1EN ((uint32_t) 0x00000001) +#define RCC_APB2ENR_TIM8EN ((uint32_t) 0x00000002) +#define RCC_APB2ENR_USART1EN ((uint32_t) 0x00000010) +#define RCC_APB2ENR_USART6EN ((uint32_t) 0x00000020) +#define RCC_APB2ENR_ADC1EN ((uint32_t) 0x00000100) +#define RCC_APB2ENR_ADC2EN ((uint32_t) 0x00000200) +#define RCC_APB2ENR_ADC3EN ((uint32_t) 0x00000400) +#define RCC_APB2ENR_SDIOEN ((uint32_t) 0x00000800) +#define RCC_APB2ENR_SPI1EN ((uint32_t) 0x00001000) +#define RCC_APB2ENR_SYSCFGEN ((uint32_t) 0x00004000) +#define RCC_APB2ENR_TIM11EN ((uint32_t) 0x00040000) +#define RCC_APB2ENR_TIM10EN ((uint32_t) 0x00020000) +#define RCC_APB2ENR_TIM9EN ((uint32_t) 0x00010000) + +/* RCC AHB1 peripheral clock enable in low power mode register (RCC_AHB1LPENR) */ +#define RCC_AHB1LPENR_GPIOALPEN ((uint32_t) 0x00000001) +#define RCC_AHB1LPENR_GPIOBLPEN ((uint32_t) 0x00000002) +#define RCC_AHB1LPENR_GPIOCLPEN ((uint32_t) 0x00000004) +#define RCC_AHB1LPENR_GPIODLPEN ((uint32_t) 0x00000008) +#define RCC_AHB1LPENR_GPIOELPEN ((uint32_t) 0x00000010) +#define RCC_AHB1LPENR_GPIOFLPEN ((uint32_t) 0x00000020) +#define RCC_AHB1LPENR_GPIOGLPEN ((uint32_t) 0x00000040) +#define RCC_AHB1LPENR_GPIOHLPEN ((uint32_t) 0x00000080) +#define RCC_AHB1LPENR_GPIOILPEN ((uint32_t) 0x00000100) +#define RCC_AHB1LPENR_CRCLPEN ((uint32_t) 0x00001000) +#define RCC_AHB1LPENR_FLITFLPEN ((uint32_t) 0x00008000) +#define RCC_AHB1LPENR_SRAM1LPEN ((uint32_t) 0x00010000) +#define RCC_AHB1LPENR_SRAM2LPEN ((uint32_t) 0x00020000) +#define RCC_AHB1LPENR_BKPSRAMLPEN ((uint32_t) 0x00040000) +#define RCC_AHB1LPENR_DMA1LPEN ((uint32_t) 0x00200000) +#define RCC_AHB1LPENR_DMA2LPEN ((uint32_t) 0x00400000) +#define RCC_AHB1LPENR_ETHMACLPEN ((uint32_t) 0x02000000) +#define RCC_AHB1LPENR_ETHMACTXLPEN ((uint32_t) 0x04000000) +#define RCC_AHB1LPENR_ETHMACRXLPEN ((uint32_t) 0x08000000) +#define RCC_AHB1LPENR_ETHMACPTPLPEN ((uint32_t) 0x10000000) +#define RCC_AHB1LPENR_OTGHSLPEN ((uint32_t) 0x20000000) +#define RCC_AHB1LPENR_OTGHSULPILPEN ((uint32_t) 0x40000000) + +/* RCC AHB2 peripheral clock enable in low power mode register (RCC_AHB2LPENR) */ +#define RCC_AHB2LPENR_DCMILPEN ((uint32_t) 0x00000001) +#define RCC_AHB2LPENR_CRYPLPEN ((uint32_t) 0x00000010) +#define RCC_AHB2LPENR_HASHLPEN ((uint32_t) 0x00000020) +#define RCC_AHB2LPENR_RNGLPEN ((uint32_t) 0x00000040) +#define RCC_AHB2LPENR_OTGFSLPEN ((uint32_t) 0x00000080) + +/* RCC AHB3 peripheral clock enable in low power mode register (RCC_AHB3LPENR) */ +#define RCC_AHB3LPENR_FSMCLPEN ((uint32_t) 0x00000001) + +/* RCC APB1 peripheral clock enable in low power mode register (RCC_APB1LPENR) */ +#define RCC_APB1LPENR_TIM2LPEN ((uint32_t) 0x00000001) +#define RCC_APB1LPENR_TIM3LPEN ((uint32_t) 0x00000002) +#define RCC_APB1LPENR_TIM4LPEN ((uint32_t) 0x00000004) +#define RCC_APB1LPENR_TIM5LPEN ((uint32_t) 0x00000008) +#define RCC_APB1LPENR_TIM6LPEN ((uint32_t) 0x00000010) +#define RCC_APB1LPENR_TIM7LPEN ((uint32_t) 0x00000020) +#define RCC_APB1LPENR_TIM12LPEN ((uint32_t) 0x00000040) +#define RCC_APB1LPENR_TIM13LPEN ((uint32_t) 0x00000080) +#define RCC_APB1LPENR_TIM14LPEN ((uint32_t) 0x00000100) +#define RCC_APB1LPENR_WWDGLPEN ((uint32_t) 0x00000800) +#define RCC_APB1LPENR_SPI2LPEN ((uint32_t) 0x00004000) +#define RCC_APB1LPENR_SPI3LPEN ((uint32_t) 0x00008000) +#define RCC_APB1LPENR_USART2LPEN ((uint32_t) 0x00020000) +#define RCC_APB1LPENR_USART3LPEN ((uint32_t) 0x00040000) +#define RCC_APB1LPENR_UART4LPEN ((uint32_t) 0x00080000) +#define RCC_APB1LPENR_UART5LPEN ((uint32_t) 0x00100000) +#define RCC_APB1LPENR_I2C1LPEN ((uint32_t) 0x00200000) +#define RCC_APB1LPENR_I2C2LPEN ((uint32_t) 0x00400000) +#define RCC_APB1LPENR_I2C3LPEN ((uint32_t) 0x00800000) +#define RCC_APB1LPENR_CAN1LPEN ((uint32_t) 0x02000000) +#define RCC_APB1LPENR_CAN2LPEN ((uint32_t) 0x04000000) +#define RCC_APB1LPENR_PWRLPEN ((uint32_t) 0x10000000) +#define RCC_APB1LPENR_DACLPEN ((uint32_t) 0x20000000) + +/* RCC APB2 peripheral clock enabled in low power mode register (RCC_APB2LPENR) */ +#define RCC_APB2LPENR_TIM1LPEN ((uint32_t) 0x00000001) +#define RCC_APB2LPENR_TIM8LPEN ((uint32_t) 0x00000002) +#define RCC_APB2LPENR_USART1LPEN ((uint32_t) 0x00000010) +#define RCC_APB2LPENR_USART6LPEN ((uint32_t) 0x00000020) +#define RCC_APB2LPENR_ADC1LPEN ((uint32_t) 0x00000100) +#define RCC_APB2LPENR_ADC2PEN ((uint32_t) 0x00000200) +#define RCC_APB2LPENR_ADC3LPEN ((uint32_t) 0x00000400) +#define RCC_APB2LPENR_SDIOLPEN ((uint32_t) 0x00000800) +#define RCC_APB2LPENR_SPI1LPEN ((uint32_t) 0x00001000) +#define RCC_APB2LPENR_SYSCFGLPEN ((uint32_t) 0x00004000) +#define RCC_APB2LPENR_TIM9LPEN ((uint32_t) 0x00010000) +#define RCC_APB2LPENR_TIM10LPEN ((uint32_t) 0x00020000) +#define RCC_APB2LPENR_TIM11LPEN ((uint32_t) 0x00040000) + +/* RCC APB2 peripheral reset register (RCC_APB2RSTR) */ +#define RCC_APB2RSTR_TIM1RST ((uint32_t)0x00000001) +#define RCC_APB2RSTR_TIM8RST ((uint32_t)0x00000002) +#define RCC_APB2RSTR_USART1RST ((uint32_t)0x00000010) +#define RCC_APB2RSTR_USART6RST ((uint32_t)0x00000020) +#define RCC_APB2RSTR_ADCRST ((uint32_t)0x00000100) +#define RCC_APB2RSTR_SDIORST ((uint32_t)0x00000800) +#define RCC_APB2RSTR_SPI1RST ((uint32_t)0x00001000) +#define RCC_APB2RSTR_SYSCFGRST ((uint32_t)0x00004000) +#define RCC_APB2RSTR_TIM9RST ((uint32_t)0x00010000) +#define RCC_APB2RSTR_TIM10RST ((uint32_t)0x00020000) +#define RCC_APB2RSTR_TIM11RST ((uint32_t)0x00040000) + +/* RCC Backup domain control register (RCC_BDCR) */ +#define RCC_BDCR_LSEON ((uint32_t) 0x00000001) +#define RCC_BDCR_LSERDY ((uint32_t) 0x00000002) +#define RCC_BDCR_LSEBYP ((uint32_t) 0x00000004) + +#define RCC_BDCR_RTCSEL ((uint32_t) 0x00000300) +#define RCC_BDCR_RTCSEL_0 ((uint32_t) 0x00000100) +#define RCC_BDCR_RTCSEL_1 ((uint32_t) 0x00000200) + +#define RCC_BDCR_RTCEN ((uint32_t) 0x00008000) +#define RCC_BDCR_BDRST ((uint32_t) 0x00010000) + +/* RCC clock control & status register */ +#define RCC_CSR_LSION ((uint32_t) 0x00000001) +#define RCC_CSR_LSIRDY ((uint32_t) 0x00000002) +#define RCC_CSR_RMVF ((uint32_t) 0x01000000) +#define RCC_CSR_BORRSTF ((uint32_t) 0x02000000) +#define RCC_CSR_PADRSTF ((uint32_t) 0x04000000) +#define RCC_CSR_PORRSTF ((uint32_t) 0x08000000) +#define RCC_CSR_SFTRSTF ((uint32_t) 0x10000000) +#define RCC_CSR_WDGRSTF ((uint32_t) 0x20000000) +#define RCC_CSR_WWDGRSTF ((uint32_t) 0x40000000) +#define RCC_CSR_LPWRRSTF ((uint32_t) 0x80000000) + +/* RCC spread spectrum clock generation register (RCC_SSCGR) */ +#define RCC_SSCGR_MODPER ((uint32_t) 0x00001FFF) +#define RCC_SSCGR_INCSTEP ((uint32_t) 0x0FFFE000) +#define RCC_SSCGR_SPREADSEL ((uint32_t) 0x40000000) +#define RCC_SSCGR_SSCGEN ((uint32_t) 0x80000000) + +/* RCC PLLI2S configuration register (RCC_PLLI2SCFGR) */ +#define RCC_PLLI2SCFGR_PLLI2SN ((uint32_t) 0x00007FC0) +#define RCC_PLLI2SCFGR_PLLI2SR ((uint32_t) 0x70000000) + +/* Exported Constants */ +#define RCC_HSE_OFF ((uint8_t) 0x00) +#define RCC_HSE_ON ((uint8_t) 0x01) +#define RCC_HSE_Bypass ((uint8_t) 0x05) +#define IS_RCC_HSE(HSE) (((HSE) == RCC_HSE_OFF) || ((HSE) == RCC_HSE_ON) || \ + ((HSE) == RCC_HSE_Bypass)) + +/* RCC_PLL_Clock_Source */ +#define RCC_PLLSource_HSI ((uint32_t) 0x00000000) +#define RCC_PLLSource_HSE ((uint32_t) 0x00400000) +#define IS_RCC_PLL_SOURCE(SOURCE) (((SOURCE) == RCC_PLLSource_HSI) || \ + ((SOURCE) == RCC_PLLSource_HSE)) +#define IS_RCC_PLLM_VALUE(VALUE) ((VALUE) <= 63) +#define IS_RCC_PLLN_VALUE(VALUE) ((192 <= (VALUE)) && ((VALUE) <= 432)) +#define IS_RCC_PLLP_VALUE(VALUE) (((VALUE) == 2) || ((VALUE) == 4) || ((VALUE) == 6) || ((VALUE) == 8)) +#define IS_RCC_PLLQ_VALUE(VALUE) ((4 <= (VALUE)) && ((VALUE) <= 15)) + +#define IS_RCC_PLLI2SN_VALUE(VALUE) ((192 <= (VALUE)) && ((VALUE) <= 432)) +#define IS_RCC_PLLI2SR_VALUE(VALUE) ((2 <= (VALUE)) && ((VALUE) <= 7)) + +/* RCC_System_Clock_Source */ +#define RCC_SYSCLKSource_HSI ((uint32_t) 0x00000000) +#define RCC_SYSCLKSource_HSE ((uint32_t) 0x00000001) +#define RCC_SYSCLKSource_PLLCLK ((uint32_t) 0x00000002) +#define IS_RCC_SYSCLK_SOURCE(SOURCE) (((SOURCE) == RCC_SYSCLKSource_HSI) || \ + ((SOURCE) == RCC_SYSCLKSource_HSE) || \ + ((SOURCE) == RCC_SYSCLKSource_PLLCLK)) + +/* RCC_AHB_Clock_Source */ +#define RCC_SYSCLK_Div1 ((uint32_t) 0x00000000) +#define RCC_SYSCLK_Div2 ((uint32_t) 0x00000080) +#define RCC_SYSCLK_Div4 ((uint32_t) 0x00000090) +#define RCC_SYSCLK_Div8 ((uint32_t) 0x000000A0) +#define RCC_SYSCLK_Div16 ((uint32_t) 0x000000B0) +#define RCC_SYSCLK_Div64 ((uint32_t) 0x000000C0) +#define RCC_SYSCLK_Div128 ((uint32_t) 0x000000D0) +#define RCC_SYSCLK_Div256 ((uint32_t) 0x000000E0) +#define RCC_SYSCLK_Div512 ((uint32_t) 0x000000F0) +#define IS_RCC_HCLK(HCLK) (((HCLK) == RCC_SYSCLK_Div1) || ((HCLK) == RCC_SYSCLK_Div2) || \ + ((HCLK) == RCC_SYSCLK_Div4) || ((HCLK) == RCC_SYSCLK_Div8) || \ + ((HCLK) == RCC_SYSCLK_Div16) || ((HCLK) == RCC_SYSCLK_Div64) || \ + ((HCLK) == RCC_SYSCLK_Div128) || ((HCLK) == RCC_SYSCLK_Div256) || \ + ((HCLK) == RCC_SYSCLK_Div512)) + +/* RCC_APB1_APB2_Clock_Source */ +#define RCC_HCLK_Div1 ((uint32_t) 0x00000000) +#define RCC_HCLK_Div2 ((uint32_t) 0x00001000) +#define RCC_HCLK_Div4 ((uint32_t) 0x00001400) +#define RCC_HCLK_Div8 ((uint32_t) 0x00001800) +#define RCC_HCLK_Div16 ((uint32_t) 0x00001C00) +#define IS_RCC_PCLK(PCLK) (((PCLK) == RCC_HCLK_Div1) || ((PCLK) == RCC_HCLK_Div2) || \ + ((PCLK) == RCC_HCLK_Div4) || ((PCLK) == RCC_HCLK_Div8) || \ + ((PCLK) == RCC_HCLK_Div16)) + +/* RCC_Interrupt_Source */ +#define RCC_IT_LSIRDY ((uint8_t) 0x01) +#define RCC_IT_LSERDY ((uint8_t) 0x02) +#define RCC_IT_HSIRDY ((uint8_t) 0x04) +#define RCC_IT_HSERDY ((uint8_t) 0x08) +#define RCC_IT_PLLRDY ((uint8_t) 0x10) +#define RCC_IT_PLLI2SRDY ((uint8_t) 0x20) +#define RCC_IT_CSS ((uint8_t) 0x80) +#define IS_RCC_IT(IT) ((((IT) & (uint8_t) 0xC0) == 0x00) && ((IT) != 0x00)) +#define IS_RCC_GET_IT(IT) (((IT) == RCC_IT_LSIRDY) || ((IT) == RCC_IT_LSERDY) || \ + ((IT) == RCC_IT_HSIRDY) || ((IT) == RCC_IT_HSERDY) || \ + ((IT) == RCC_IT_PLLRDY) || ((IT) == RCC_IT_CSS) || \ + ((IT) == RCC_IT_PLLI2SRDY)) +#define IS_RCC_CLEAR_IT(IT) ((((IT) & (uint8_t) 0x40) == 0x00) && ((IT) != 0x00)) + +/* RCC_LSE_Configuration */ +#define RCC_LSE_OFF ((uint8_t) 0x00) +#define RCC_LSE_ON ((uint8_t) 0x01) +#define RCC_LSE_Bypass ((uint8_t) 0x04) +#define IS_RCC_LSE(LSE) (((LSE) == RCC_LSE_OFF) || ((LSE) == RCC_LSE_ON) || \ + ((LSE) == RCC_LSE_Bypass)) + +/* RCC_RTC_Clock_Source */ +#define RCC_RTCCLKSource_LSE ((uint32_t) 0x00000100) +#define RCC_RTCCLKSource_LSI ((uint32_t) 0x00000200) +#define RCC_RTCCLKSource_HSE_Div2 ((uint32_t) 0x00020300) +#define RCC_RTCCLKSource_HSE_Div3 ((uint32_t) 0x00030300) +#define RCC_RTCCLKSource_HSE_Div4 ((uint32_t) 0x00040300) +#define RCC_RTCCLKSource_HSE_Div5 ((uint32_t) 0x00050300) +#define RCC_RTCCLKSource_HSE_Div6 ((uint32_t) 0x00060300) +#define RCC_RTCCLKSource_HSE_Div7 ((uint32_t) 0x00070300) +#define RCC_RTCCLKSource_HSE_Div8 ((uint32_t) 0x00080300) +#define RCC_RTCCLKSource_HSE_Div9 ((uint32_t) 0x00090300) +#define RCC_RTCCLKSource_HSE_Div10 ((uint32_t) 0x000A0300) +#define RCC_RTCCLKSource_HSE_Div11 ((uint32_t) 0x000B0300) +#define RCC_RTCCLKSource_HSE_Div12 ((uint32_t) 0x000C0300) +#define RCC_RTCCLKSource_HSE_Div13 ((uint32_t) 0x000D0300) +#define RCC_RTCCLKSource_HSE_Div14 ((uint32_t) 0x000E0300) +#define RCC_RTCCLKSource_HSE_Div15 ((uint32_t) 0x000F0300) +#define RCC_RTCCLKSource_HSE_Div16 ((uint32_t) 0x00100300) +#define RCC_RTCCLKSource_HSE_Div17 ((uint32_t) 0x00110300) +#define RCC_RTCCLKSource_HSE_Div18 ((uint32_t) 0x00120300) +#define RCC_RTCCLKSource_HSE_Div19 ((uint32_t) 0x00130300) +#define RCC_RTCCLKSource_HSE_Div20 ((uint32_t) 0x00140300) +#define RCC_RTCCLKSource_HSE_Div21 ((uint32_t) 0x00150300) +#define RCC_RTCCLKSource_HSE_Div22 ((uint32_t) 0x00160300) +#define RCC_RTCCLKSource_HSE_Div23 ((uint32_t) 0x00170300) +#define RCC_RTCCLKSource_HSE_Div24 ((uint32_t) 0x00180300) +#define RCC_RTCCLKSource_HSE_Div25 ((uint32_t) 0x00190300) +#define RCC_RTCCLKSource_HSE_Div26 ((uint32_t) 0x001A0300) +#define RCC_RTCCLKSource_HSE_Div27 ((uint32_t) 0x001B0300) +#define RCC_RTCCLKSource_HSE_Div28 ((uint32_t) 0x001C0300) +#define RCC_RTCCLKSource_HSE_Div29 ((uint32_t) 0x001D0300) +#define RCC_RTCCLKSource_HSE_Div30 ((uint32_t) 0x001E0300) +#define RCC_RTCCLKSource_HSE_Div31 ((uint32_t) 0x001F0300) +#define IS_RCC_RTCCLK_SOURCE(SOURCE) (((SOURCE) == RCC_RTCCLKSource_LSE) || \ + ((SOURCE) == RCC_RTCCLKSource_LSI) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div2) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div3) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div4) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div5) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div6) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div7) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div8) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div9) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div10) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div11) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div12) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div13) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div14) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div15) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div16) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div17) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div18) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div19) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div20) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div21) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div22) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div23) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div24) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div25) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div26) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div27) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div28) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div29) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div30) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div31)) +/* RCC_I2S_Clock_Source */ +#define RCC_I2S2CLKSource_PLLI2S ((uint8_t) 0x00) +#define RCC_I2S2CLKSource_Ext ((uint8_t) 0x01) +#define IS_RCC_I2SCLK_SOURCE(SOURCE) (((SOURCE) == RCC_I2S2CLKSource_PLLI2S) || ((SOURCE) == RCC_I2S2CLKSource_Ext)) + +/* RCC_AHB1_Peripherals */ +#define RCC_AHB1Periph_GPIOA ((uint32_t) 0x00000001) +#define RCC_AHB1Periph_GPIOB ((uint32_t) 0x00000002) +#define RCC_AHB1Periph_GPIOC ((uint32_t) 0x00000004) +#define RCC_AHB1Periph_GPIOD ((uint32_t) 0x00000008) +#define RCC_AHB1Periph_GPIOE ((uint32_t) 0x00000010) +#define RCC_AHB1Periph_GPIOF ((uint32_t) 0x00000020) +#define RCC_AHB1Periph_GPIOG ((uint32_t) 0x00000040) +#define RCC_AHB1Periph_GPIOH ((uint32_t) 0x00000080) +#define RCC_AHB1Periph_GPIOI ((uint32_t) 0x00000100) +#define RCC_AHB1Periph_CRC ((uint32_t) 0x00001000) +#define RCC_AHB1Periph_FLITF ((uint32_t) 0x00008000) +#define RCC_AHB1Periph_SRAM1 ((uint32_t) 0x00010000) +#define RCC_AHB1Periph_SRAM2 ((uint32_t) 0x00020000) +#define RCC_AHB1Periph_BKPSRAM ((uint32_t) 0x00040000) +#define RCC_AHB1Periph_CCMDATARAMEN ((uint32_t) 0x00100000) +#define RCC_AHB1Periph_DMA1 ((uint32_t) 0x00200000) +#define RCC_AHB1Periph_DMA2 ((uint32_t) 0x00400000) +#define RCC_AHB1Periph_ETH_MAC ((uint32_t) 0x02000000) +#define RCC_AHB1Periph_ETH_MAC_Tx ((uint32_t) 0x04000000) +#define RCC_AHB1Periph_ETH_MAC_Rx ((uint32_t) 0x08000000) +#define RCC_AHB1Periph_ETH_MAC_PTP ((uint32_t) 0x10000000) +#define RCC_AHB1Periph_OTG_HS ((uint32_t) 0x20000000) +#define RCC_AHB1Periph_OTG_HS_ULPI ((uint32_t) 0x40000000) +#define IS_RCC_AHB1_CLOCK_PERIPH(PERIPH) ((((PERIPH) & 0x818BEE00) == 0x00) && ((PERIPH) != 0x00)) +#define IS_RCC_AHB1_RESET_PERIPH(PERIPH) ((((PERIPH) & 0xDD9FEE00) == 0x00) && ((PERIPH) != 0x00)) +#define IS_RCC_AHB1_LPMODE_PERIPH(PERIPH) ((((PERIPH) & 0x81986E00) == 0x00) && ((PERIPH) != 0x00)) + +/* RCC_AHB2_Peripherals */ +#define RCC_AHB2Periph_DCMI ((uint32_t) 0x00000001) +#define RCC_AHB2Periph_CRYP ((uint32_t) 0x00000010) +#define RCC_AHB2Periph_HASH ((uint32_t) 0x00000020) +#define RCC_AHB2Periph_RNG ((uint32_t) 0x00000040) +#define RCC_AHB2Periph_OTG_FS ((uint32_t) 0x00000080) +#define IS_RCC_AHB2_PERIPH(PERIPH) ((((PERIPH) & 0xFFFFFF0E) == 0x00) && ((PERIPH) != 0x00)) + +/* RCC_AHB3_Peripherals */ +#define RCC_AHB3Periph_FSMC ((uint32_t) 0x00000001) +#define IS_RCC_AHB3_PERIPH(PERIPH) ((((PERIPH) & 0xFFFFFFFE) == 0x00) && ((PERIPH) != 0x00)) + +/* RCC_APB1_Peripherals */ +#define RCC_APB1Periph_TIM2 ((uint32_t) 0x00000001) +#define RCC_APB1Periph_TIM3 ((uint32_t) 0x00000002) +#define RCC_APB1Periph_TIM4 ((uint32_t) 0x00000004) +#define RCC_APB1Periph_TIM5 ((uint32_t) 0x00000008) +#define RCC_APB1Periph_TIM6 ((uint32_t) 0x00000010) +#define RCC_APB1Periph_TIM7 ((uint32_t) 0x00000020) +#define RCC_APB1Periph_TIM12 ((uint32_t) 0x00000040) +#define RCC_APB1Periph_TIM13 ((uint32_t) 0x00000080) +#define RCC_APB1Periph_TIM14 ((uint32_t) 0x00000100) +#define RCC_APB1Periph_WWDG ((uint32_t) 0x00000800) +#define RCC_APB1Periph_SPI2 ((uint32_t) 0x00004000) +#define RCC_APB1Periph_SPI3 ((uint32_t) 0x00008000) +#define RCC_APB1Periph_USART2 ((uint32_t) 0x00020000) +#define RCC_APB1Periph_USART3 ((uint32_t) 0x00040000) +#define RCC_APB1Periph_UART4 ((uint32_t) 0x00080000) +#define RCC_APB1Periph_UART5 ((uint32_t) 0x00100000) +#define RCC_APB1Periph_I2C1 ((uint32_t) 0x00200000) +#define RCC_APB1Periph_I2C2 ((uint32_t) 0x00400000) +#define RCC_APB1Periph_I2C3 ((uint32_t) 0x00800000) +#define RCC_APB1Periph_CAN1 ((uint32_t) 0x02000000) +#define RCC_APB1Periph_CAN2 ((uint32_t) 0x04000000) +#define RCC_APB1Periph_PWR ((uint32_t) 0x10000000) +#define RCC_APB1Periph_DAC ((uint32_t) 0x20000000) +#define IS_RCC_APB1_PERIPH(PERIPH) ((((PERIPH) & 0xC9013600) == 0x00) && ((PERIPH) != 0x00)) + +/* RCC_APB2_Peripherals */ +#define RCC_APB2Periph_TIM1 ((uint32_t) 0x00000001) +#define RCC_APB2Periph_TIM8 ((uint32_t) 0x00000002) +#define RCC_APB2Periph_USART1 ((uint32_t) 0x00000010) +#define RCC_APB2Periph_USART6 ((uint32_t) 0x00000020) +#define RCC_APB2Periph_ADC ((uint32_t) 0x00000100) +#define RCC_APB2Periph_ADC1 ((uint32_t) 0x00000100) +#define RCC_APB2Periph_ADC2 ((uint32_t) 0x00000200) +#define RCC_APB2Periph_ADC3 ((uint32_t) 0x00000400) +#define RCC_APB2Periph_SDIO ((uint32_t) 0x00000800) +#define RCC_APB2Periph_SPI1 ((uint32_t) 0x00001000) +#define RCC_APB2Periph_SYSCFG ((uint32_t) 0x00004000) +#define RCC_APB2Periph_TIM9 ((uint32_t) 0x00010000) +#define RCC_APB2Periph_TIM10 ((uint32_t) 0x00020000) +#define RCC_APB2Periph_TIM11 ((uint32_t) 0x00040000) +#define IS_RCC_APB2_PERIPH(PERIPH) ((((PERIPH) & 0xFFF8A0CC) == 0x00) && ((PERIPH) != 0x00)) +#define IS_RCC_APB2_RESET_PERIPH(PERIPH) ((((PERIPH) & 0xFFF8A6CC) == 0x00) && ((PERIPH) != 0x00)) + +/* RCC_MCO1_Clock_Source_Prescaler */ +#define RCC_MCO1Source_HSI ((uint32_t) 0x00000000) +#define RCC_MCO1Source_LSE ((uint32_t) 0x00200000) +#define RCC_MCO1Source_HSE ((uint32_t) 0x00400000) +#define RCC_MCO1Source_PLLCLK ((uint32_t) 0x00600000) +#define RCC_MCO1Div_1 ((uint32_t) 0x00000000) +#define RCC_MCO1Div_2 ((uint32_t) 0x04000000) +#define RCC_MCO1Div_3 ((uint32_t) 0x05000000) +#define RCC_MCO1Div_4 ((uint32_t) 0x06000000) +#define RCC_MCO1Div_5 ((uint32_t) 0x07000000) +#define IS_RCC_MCO1SOURCE(SOURCE) (((SOURCE) == RCC_MCO1Source_HSI) || ((SOURCE) == RCC_MCO1Source_LSE) || \ + ((SOURCE) == RCC_MCO1Source_HSE) || ((SOURCE) == RCC_MCO1Source_PLLCLK)) + +#define IS_RCC_MCO1DIV(DIV) (((DIV) == RCC_MCO1Div_1) || ((DIV) == RCC_MCO1Div_2) || \ + ((DIV) == RCC_MCO1Div_3) || ((DIV) == RCC_MCO1Div_4) || \ + ((DIV) == RCC_MCO1Div_5)) + +/* RCC_MCO2_Clock_Source_Prescaler */ +#define RCC_MCO2Source_SYSCLK ((uint32_t) 0x00000000) +#define RCC_MCO2Source_PLLI2SCLK ((uint32_t) 0x40000000) +#define RCC_MCO2Source_HSE ((uint32_t) 0x80000000) +#define RCC_MCO2Source_PLLCLK ((uint32_t) 0xC0000000) +#define RCC_MCO2Div_1 ((uint32_t) 0x00000000) +#define RCC_MCO2Div_2 ((uint32_t) 0x20000000) +#define RCC_MCO2Div_3 ((uint32_t) 0x28000000) +#define RCC_MCO2Div_4 ((uint32_t) 0x30000000) +#define RCC_MCO2Div_5 ((uint32_t) 0x38000000) +#define IS_RCC_MCO2SOURCE(SOURCE) (((SOURCE) == RCC_MCO2Source_SYSCLK) || ((SOURCE) == RCC_MCO2Source_PLLI2SCLK)|| \ + ((SOURCE) == RCC_MCO2Source_HSE) || ((SOURCE) == RCC_MCO2Source_PLLCLK)) + +#define IS_RCC_MCO2DIV(DIV) (((DIV) == RCC_MCO2Div_1) || ((DIV) == RCC_MCO2Div_2) || \ + ((DIV) == RCC_MCO2Div_3) || ((DIV) == RCC_MCO2Div_4) || \ + ((DIV) == RCC_MCO2Div_5)) + +/* RCC_Flag */ +#define RCC_FLAG_HSIRDY ((uint8_t) 0x21) +#define RCC_FLAG_HSERDY ((uint8_t) 0x31) +#define RCC_FLAG_PLLRDY ((uint8_t) 0x39) +#define RCC_FLAG_PLLI2SRDY ((uint8_t) 0x3B) +#define RCC_FLAG_LSERDY ((uint8_t) 0x41) +#define RCC_FLAG_LSIRDY ((uint8_t) 0x61) +#define RCC_FLAG_BORRST ((uint8_t) 0x79) +#define RCC_FLAG_PINRST ((uint8_t) 0x7A) +#define RCC_FLAG_PORRST ((uint8_t) 0x7B) +#define RCC_FLAG_SFTRST ((uint8_t) 0x7C) +#define RCC_FLAG_IWDGRST ((uint8_t) 0x7D) +#define RCC_FLAG_WWDGRST ((uint8_t) 0x7E) +#define RCC_FLAG_LPWRRST ((uint8_t) 0x7F) +#define IS_RCC_FLAG(FLAG) (((FLAG) == RCC_FLAG_HSIRDY) || ((FLAG) == RCC_FLAG_HSERDY) || \ + ((FLAG) == RCC_FLAG_PLLRDY) || ((FLAG) == RCC_FLAG_LSERDY) || \ + ((FLAG) == RCC_FLAG_LSIRDY) || ((FLAG) == RCC_FLAG_BORRST) || \ + ((FLAG) == RCC_FLAG_PINRST) || ((FLAG) == RCC_FLAG_PORRST) || \ + ((FLAG) == RCC_FLAG_SFTRST) || ((FLAG) == RCC_FLAG_IWDGRST)|| \ + ((FLAG) == RCC_FLAG_WWDGRST)|| ((FLAG) == RCC_FLAG_LPWRRST)|| \ + ((FLAG) == RCC_FLAG_PLLI2SRDY)) +#define IS_RCC_CALIBRATION_VALUE(VALUE) ((VALUE) <= 0x1F) + +/** + * \brief Reset the RCC clock configuration + */ +void soc_rcc_reset(void); + +/* + * \brief Configures the System clock source, PLL Multiplier and Divider factors, + * AHB/APBx prescalers and Flash settings + * + * + * This function should be called only once the RCC clock configuration + * is reset to the default reset state (done in SystemInit() function). + * + */ +void soc_rcc_setsysclock(void); + +#endif /*!SOC_RCC_H */ diff --git a/arch/socs/stm32f439/soc-rng.c b/arch/socs/stm32f439/soc-rng.c new file mode 100644 index 0000000..028b2e6 --- /dev/null +++ b/arch/socs/stm32f439/soc-rng.c @@ -0,0 +1,177 @@ +/* \file soc-rng.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "soc-rcc.h" +#include "soc-rng.h" +#include "debug.h" + +/** + * @brief Initialize RNG (mainly initialize it clock). + * + * @param nothing + * @return nothing + */ +static void rng_init(void) +{ + set_reg_bits(r_CORTEX_M_RCC_AHB2ENR, RCC_AHB2ENR_RNGEN); + + return; +} + +/** + * @brief Run the random number genrator. + * + * Run the RNG to get a random number. return 0 if + * generation is completed, or an error code if not. + * + * As explained in FIPS PUB, we discard the first + * random number generated and compare each generation + * to the next one. Each number has to be compared to + * previous one and generation fails if they're equal. + * + * @param random Random number buffer. + * @return 0 if success, error code is failure. + */ +static volatile unsigned int rng_enabled = 0; +static volatile unsigned int not_first_rng = 0; +static volatile uint32_t last_rng = 0; + +static int soc_rng_init(void) +{ + rng_init(); + rng_enabled = 1; + /* Enable random number generation */ + set_reg(r_CORTEX_M_RNG_CR, 1, RNG_CR_RNGEN); + /* Wait for the RNG to be ready */ + while (!(read_reg_value(r_CORTEX_M_RNG_SR) & RNG_SR_DRDY_Msk)) { + }; + /* Check for error */ + if (read_reg_value(r_CORTEX_M_RNG_SR) & RNG_SR_CEIS_Msk) { + return 2; + } else if (read_reg_value(r_CORTEX_M_RNG_SR) & RNG_SR_SEIS_Msk) { + return 3; + } + return 0; +} + +int soc_rng_getrng(uint32_t * random) +{ + int ret = 0; + if (rng_enabled == 0) { + return soc_rng_init(); + ret = 1; + } + *random = read_reg_value(r_CORTEX_M_RNG_DR); + return 0; +} + +static uint8_t rng_run(uint32_t * random) +{ + /* Enable RNG clock if needed */ + if (rng_enabled == 0) { + return soc_rng_init(); + } + /* Read random number */ + else if (read_reg_value(r_CORTEX_M_RNG_SR) & RNG_SR_DRDY_Msk) { + *random = read_reg_value(r_CORTEX_M_RNG_DR); + if ((not_first_rng == 0) || (last_rng == *random)) { + /* FIPS PUB test of current with previous random + * and discard the first random. + */ + last_rng = *random; + not_first_rng = 1; + return 4; + } else { + last_rng = *random; + return 0; + } + } else { + return 3; + } +} + +/** + * \brief Handles clock error (CEIS bit read as '1'). + */ +static void rng_ceis_error(void) +{ + /* Check that clock controller is correctly configured */ + LOG("[Clock error\n"); + /* Clear error */ + set_reg(r_CORTEX_M_RNG_SR, 0, RNG_SR_CEIS); +} + +/** + * \brief Handles seed error (SEIS bit read as '1'). + * + * Seed error, we should not read the random number provided. + */ +static void rng_seis_error(void) +{ + LOG("SEIS (seed) error\n"); + /* Clear error */ + set_reg(r_CORTEX_M_RNG_SR, 0, RNG_SR_SEIS); + /* Clear and set RNGEN bit to restart the RNG */ + set_reg(r_CORTEX_M_RNG_CR, 0, RNG_CR_RNGEN); + set_reg(r_CORTEX_M_RNG_CR, 1, RNG_CR_RNGEN); +} + +static void rng_fips_error(void) +{ + LOG("FIPS PUB warning: current random is the same as the previous one (or it is the first one)\n"); +} + +static void rng_unknown_error(void) +{ + ERROR("Unknown error happened (maybe data wasn't ready?)\n"); +} + +/** + * @brief Launch a random number generation and handles errors. + * + * @param random Random number buffer + */ +int soc_rng_manager(uint32_t * random) +{ + uint8_t ret; + again: + ret = rng_run(random); + switch (ret) { + case 1: + rng_ceis_error(); + goto again; + case 2: + rng_seis_error(); + /* We have a seed error, discard the random and run again! */ + goto again; + case 3: + rng_unknown_error(); + break; + case 4: + rng_fips_error(); + goto again; + } + if (ret) { + return -1; + } + return 0; +} diff --git a/arch/socs/stm32f439/soc-rng.h b/arch/socs/stm32f439/soc-rng.h new file mode 100644 index 0000000..c09333a --- /dev/null +++ b/arch/socs/stm32f439/soc-rng.h @@ -0,0 +1,60 @@ +/* \file soc-rng.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _SOC_RNG_H +#define _SOC_RNG_H + +#include "types.h" + +#define r_CORTEX_M_RNG_BASE REG_ADDR(0x50060800) + +#define r_CORTEX_M_RNG_CR (r_CORTEX_M_RNG_BASE + (uint32_t)0x00) +#define r_CORTEX_M_RNG_SR (r_CORTEX_M_RNG_BASE + (uint32_t)0x01) +#define r_CORTEX_M_RNG_DR (r_CORTEX_M_RNG_BASE + (uint32_t)0x02) + +/* RNG control register */ +#define RNG_CR_RNGEN_Pos 2 +#define RNG_CR_RNGEN_Msk ((uint32_t)1 << RNG_CR_RNGEN_Pos) +#define RNG_CR_IE_Pos 3 +#define RNG_CR_IE_Msk ((uint32_t)1 << RNG_CR_IE_Pos) + +/* RNG status register */ +#define RNG_SR_DRDY_Pos 0 +#define RNG_SR_DRDY_Msk ((uint32_t)1 << RNG_SR_DRDY_Pos) +#define RNG_SR_CECS_Pos 1 +#define RNG_SR_CECS_Msk ((uint32_t)1 << RNG_SR_CECS_Pos) +#define RNG_SR_SECS_Pos 2 +#define RNG_SR_SECS_Msk ((uint32_t)1 << RNG_SR_SECS_Pos) +#define RNG_SR_CEIS_Pos 5 +#define RNG_SR_CEIS_Msk ((uint32_t)1 << RNG_SR_CEIS_Pos) +#define RNG_SR_SEIS_Pos 6 +#define RNG_SR_SEIS_Msk ((uint32_t)1 << RNG_SR_SEIS_Pos) + +/* RNG data register */ +#define RNG_DR_RNDATA_Pos 0 +#define RNG_DR_RNDATA_Msk ((uint32_t)0xFFFF << RNG_DR_RNDATA_Pos) + +int soc_rng_manager(uint32_t * random); + +int soc_rng_getrng(uint32_t * random); + +#endif /* _SOC_RNG_H */ diff --git a/arch/socs/stm32f439/soc-scb.h b/arch/socs/stm32f439/soc-scb.h new file mode 100644 index 0000000..42b016a --- /dev/null +++ b/arch/socs/stm32f439/soc-scb.h @@ -0,0 +1,426 @@ +/* \file soc-scb.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_SCB_H +#define SOC_SCB_H + +#include "regutils.h" +#include "soc-core.h" + +/* System control block design hints and tips + * Ensure software uses aligned accesses of the correct size to access the system control block registers: + * • except for the CFSR and SHPR1-SHPR3, it must use aligned word accesses + * • for the CFSR and SHPR1-SHPR3 it can use byte or aligned halfword or word accesses. + * + * The processor does not support unaligned accesses to system control block registers + * + * In a fault handler. + * + * to determine the true faulting address: + * 1. Read and save the MMFAR or BFAR value. + * 2. Read the MMARVALID bit in the MMFSR, or the BFARVALID bit in the BFSR. + * + * The MMFAR or BFAR address is valid only if this bit is 1. + * Software must follow this sequence because another higher priority exception might change + * the MMFAR or BFAR value. For example, if a higher priority handler preempts the current + * fault handler, the other fault might change the MMFAR or BFAR value. + */ + +/* SCB Registers */ +#define r_CORTEX_M_SCB_ACTLR REG_ADDR(SCS_BASE + (uint32_t) 0x08) /* (R/W) Auxiliary control register */ + +#define r_CORTEX_M_SCB REG_ADDR(SCB_BASE + (uint32_t) 0x00) +#define r_CORTEX_M_SCB_CPUID REG_ADDR(SCB_BASE + (uint32_t) 0x00) /* (R/ ) CPUID Base Register */ +#define r_CORTEX_M_SCB_ICSR REG_ADDR(SCB_BASE + (uint32_t) 0x04) /* (R/W) Interrupt Control and State Register */ +#define r_CORTEX_M_SCB_VTOR REG_ADDR(SCB_BASE + (uint32_t) 0x08) /* (R/W) Vector Table Offset Register */ +#define r_CORTEX_M_SCB_AIRCR REG_ADDR(SCB_BASE + (uint32_t) 0x0C) /* (R/W) Application Interrupt and Reset Control Register */ +#define r_CORTEX_M_SCB_SCR REG_ADDR(SCB_BASE + (uint32_t) 0x10) /* (R/W) System Control Register */ +#define r_CORTEX_M_SCB_CCR REG_ADDR(SCB_BASE + (uint32_t) 0x14) /* (R/W) Configuration Control Register */ + +#define r_CORTEX_M_SCB_SHPR1 REG_ADDR(SCB_BASE + (uint32_t) 0x18) /* (R/W) System Handlers Priority Registers (4-6) */ +#define r_CORTEX_M_SCB_SHPR2 REG_ADDR(SCB_BASE + (uint32_t) 0x1C) /* (R/W) System Handlers Priority Registers (11) */ +#define r_CORTEX_M_SCB_SHPR3 REG_ADDR(SCB_BASE + (uint32_t) 0x20) /* (R/W) System Handlers Priority Registers (14-15) */ + +#define r_CORTEX_M_SCB_SHCSR REG_ADDR(SCB_BASE + (uint32_t) 0x24) /* (R/W) System Handler Control and State Register */ + +#define r_CORTEX_M_SCB_CFSR REG_ADDR(SCB_BASE + (uint32_t) 0x28) /* (R/W) Configurable Fault Status Register */ +#define r_CORTEX_M_SCB_MMSR REG_ADDR(SCB_BASE + (uint32_t) 0x28) /* (R/W) MemManage Fault Address Register (A subregister of the CFSR) */ +#define r_CORTEX_M_SCB_BFSR REG_ADDR(SCB_BASE + (uint32_t) 0x29) /* (R/W) BusFault Status Register */ +#define r_CORTEX_M_SCB_UFSR REG_ADDR(SCB_BASE + (uint32_t) 0x2a) /* (R/W) UsageFault Status Register */ + +#define r_CORTEX_M_SCB_HFSR REG_ADDR(SCB_BASE + (uint32_t) 0x2c) /* (R/W) Hard fault status register */ +#define r_CORTEX_M_SCB_MMFAR REG_ADDR(SCB_BASE + (uint32_t) 0x34) /* (R/W) Memory management fault address register */ +#define r_CORTEX_M_SCB_BFAR REG_ADDR(SCB_BASE + (uint32_t) 0x38) /* (R/W) Bus fault address register (BFAR) */ +#define r_CORTEX_M_SCB_AFSR REG_ADDR(SCB_BASE + (uint32_t) 0x3c) /* (R/W) Auxiliary fault status register */ + +#define r_CORTEX_M_SCB_CPACR REG_ADDR(SCB_BASE + (uint32_t) 0x88) /* (R/W) Coprocessor Access Control register */ + +/* Auxiliary control register Définitions */ +#define SCB_ACTLR_DISOOFP_Pos 9 /* Bit 9 DISOOFP */ +#define SCB_ACTLR_DISOOFP_Msk ((uint32_t) 0x01 << SCB_ACTLR_DISOOFP_Pos) +#define SCB_ACTLR_DISFPCA_Pos 8 /* Bit 8 DISFPCA */ +#define SCB_ACTLR_DISFPCA_Msk ((uint32_t) 0x01 << SCB_ACTLR_DISFPCA_Pos) +#define SCB_ACTLR_DISFOLD_Pos 2 /* Bit 2 DISFOLD */ +#define SCB_ACTLR_DISFOLD_Msk ((uint32_t) 0x01 << SCB_ACTLR_DISFOLD_Pos) +#define SCB_ACTLR_DISDEFWBUF_Pos 1 /* Bit 1 DISDEFWBUF */ +#define SCB_ACTLR_DISDEFWBUF_Msk ((uint32_t) 0x01 << SCB_ACTLR_DISDEFWBUF_Pos) +#define SCB_ACTLR_DISMCYCINT_Pos 0 /* Bit 0 DISMCYCINT */ +#define SCB_ACTLR_DISMCYCINT_Msk ((uint32_t) 0x01 << SCB_ACTLR_DISMCYCINT_Pos) + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24 /* Bits 31:24 IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk ((uint32_t) 0x00ff << SCB_CPUID_IMPLEMENTER_Pos) + +#define SCB_CPUID_VARIANT_Pos 20 /* Bits 23:20 VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk ((uint32_t) 0x000f << SCB_CPUID_VARIANT_Pos) + +#define SCB_CPUID_ARCHITECTURE_Pos 16 /* Bits 19:16 ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk ((uint32_t) 0x000f << SCB_CPUID_ARCHITECTURE_Pos) + +#define SCB_CPUID_PARTNO_Pos 4 /* Bits 15:4 PartNo Position */ +#define SCB_CPUID_PARTNO_Msk ((uint32_t) 0x0fff << SCB_CPUID_PARTNO_Pos) + +#define SCB_CPUID_REVISION_Pos 0 /* Bits 3:0 Revision Position */ +#define SCB_CPUID_REVISION_Msk ((uint32_t) 0x000f << SCB_CPUID_REVISION_Pos) + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31 /* Bit 31 NMIPENDSET: + NMI set-pending bit position */ +#define SCB_ICSR_NMIPENDSET_Msk ((uint32_t) 0x01 << SCB_ICSR_NMIPENDSET_Pos) + +#define SCB_ICSR_PENDSVSET_Pos 28 /* Bit 28 PENDSVSET: + PendSV set-pending bit Position */ +#define SCB_ICSR_PENDSVSET_Msk ((uint32_t) 0x01 << SCB_ICSR_PENDSVSET_Pos) + +#define SCB_ICSR_PENDSVCLR_Pos 27 /* Bit 27 PENDSVCLR: + PendSV clear-pending bit Position */ +#define SCB_ICSR_PENDSVCLR_Msk ((uint32_t) 0x01 << SCB_ICSR_PENDSVCLR_Pos) + +#define SCB_ICSR_PENDSTSET_Pos 26 /* Bit 26 PENDSTSET: + SysTick exception set-pending bit Position */ +#define SCB_ICSR_PENDSTSET_Msk ((uint32_t) 0x01 << SCB_ICSR_PENDSTSET_Pos) + +#define SCB_ICSR_PENDSTCLR_Pos 25 /* Bit 25 PENDSTCLR: + SysTick exception clear-pending bit Position */ +#define SCB_ICSR_PENDSTCLR_Msk ((uint32_t) 0x01 << SCB_ICSR_PENDSTCLR_Pos) + +#define SCB_ICSR_ISRPREEMPT_Pos 23 /* Bit 23 ISRPREEMPT: + reserved for Debug use and reads-as-zero when + the processor is not in Debug */ +#define SCB_ICSR_ISRPREEMPT_Msk ((uint32_t) 0x01 << SCB_ICSR_ISRPREEMPT_Pos) + +#define SCB_ICSR_ISRPENDING_Pos 22 /* Bit 22 ISRPENDING: + Interrupt pending flag, excluding NMI and Faults */ +#define SCB_ICSR_ISRPENDING_Msk ((uint32_t) 0x01 << SCB_ICSR_ISRPENDING_Pos) + +#define SCB_ICSR_VECTPENDING_Pos 12 /* Bits 18:12 VECTPENDING: Pending vector. + Indicates the exception number of the highest priority + pending enabled exception Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) + +#define SCB_ICSR_RETTOBASE_Pos 11 /* Bit 11 RETTOBASE: Return to base level. + Indicates whether there are preempted active exceptions Position */ +#define SCB_ICSR_RETTOBASE_Msk ((uint32_t) 0x01 << SCB_ICSR_RETTOBASE_Pos) + +#define SCB_ICSR_VECTACTIVE_Pos 0 /* Bits 8:0 VECTACTIVE Active vector. + Contains the active exception number Position */ +#define SCB_ICSR_VECTACTIVE_Msk ((uint32_t) 0x1FF << SCB_ICSR_VECTACTIVE_Pos) + +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 9 /* Bits 29:9 TBLOFF: Vector table base offset field */ +#define SCB_VTOR_TBLOFF_Msk ((uint32_t) 0x1fffff << SCB_VTOR_TBLOFF_Pos) + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16 /* Bits 31:16 VECTKEYSTAT/ VECTKEY Register key */ +#define SCB_AIRCR_VECTKEY_Msk ((uint32_t) 0xFFFF << SCB_AIRCR_VECTKEY_Pos) + +#define SCB_AIRCR_ENDIANESS_Pos 15 /* Bit 15 ENDIANESS Data endianness bit */ +#define SCB_AIRCR_ENDIANESS_Msk ((uint32_t) 0x01 << SCB_AIRCR_ENDIANESS_Pos) + +#define SCB_AIRCR_PRIGROUP_Pos 8 /* Bits 10:8 PRIGROUP: Interrupt priority grouping field */ +#define SCB_AIRCR_PRIGROUP_Msk ((uint32_t) 0x07 << SCB_AIRCR_PRIGROUP_Pos) + +#define SCB_AIRCR_SYSRESETREQ_Pos 2 /* Bit 2 SYSRESETREQ System reset request */ +#define SCB_AIRCR_SYSRESETREQ_Msk ((uint32_t) 0x01 << SCB_AIRCR_SYSRESETREQ_Pos) + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1 /* Bit 1 VECTCLRACTIVE Reserved for Debug use. + This bit reads as 0. + When writing to the register you must write 0 to + this bit, otherwise behavior is unpredictable. */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk ((uint32_t) 0x01 << SCB_AIRCR_VECTCLRACTIVE_Pos) + +#define SCB_AIRCR_VECTRESET_Pos 0 /* Bit 0 VECTRESET + Reserved for Debug use. + This bit reads as 0. + When writing to the register you must write 0 to + this bit, otherwise behavior is unpredictable. */ +#define SCB_AIRCR_VECTRESET_Msk ((uint32_t) 0x01 << SCB_AIRCR_VECTRESET_Pos) + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4 /* Bit 4 SEVEONPEND Send Event on Pending bit */ +#define SCB_SCR_SEVONPEND_Msk ((uint32_t) 0x01 << SCB_SCR_SEVONPEND_Pos) + +#define SCB_SCR_SLEEPDEEP_Pos 2 /* Bit 2 SLEEPDEEP */ +#define SCB_SCR_SLEEPDEEP_Msk ((uint32_t) 0x01 << SCB_SCR_SLEEPDEEP_Pos) + +#define SCB_SCR_SLEEPONEXIT_Pos 1 /* Bit 1 SLEEPONEXIT */ +#define SCB_SCR_SLEEPONEXIT_Msk ((uint32_t) 0x01 << SCB_SCR_SLEEPONEXIT_Pos) + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9 /* Bit 9 STKALIGN */ +#define SCB_CCR_STKALIGN_Msk ((uint32_t) 0x01 << SCB_CCR_STKALIGN_Pos) + +#define SCB_CCR_BFHFNMIGN_Pos 8 /* Bit 8 BFHFNMIGN */ +#define SCB_CCR_BFHFNMIGN_Msk ((uint32_t) 0x01 << SCB_CCR_BFHFNMIGN_Pos) + +#define SCB_CCR_DIV_0_TRP_Pos 4 /* Bit 4 DIV_0_TRP */ +#define SCB_CCR_DIV_0_TRP_Msk ((uint32_t) 0x01 << SCB_CCR_DIV_0_TRP_Pos) + +#define SCB_CCR_UNALIGN_TRP_Pos 3 /* Bit 3 UNALIGN_ TRP */ +#define SCB_CCR_UNALIGN_TRP_Msk ((uint32_t) 0x01 << SCB_CCR_UNALIGN_TRP_Pos) + +#define SCB_CCR_USERSETMPEND_Pos 1 /* Bit 1 USERSETMPEND */ +#define SCB_CCR_USERSETMPEND_Msk ((uint32_t) 0x01 << SCB_CCR_USERSETMPEND_Pos) + +#define SCB_CCR_NONBASETHRDENA_Pos 0 /* Bit 0 NONBASETHRDENA */ +#define SCB_CCR_NONBASETHRDENA_Msk ((uint32_t) 0x01 << SCB_CCR_NONBASETHRDENA_Pos) + +//System handler priority register 1 (SHPR1) +#define SCB_SHPR1_PRI_4_Pos 0 /* Bits 7:0 PRI_4: + Priority of system handler 4, + memory management fault */ +#define SCB_SHPR1_PRI_4_Msk ((uint32_t) 0xff << SCB_SHPR1_PRI_4_Pos) + +#define SCB_SHPR1_PRI_5_Pos 8 /* Bits 15:8 PRI_5: + Priority of system handler 5, bus fault */ +#define SCB_SHPR1_PRI_5_Msk ((uint32_t) 0xff << SCB_SHPR1_PRI_5_Pos) + +//System handler priority register 2 (SHPR2) +#define SCB_SHPR2_PRI_6_Pos 16 /* Bits 23:16 PRI_6: + Priority of system handler 6, usage fault */ +#define SCB_SHPR2_PRI_6_Msk ((uint32_t) 0xff << SCB_SHPR2_PRI_6_Pos) +#define SCB_SHPR2_PRI_11_Pos 24 /* Bits 31:24 PRI_11: + Priority of system handler 11, SVCall */ +#define SCB_SHPR2_PRI_11_Msk ((uint32_t) 0xff << SCB_SHPR2_PRI_11_Pos) + +//System handler priority register 3 (SHPR3) +#define SCB_SHPR3_PRI_14_Pos 16 /* Bits 23:16 PRI_14: + Priority of system handler 14, PendSV */ +#define SCB_SHPR3_PRI_14_Msk ((uint32_t) 0xff << SCB_SHPR3_PRI_14_Pos) +#define SCB_SHPR3_PRI_15_Pos 24 /* Bits 31:24 PRI_15: + Priority of system handler 15, SysTick exception */ +#define SCB_SHPR3_PRI_15_Msk ((uint32_t) 0xff << SCB_SHPR3_PRI_15_Pos) + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_USGFAULTENA_Pos 18 /* Bit 18 USGFAULTENA: + Usage fault enable bit, set to 1 to enable */ +#define SCB_SHCSR_USGFAULTENA_Msk ((uint32_t) 0x01 << SCB_SHCSR_USGFAULTENA_Pos) + +#define SCB_SHCSR_BUSFAULTENA_Pos 17 /* Bit 17 BUSFAULTENA: + Bus fault enable bit, set to 1 to enabl */ +#define SCB_SHCSR_BUSFAULTENA_Msk ((uint32_t) 0x01 << SCB_SHCSR_BUSFAULTENA_Pos) + +#define SCB_SHCSR_MEMFAULTENA_Pos 16 /* Bit 16 MEMFAULTENA: + Memory management fault enable bit, + set to 1 to enable */ +#define SCB_SHCSR_MEMFAULTENA_Msk ((uint32_t) 0x01 << SCB_SHCSR_MEMFAULTENA_Pos) + +#define SCB_SHCSR_SVCALLPENDED_Pos 15 /* Bit 15 SVCALLPENDED: + SVC call pending bit, + reads as 1 if exception is pending */ +#define SCB_SHCSR_SVCALLPENDED_Msk ((uint32_t) 0x01 << SCB_SHCSR_SVCALLPENDED_Pos) + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14 /* Bit 14 BUSFAULTPENDED: + Bus fault exception pending bit, + reads as 1 if exception is pending */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk ((uint32_t) 0x01 << SCB_SHCSR_BUSFAULTPENDED_Pos) + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13 /* Bit 13 MEMFAULTPENDED: + Memory management fault exception pending bit, + reads as 1 if exception is pending */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk ((uint32_t) 0x01 << SCB_SHCSR_MEMFAULTPENDED_Pos) + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12 /* Bit 12 USGFAULTPENDED: + Usage fault exception pending bit, + reads as 1 if exception is pending */ +#define SCB_SHCSR_USGFAULTPENDED_Msk ((uint32_t) 0x01 << SCB_SHCSR_USGFAULTPENDED_Pos) + +#define SCB_SHCSR_SYSTICKACT_Pos 11 /* Bit 11 SYSTICKACT: + SysTick exception active bit, + reads as 1 if exception is active */ +#define SCB_SHCSR_SYSTICKACT_Msk ((uint32_t) 0x01 << SCB_SHCSR_SYSTICKACT_Pos) + +#define SCB_SHCSR_PENDSVACT_Pos 10 /* Bit 10 PENDSVACT: + PendSV exception active bit, + reads as 1 if exception is activen */ +#define SCB_SHCSR_PENDSVACT_Msk ((uint32_t) 0x01 << SCB_SHCSR_PENDSVACT_Pos) + +#define SCB_SHCSR_MONITORACT_Pos 8 /* Bit 8 MONITORACT: + Debug monitor active bit, + reads as 1 if Debug monitor is active */ +#define SCB_SHCSR_MONITORACT_Msk ((uint32_t) 0x01 << SCB_SHCSR_MONITORACT_Pos) + +#define SCB_SHCSR_SVCALLACT_Pos 7 /* Bit 7 SVCALLACT: + SVC call active bit, + reads as 1 if SVC call is active */ +#define SCB_SHCSR_SVCALLACT_Msk ((uint32_t) 0x01 << SCB_SHCSR_SVCALLACT_Pos) + +#define SCB_SHCSR_USGFAULTACT_Pos 3 /* Bit 3 USGFAULTACT: + Usage fault exception active bit, + reads as 1 if exception is active */ +#define SCB_SHCSR_USGFAULTACT_Msk ((uint32_t) 0x01 << SCB_SHCSR_USGFAULTACT_Pos) + +#define SCB_SHCSR_BUSFAULTACT_Pos 1 /* Bit 1 BUSFAULTACT: + Bus fault exception active bit, + reads as 1 if exception is active */ +#define SCB_SHCSR_BUSFAULTACT_Msk ((uint32_t) 0x01 << SCB_SHCSR_BUSFAULTACT_Pos) + +#define SCB_SHCSR_MEMFAULTACT_Pos 0 /* Bit 0 MEMFAULTACT: + Memory management fault exception active bit, + reads as 1 if exception is active */ +#define SCB_SHCSR_MEMFAULTACT_Msk ((uint32_t) 0x01 << SCB_SHCSR_MEMFAULTACT_Pos) + +/* Configurable fault status register (CFSR; UFSR+BFSR+MMFSR) + * The CFSR is byte accessible. You can access the CFSR or its subregisters as follows: + * • Access the complete CFSR with a word access to 0xE000ED28 + * • Access the MMFSR with a byte access to 0xE000ED28 + * • Access the MMFSR and BFSR with a halfword access to 0xE000ED28 + * • Access the BFSR with a byte access to 0xE000ED29 + * • Access the UFSR with a halfword access to 0xE000ED2A. + * + * The CFSR indicates the cause of a memory management fault, bus fault, or usage fault. + */ + +#define SCB_CFSR_UFSR_Pos 16 /* Bits 31:16 UFSR: + Usage fault status register (UFSR) */ +#define SCB_CFSR_UFSR_Msk ((uint32_t) 0xffff << SCB_CFSR_UFSR_Pos) +#define SCB_CFSR_BFSR_Pos 8 /* Bits 15:8 BFSR: + Bus fault status register (BFSR) */ +#define SCB_CFSR_BFSR_Msk ((uint32_t) 0xff << SCB_CFSR_BFSR_Pos) +#define SCB_CFSR_MMFSR_Pos 0 /* Bits 7:0 MMFSR: + Memory management fault address register (MMFSR) */ +#define SCB_CFSR_MMFSR_Msk ((uint32_t) 0xff << SCB_CFSR_MMFSR_Pos) + + /* Usage fault status register (UFSR) */ +#define SCB_CFSR_UFSR_DIVBYZERO_Pos 25 /* Bit 25 DIVBYZERO: + Divide by zero usage fault. */ +#define SCB_CFSR_UFSR_DIVBYZERO_Msk ((uint32_t) 0x01 << SCB_UFSR_DIVBYZERO_Pos) +#define SCB_CFSR_UFSR_UNALIGNED_Pos 24 /* Bit 24 UNALIGNED: + Unaligned access usage fault. */ +#define SCB_CFSR_UFSR_UNALIGNED_Msk ((uint32_t) 0x01 << SCB_UFSR_UNALIGNED_Pos) +#define SCB_CFSR_UFSR_NOCP_Pos 19 /* Bit 19 NOCP: + No coprocessor usage fault. */ +#define SCB_CFSR_UFSR_NOCP_Msk ((uint32_t) 0x01 << SCB_UFSR_NOCP_Pos) +#define SCB_CFSR_UFSR_INVPC_Pos 18 /* Bit 18 INVPC: + Invalid PC load usage fault, + caused by an invalid PC load by EXC_RETURN */ +#define SCB_CFSR_UFSR_INVPC_Msk ((uint32_t) 0x01 << SCB_UFSR_INVPC_Pos) +#define SCB_CFSR_UFSR_INVSTATE_Pos 17 /* Bit 17 INVSTATE: + Invalid state usage fault. */ +#define SCB_CFSR_UFSR_INVSTATE_Msk ((uint32_t) 0x01 << SCB_UFSR_INVSTATE_Pos) +#define SCB_CFSR_UFSR_UNDEFINSTR_Pos 16 /* Bit 16 UNDEFINSTR: + Undefined instruction usage fault. */ +#define SCB_CFSR_UFSR_UNDEFINSTR_Msk ((uint32_t) 0x01 << SCB_UFSR_UNDEFINSTR_Pos) + +/* Bus fault status register (BFSR) */ +#define SCB_CFSR_BFSR_BFARVALID_Pos 15 /* Bit 15 BFARVALID: + Bus Fault Address Register (BFAR) valid flag. + The processor sets this bit to 1 */ +#define SCB_CFSR_BFSR_BFARVALID_Msk ((uint32_t) 0x01 << SCB_BFSR_BFARVALID_Pos) +#define SCB_CFSR_BFSR_LSPERR_Pos 13 /* Bit 13 LSPERR: + Bus fault on floating-point lazy state preservation. */ +#define SCB_CFSR_BFSR_LSPERR_Msk ((uint32_t) 0x01 << SCB_BFSR_LSPERR_Pos) +#define SCB_CFSR_BFSR_STKERR_Pos 12 /* Bit 12 STKERR: + Bus fault on stacking for exception entry. */ +#define SCB_CFSR_BFSR_STKERR_Msk ((uint32_t) 0x01 << SCB_BFSR_STKERR_Pos) +#define SCB_CFSR_BFSR_UNSTKERR_Pos 11 /* Bit 11 UNSTKERR: + Bus fault on unstacking for a return from exception. */ +#define SCB_CFSR_BFSR_UNSTKERR_Msk ((uint32_t) 0x01 << SCB_BFSR_UNSTKERR_Pos) +#define SCB_CFSR_BFSR_IMPRECISERR_Pos 10 /* Bit 10 IMPRECISERR: + Imprecise data bus error. */ +#define SCB_CFSR_BFSR_IMPRECISERR_Msk ((uint32_t) 0x01 << SCB_BFSR_IMPRECISERR_Pos) +#define SCB_CFSR_BFSR_PRECISERR_Pos 9 /* Bit 9 PRECISERR: + Precise data bus error. */ +#define SCB_CFSR_BFSR_PRECISERR_Msk ((uint32_t) 0x01 << SCB_BFSR_PRECISERR_Pos) +#define SCB_CFSR_BFSR_IBUSERR_Pos 8 /* Bit 8 IBUSERR: + Instruction bus error. */ +#define SCB_CFSR_BFSR_IBUSERR_Msk ((uint32_t) 0x01 << SCB_BFSR_IBUSERR_Pos) + +/* Memory management fault address register (MMFSR)*/ +#define SCB_CFSR_MMFSR_MMARVALID_Pos 7 /* Bit 7 MMARVALID: + Memory Management Fault Address Register (MMAR) valid flag. */ +#define SCB_CFSR_MMFSR_MMARVALID_Msk ((uint32_t) 0x01 << SCB_CFSR_MMFSR_MMARVALID_Pos) +#define SCB_CFSR_MMFSR_MLSPERR_Pos 5 /* Bit 5 MLSPERR: + MemManage fault status */ +#define SCB_CFSR_MMFSR_MLSPERR_Msk ((uint32_t) 0x01 << SCB_CFSR_MMFSR_MLSPERR_Pos) +#define SCB_CFSR_MMFSR_MSTKERR_Pos 4 /* Bit 4 MSTKERR: + Memory manager fault on stacking for exception entry. */ +#define SCB_CFSR_MMFSR_MSTKERR_Msk ((uint32_t) 0x01 << SCB_CFSR_MMFSR_MSTKERR_Pos) +#define SCB_CFSR_MMFSR_MUNSTKERR_Pos 3 /* Bit 3 MUNSTKERR: + Memory manager fault on unstacking + for a return from exception. */ +#define SCB_CFSR_MMFSR_MUNSTKERR_Msk ((uint32_t) 0x01 << SCB_CFSR_MMFSR_MUNSTKERR_Pos) +#define SCB_CFSR_MMFSR_DACCVIOL_Pos 1 /* Bit 1 DACCVIOL: + Data access violation flag. */ +#define SCB_CFSR_MMFSR_DACCVIOL_Msk ((uint32_t) 0x01 << SCB_CFSR_MMFSR_DACCVIOL_Pos) + +#define SCB_CFSR_MMFSR_IACCVIOL_Pos 0 /* Bit 0 IACCVIOL: + Instruction access violation flag. + This fault occurs on any access to an XN region */ +#define SCB_CFSR_MMFSR_IACCVIOL_Msk ((uint32_t) 0x01 << SCB_CFSR_MMFSR_Pos) + +/* Hard fault status register (HFSR)*/ +#define SCB_HFSR_DEBUG_VT_Pos 31 /* Bit 31 DEBUG_VT: + Reserved for Debug use. + When writing to the register you must write 0 to this bit */ +#define SCB_HFSR_DEBUG_VT_Msk ((uint32_t) 0x01 << SCB_HFSR_DEBUG_VT_Pos) + +#define SCB_HFSR_FORCED_Pos 30 /* Bit 30 FORCED: + Forced hard fault. + Indicates a forced hard fault, + generated by escalation of a fault */ +#define SCB_HFSR_FORCED_Msk ((uint32_t) 0x01 << SCB_HFSR_FORCED_Pos) + +#define SCB_HFSR_VECTTBL_Pos 1 /* Bit 1 VECTTBL: + Vector table hard fault. + Indicates a bus fault on a vector table read during */ +#define SCB_HFSR_VECTTBL_Msk ((uint32_t) 0x01 << SCB_HFSR_VECTTBL_Pos) + +/* Memory management fault address register (MMFAR) */ +#define SCB_MMFAR_Pos 0 /* Bits 31:0 MMFAR: Memory management fault address */ +#define SCB_MMFAR_Msk ((uint32_t) 0xffffffff << SCB_MMFAR_Pos) + +/* Bus fault address register (BFAR) */ +#define SCB_BFAR_Pos 0 /* Bits 31:0 Bus fault address + When the BFARVALID bit of the BFSR is set to 1, + this field holds the address f the location that + generated the bus fault. When an unaligned access faults + the address in the BFAR is the one requested by the instruction, + even if it is not the adress of the fault. */ +#define SCB_BFAR_Msk ((uint32_t) 0xffffffff << SCB_BFAR_Pos) + +/* Auxiliary fault status register (AFSR) */ +#define SCB_AFSR_IMPDEF_Pos 0 /* Bits 31:0 IMPDEF: + Implementation defined. + The AFSR contains additional system fault information. */ +#define SCB_AFSR_IMPDEF_Msk ((uint32_t) 0xffffffff << SCB_AFSR_IMPDEF_Pos) +#endif /* SOC_SCB_H */ diff --git a/arch/socs/stm32f439/soc-syscfg.h b/arch/socs/stm32f439/soc-syscfg.h new file mode 100644 index 0000000..9c55d47 --- /dev/null +++ b/arch/socs/stm32f439/soc-syscfg.h @@ -0,0 +1,39 @@ +/* \file soc-syscfg.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_SYSCFG_H +#define SOC_SYSCFG_H + +#include "soc-core.h" + +#define SYSCFG_MEMRMP ((uint32_t*)(SYSCFG_BASE+0x0)) +#define SYSCFG_PMC ((uint32_t*)(SYSCFG_BASE+0x4)) +#define SYSCFG_EXTICR1 ((uint32_t*)(SYSCFG_BASE+0x8)) +#define SYSCFG_EXTICR2 ((uint32_t*)(SYSCFG_BASE+0x0C)) +#define SYSCFG_EXTICR3 ((uint32_t*)(SYSCFG_BASE+0x10)) +#define SYSCFG_EXTICR4 ((uint32_t*)(SYSCFG_BASE+0x14)) +#define SYSCFG_CMPCR ((uint32_t*)(SYSCFG_BASE+0x20)) + +#define SYSCFG_EXTICR_FIELD_MASK 0xf + + +#endif /*!SOC_SYSCFG_H */ diff --git a/arch/socs/stm32f439/soc-usart-regs.h b/arch/socs/stm32f439/soc-usart-regs.h new file mode 100644 index 0000000..4009737 --- /dev/null +++ b/arch/socs/stm32f439/soc-usart-regs.h @@ -0,0 +1,433 @@ +/* \file soc-usart-regs.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SOC_USART_REGS_H +#define SOC_USART_REGS_H + +#include "soc-core.h" + +/* Add some aliases for UART4 and UART 5 */ +#define USART4_BASE UART4_BASE +#define USART5_BASE UART5_BASE + +#define _r_CORTEX_M_USART_SR(n) REG_ADDR(USART ## n ## _BASE + 0x00) +#define _r_CORTEX_M_USART_DR(n) REG_ADDR(USART ## n ## _BASE + 0x04) +#define _r_CORTEX_M_USART_BRR(n) REG_ADDR(USART ## n ## _BASE + 0x08) +#define _r_CORTEX_M_USART_CR1(n) REG_ADDR(USART ## n ## _BASE + 0x0c) +#define _r_CORTEX_M_USART_CR2(n) REG_ADDR(USART ## n ## _BASE + 0x10) +#define _r_CORTEX_M_USART_CR3(n) REG_ADDR(USART ## n ## _BASE + 0x14) +#define _r_CORTEX_M_USART_GTPR(n) REG_ADDR(USART ## n ## _BASE + 0x18) + +/***** Status register *****/ +/* Bit 0 PE: Parity error */ +#define USART_SR_PE_Pos 0 +#define USART_SR_PE_Msk ((uint32_t)1 << USART_SR_PE_Pos) +#define USART_SR_PE_OK ((uint32_t)0 << USART_SR_PE_Pos) +#define USART_SR_PE_ERROR ((uint32_t)1 << USART_SR_PE_Pos) + +/* Bit 1 FE: Framing error */ +#define USART_SR_FE_Pos 1 +#define USART_SR_FE_Msk ((uint32_t)1 << USART_SR_FE_Pos) +#define USART_SR_FE_OK ((uint32_t)0 << USART_SR_FE_Pos) +#define USART_SR_FE_ERROR ((uint32_t)1 << USART_SR_FE_Pos) + +/* Bit 2 NF: Noise detected flag */ +#define USART_SR_NF_Pos 2 +#define USART_SR_NF_Msk ((uint32_t)1 << USART_SR_NF_Pos) +#define USART_SR_NF_OK ((uint32_t)0 << USART_SR_NF_Pos) +#define USART_SR_NF_ERROR ((uint32_t)1 << USART_SR_NF_Pos) + +/* Bit 3 ORE: Overrun error */ +#define USART_SR_OVERRUN_Pos 3 +#define USART_SR_OVERRUN_Msk ((uint32_t)1 << USART_SR_OVERRUN_Pos) +#define USART_SR_OVERRUN_OK ((uint32_t)0 << USART_SR_OVERRUN_Pos) +#define USART_SR_OVERRUN_ERROR ((uint32_t)1 << USART_SR_OVERRUN_Pos) + +/* Bit 4 IDLE: IDLE line detected */ +#define USART_SR_IDLE_Pos 4 +#define USART_SR_IDLE_Msk ((uint32_t)1 << USART_SR_IDLE_Pos) +#define USART_SR_IDLE_NO_IDLE ((uint32_t)0 << USART_SR_IDLE_Pos) +#define USART_SR_IDLE_IDLE ((uint32_t)1 << USART_SR_IDLE_Pos) + +#define USART_SR_RXNE_Pos 5 +#define USART_SR_RXNE_Msk ((uint32_t)1 << USART_SR_RXNE_Pos) +#define USART_SR_RXNE_EMPTY ((uint32_t)0 << USART_SR_RXNE_Pos) +#define USART_SR_RXNE_RDY ((uint32_t)1 << USART_SR_RXNE_Pos) + +/* Bit 6 TC: Transmission complete */ +#define USART_SR_TC_Pos 6 +#define USART_SR_TC_Msk ((uint32_t)1 << USART_SR_TC_Pos) +#define USART_SR_TC_RUNNING ((uint32_t)0 << USART_SR_TC_Pos) +#define USART_SR_TC_COMPLETE ((uint32_t)1 << USART_SR_TC_Pos) + +/* Bit 6 TC: Transmission complete */ +#define USART_SR_TXE_Pos 7 +#define USART_SR_TXE_Msk ((uint32_t)1 << USART_SR_TXE_Pos) +#define USART_SR_TXE_DATA_NOT_TRANSFERED ((uint32_t)0 << USART_SR_TXE_Pos) +#define USART_SR_TXE_DATA_TRANSFERED ((uint32_t)1 << USART_SR_TXE_Pos) + +/* Bit 8 LBD: LIN break detection flag */ +#define USART_SR_LIN_Pos 8 +#define USART_SR_LIN_Msk ((uint32_t)1 << USART_SR_LIN_Pos) +#define USART_SR_LIN_NO_LINE_BREAK ((uint32_t)0 << USART_SR_LIN_Pos) +#define USART_SR_LIN_LINE_BREAK ((uint32_t)1 << USART_SR_LIN_Pos) + +/* Bit 9 CTS: CTS flag */ +#define USART_SR_CTS_Pos 9 +#define USART_SR_CTS_Msk ((uint32_t)1 << USART_SR_CTS_Pos) +#define USART_SR_CTS_NO_CHANGE ((uint32_t)0 << USART_SR_CTS_Pos) +#define USART_SR_CTS_CHANGED ((uint32_t)1 << USART_SR_CTS_Pos) + +/***** Data register *****/ +/* Bits 8:0 DR[8:0]: Data value */ +#define USART_DR_DR_Pos 0 +#define USART_DR_DR_Msk ((uint32_t)0xff << USART_DR_DR_Pos) + +/* Baud rate register */ +/* Bits 3:0 DIV_Fraction[3:0]: fraction of USARTDIV */ +#define USART_BRR_FRACTION_Pos 0 +#define USART_BRR_FRACTION_Msk ((uint32_t)0xf << USART_BRR_FRACTION_Pos) + +/* Bits 15:4 DIV_Mantissa[11:0]: mantissa of USARTDIV */ +#define USART_BRR_MANTISSA_Pos 4 +#define USART_BRR_MANTISSA_Msk ((uint32_t)0xfff << USART_BRR_MANTISSA_Pos) + +/***** Control register 1 *****/ +/* Bit 0 SBK: Send break */ +#define USART_CR1_SBK_Pos 0 +#define USART_CR1_SBK_Msk ((uint32_t)1 << USART_CR1_SBK_Pos) + +/* Bit 1 RWU: Receiver wakeup */ +#define USART_CR1_RWU_Pos 1 +#define USART_CR1_RWU_Msk ((uint32_t)1 << USART_CR1_RWU_Pos) + +/* Bit 2 RE: Receiver enable */ +#define USART_CR1_RE_Pos 2 +#define USART_CR1_RE_Msk ((uint32_t)1 << USART_CR1_RE_Pos) +#define USART_CR1_RE_EN ((uint32_t)1 << USART_CR1_RE_Pos) +#define USART_CR1_RE_DIS ((uint32_t)0 << USART_CR1_RE_Pos) + +/* Bit 3 TE: Transmitter enable */ +#define USART_CR1_TE_Pos 3 +#define USART_CR1_TE_Msk ((uint32_t)1 << USART_CR1_TE_Pos) +#define USART_CR1_TE_EN ((uint32_t)1 << USART_CR1_TE_Pos) +#define USART_CR1_TE_DIS ((uint32_t)0 << USART_CR1_TE_Pos) + +/* Bit 4 IDLEIE: IDLE interrupt enable */ +#define USART_CR1_IDLEIE_Pos 5 +#define USART_CR1_IDLEIE_Msk ((uint32_t)1 << USART_CR1_IDLEIE_Pos) + +/* Bit 5 RXNEIE: RXNE interrupt enable */ +#define USART_CR1_RXNEIE_Pos 5 +#define USART_CR1_RXNEIE_Msk ((uint32_t)1 << USART_CR1_RXNEIE_Pos) + +/* Bit 6 TCIE: Transmission complete interrupt enable */ +#define USART_CR1_TCIE_Pos 6 +#define USART_CR1_TCIE_Msk ((uint32_t)1 << USART_CR1_TCIE_Pos) + +/* Bit 7 TXEIE: TXE interrupt enable */ +#define USART_CR1_TXEIE_Pos 7 +#define USART_CR1_TXEIE_Msk ((uint32_t)1 << USART_CR1_TXEIE_Pos) + +/* Bit 8 PEIE: PE interrupt enable */ +#define USART_CR1_PEIE_Pos 8 +#define USART_CR1_PEIE_Msk ((uint32_t)1 << USART_CR1_PEIE_Pos) +#define USART_CR1_PEIE_DIS ((uint32_t)0 << USART_CR1_PEIE_Pos) +#define USART_CR1_PEIE_EN ((uint32_t)1 << USART_CR1_PEIE_Pos) + +/* Bit 9 PS: Parity selection */ +#define USART_CR1_PS_Pos 9 +#define USART_CR1_PS_Msk ((uint32_t)1 << USART_CR1_PS_Pos) +#define USART_CR1_PS_EVEN ((uint32_t)0 << USART_CR1_PS_Pos) +#define USART_CR1_PS_ODD ((uint32_t)1 << USART_CR1_PS_Pos) + +/* Bit 10 PCE: Parity control enable */ +#define USART_CR1_PCE_Pos 10 +#define USART_CR1_PCE_Msk ((uint32_t)1 << USART_CR1_PCE_Pos) +#define USART_CR1_PCE_EN ((uint32_t)1 << USART_CR1_PCE_Pos) +#define USART_CR1_PCE_DIS ((uint32_t)0 << USART_CR1_PCE_Pos) + +/* Bit 11 WAKE: Wakeup method */ +#define USART_CR1_WAKE_Pos 11 +#define USART_CR1_WAKE_Msk ((uint32_t)1 << USART_CR1_WAKE_Pos) + +/* Bit 12 M: Word length */ +#define USART_CR1_M_Pos 12 +#define USART_CR1_M_Msk ((uint32_t)1 << USART_CR1_M_Pos) +#define USART_CR1_M_8 ((uint32_t)0 << USART_CR1_M_Pos) +#define USART_CR1_M_9 ((uint32_t)1 << USART_CR1_M_Pos) + +/* Bit 13 UE: USART enable */ +#define USART_CR1_UE_Pos 13 +#define USART_CR1_UE_Msk ((uint32_t)1 << USART_CR1_UE_Pos) +#define USART_CR1_UE_DIS ((uint32_t)0 << USART_CR1_UE_Pos) +#define USART_CR1_UE_EN ((uint32_t)1 << USART_CR1_UE_Pos) + +/* Bit 15 OVER8: Over sampling */ +#define USART_CR1_OVER8_Pos 15 +#define USART_CR1_OVER8_Msk ((uint32_t)1 << USART_CR1_OVER8_Pos) +#define USART_CR1_OVER_S_8 ((uint32_t)0 << USART_CR1_OVER8_Pos) +#define USART_CR1_OVER_S_16 ((uint32_t)1 << USART_CR1_OVER8_Pos) + +/***** Control register 2 *****/ +/* Bit 14 LINEN: LIN mode enable */ +#define USART_CR2_LINEN_Pos 14 +#define USART_CR2_LINEN_Msk ((uint32_t)1 << USART_CR2_LINEN_Pos) +#define USART_CR2_LINEN_DIS ((uint32_t)0 << USART_CR2_LINEN_Pos) +#define USART_CR2_LINEN_EN ((uint32_t)1 << USART_CR2_LINEN_Pos) + +/* Bits 13:12 STOP: STOP bits */ +#define USART_CR2_STOP_Pos 12 +#define USART_CR2_STOP_Msk ((uint32_t)3 << USART_CR2_STOP_Pos) +#define USART_CR2_STOP_1BIT 0 /* 1 Stop bit */ +#define USART_CR2_STOP_0_5BITS 1 /* 0.5 Stop bit */ +#define USART_CR2_STOP_2BITS 2 /* 2 Stop bit */ +#define USART_CR2_STOP_1_5BITS 3 /* 1.5 Stop bit */ + +/* Bit 11 CLKEN: Clock enable */ +#define USART_CR2_CLKEN_Pos 11 +#define USART_CR2_CLKEN_Msk ((uint32_t)1 << USART_CR2_CLKEN_Pos) +#define USART_CR2_CLKEN_PIN_EN ((uint32_t)1 << USART_CR2_CLKEN_Pos) +#define USART_CR2_CLKEN_PIN_DIS ((uint32_t)0 << USART_CR2_CLKEN_Pos) + +/* Bit 10 CPOL: Clock polarity */ +#define USART_CR2_CPOL_Pos 10 +#define USART_CR2_CPOL_Msk ((uint32_t)1 << USART_CR2_CPOL_Pos) +#define USART_CR2_CPOL_EN ((uint32_t)1 << USART_CR2_CPOL_Pos) +#define USART_CR2_CPOL_DIS ((uint32_t)0 << USART_CR2_CPOL_Pos) + +/* Bit 9 CPHA: Clock phase */ +#define USART_CR2_CPHA_Pos 9 +#define USART_CR2_CPHA_Msk ((uint32_t)1 << USART_CR2_CPHA_Pos) +#define USART_CR2_CPHA_EN ((uint32_t)1 << USART_CR2_CPHA_Pos) +#define USART_CR2_CPHA_DIS ((uint32_t)0 << USART_CR2_CPHA_Pos) + +/* Bit 8 LBCL: Last bit clock pulse */ +#define USART_CR2_LBCL_Pos 8 +#define USART_CR2_LBCL_Msk ((uint32_t)1 << USART_CR2_LBCL_Pos) +#define USART_CR2_LBCL_DIS ((uint32_t)0 << USART_CR2_LBCL_Pos) +#define USART_CR2_LBCL_EN ((uint32_t)1 << USART_CR2_LBCL_Pos) + +/* Bit 6 LBDIE: LIN break detection interrupt enable */ +#define USART_CR2_LBDIE_Pos 6 +#define USART_CR2_LBDIE_Msk ((uint32_t)1 << USART_CR2_LBDIE_Pos) +#define USART_CR2_LBDIE_EN ((uint32_t)1 << USART_CR2_LBDIE_Pos) /* An interrupt is generated whenever LBD=1 in the USART_SR register */ +#define USART_CR2_LBDIE_DIS ((uint32_t)0 << USART_CR2_LBDIE_Pos) /* Interrupt is inhibited */ + +/* Bit 5 LBDL: lin break detection length */ +#define USART_CR2_LBDL_Pos 5 +#define USART_CR2_LBDL_Msk ((uint32_t)1 << USART_CR2_LBDL_Pos) +#define USART_CR2_LBDL_10 ((uint32_t)0 << USART_CR2_LBDL_Pos) +#define USART_CR2_LBDL_11 ((uint32_t)1 << USART_CR2_LBDL_Pos) + +/* Bits 3:0 ADD[3:0]: Address of the USART node */ +#define USART_CR2_ADD_Pos 0 +#define USART_CR2_ADD_Msk ((uint32_t)4 << USART_CR2_ADD_Pos) + +/***** Control register 3 ******/ +/* Bit 11 ONEBIT: One sample bit method enable */ +#define USART_CR3_ONEBIT_Pos 11 +#define USART_CR3_ONEBIT_Msk ((uint32_t)1 << USART_CR3_ONEBIT_Pos) +#define USART_CR3_ONEBIT_3_SPL_BIT ((uint32_t)0 << USART_CR3_ONEBIT_Pos) +#define USART_CR3_ONEBIT_1_SPL_BIT ((uint32_t)1 << USART_CR3_ONEBIT_Pos) + +/* Bit 10 CTSIE: CTS interrupt enable */ +#define USART_CR3_CTSIE_Pos 10 +#define USART_CR3_CTSIE_Msk ((uint32_t)1 << USART_CR3_CTSIE_Pos) +#define USART_CR3_CTSIE_DIS ((uint32_t)0 << USART_CR3_CTSIE_Pos) +#define USART_CR3_CTSIE_EN ((uint32_t)1 << USART_CR3_CTSIE_Pos) + +/* Bit 9 CTSE: CTS enable */ +/* Note: This bit is not available for UART4 & UART5. */ +#define USART_CR3_CTSE_Pos 9 +#define USART_CR3_CTSE_Msk ((uint32_t)1 << USART_CR3_CTSE_Pos) +#define USART_CR3_CTSE_CTS_DIS ((uint32_t)0 << USART_CR3_CTSE_Pos) +#define USART_CR3_CTSE_CTS_EN ((uint32_t)1 << USART_CR3_CTSE_Pos) + +/* Bit 8 RTSE: RTS enable */ +/* Note: This bit is not available for UART4 & UART5. */ +#define USART_CR3_RTSE_Pos 8 +#define USART_CR3_RTSE_Msk ((uint32_t)1 << USART_CR3_RTSE_Pos) +#define USART_CR3_RTSE_RTS_DIS ((uint32_t)0 << USART_CR3_RTSE_Pos) +#define USART_CR3_RTSE_RTS_EN ((uint32_t)1 << USART_CR3_RTSE_Pos) + +/* Bit 7 DMAT: DMA enable transmitter */ +#define USART_CR3_DMAT_Pos 7 +#define USART_CR3_DMAT_Msk ((uint32_t)1 << USART_CR3_DMAT_Pos) +#define USART_CR3_DMAT_DIS ((uint32_t)0 << USART_CR3_DMAT_Pos) +#define USART_CR3_DMAT_EN ((uint32_t)1 << USART_CR3_DMAT_Pos) + +/* Bit 6 DMAR: DMA enable receiver */ +#define USART_CR3_DMAR_Pos 6 +#define USART_CR3_DMAR_Msk ((uint32_t)1 << USART_CR3_DMAR_Pos) +#define USART_CR3_DMAR_DIS ((uint32_t)0 << USART_CR3_DMAR_Pos) +#define USART_CR3_DMAR_EN ((uint32_t)1 << USART_CR3_DMAR_Pos) + +/* Bit 5 SCEN: Smartcard mode enable */ +/* Note: This bit is not available for UART4 & UART5. */ +#define USART_CR3_SCEN_Pos 5 +#define USART_CR3_SCEN_Msk ((uint32_t)1 << USART_CR3_SCEN_Pos) +#define USART_CR3_SCEN_DIS ((uint32_t)0 << USART_CR3_SCEN_Pos) +#define USART_CR3_SCEN_EN ((uint32_t)1 << USART_CR3_SCEN_Pos) + +/* Bit 4 NACK: Smartcard NACK enable */ +/* Note: This bit is not available for UART4 & UART5. */ +#define USART_CR3_NACK_Pos 4 +#define USART_CR3_NACK_Msk ((uint32_t)1 << USART_CR3_NACK_Pos) +#define USART_CR3_NACK_DIS ((uint32_t)0 << USART_CR3_NACK_Pos) +#define USART_CR3_NACK_EN ((uint32_t)1 << USART_CR3_NACK_Pos) + +/* Bit 3 HDSEL: Half-duplex selection */ +#define USART_CR3_HDSEL_Pos 3 +#define USART_CR3_HDSEL_Msk ((uint32_t)1 << USART_CR3_HDSEL_Pos) +#define USART_CR3_HDSEL_DIS ((uint32_t)0 << USART_CR3_HDSEL_Pos) +#define USART_CR3_HDSEL_EN ((uint32_t)1 << USART_CR3_HDSEL_Pos) + +/* Bit 2 IRLP: IrDA low-power */ +#define USART_CR3_IRLP_Pos 2 +#define USART_CR3_IRLP_Msk ((uint32_t)1 << USART_CR3_IRLP_Pos) +#define USART_CR3_IRLP_NORMAL ((uint32_t)0 << USART_CR3_IRLP_Pos) +#define USART_CR3_IRLP_LOW_POWER ((uint32_t)1 << USART_CR3_IRLP_Pos) + +/* Bit 1 IREN: IrDA mode enable */ +#define USART_CR3_IREN_Pos 1 +#define USART_CR3_IREN_Msk ((uint32_t)1 << USART_CR3_IREN_Pos) +#define USART_CR3_IREN_DIS ((uint32_t)0 << USART_CR3_IREN_Pos) +#define USART_CR3_IREN_EN ((uint32_t)1 << USART_CR3_IREN_Pos) + +/* Bit 0 EIE: Error interrupt enable */ +#define USART_CR3_EIE_Pos 0 +#define USART_CR3_EIE_Msk ((uint32_t)1 << USART_CR3_EIE_Pos) +#define USART_CR3_EIE_DIS ((uint32_t)0 << USART_CR3_EIE_Pos) +#define USART_CR3_EIE_EN ((uint32_t)1 << USART_CR3_EIE_Pos) + +/***** Guard time and prescaler register (USART_GTPR) ******/ +/* Bits 15:8 GT[7:0]: Guard time value */ +#define USART_GTPR_GT_Pos 8 +#define USART_GTPR_GT_Msk ((uint32_t)(0xff) << USART_GTPR_GT_Pos) + +/* Bits 7:0 PSC[7:0]: Prescaler value */ +#define USART_GTPR_PSC_Pos 0 +#define USART_GTPR_PSC_Msk ((uint32_t)(0xff) << USART_GTPR_PSC_Pos) +/* +n IrDA Low-power mode: +PSC[7:0] = IrDA Low-Power Baud Rate +Used for programming the prescaler for dividing the system clock to achieve the low-power +frequency: +The source clock is divided by the value given in the register (8 significant bits): +00000000: Reserved - do not program this value +00000001: divides the source clock by 1 +00000010: divides the source clock by 2 +... + */ +#define USART_GTPR_PSC_IRDA_LOW_DIV1 ((uint32_t)(0x1) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_IRDA_LOW_DIV2 ((uint32_t)(0x2) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_IRDA_LOW_DIV4 ((uint32_t)(0x4) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_IRDA_LOW_DIV8 ((uint32_t)(0x8) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_IRDA_LOW_DIV16 ((uint32_t)(0x10) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_IRDA_LOW_DIV32 ((uint32_t)(0x20) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_IRDA_LOW_DIV64 ((uint32_t)(0x40) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_IRDA_LOW_DIV128 ((uint32_t)(0x80) << USART_GTPR_PSC_Pos) +/* +In normal IrDA mode: PSC must be set to 00000001. + */ +#define USART_GTPR_PSC_IRDA_HIGH_DIV ((uint32_t)(0x1) << USART_GTPR_PSC_Pos) +/* +In smartcard mode: +PSC[4:0]: Prescaler value +Used for programming the prescaler for dividing the system clock to provide the smartcard +clock. +The value given in the register (5 significant bits) is multiplied by 2 to give the division factor +of the source clock frequency: +00000: Reserved - do not program this value +00001: divides the source clock by 2 +00010: divides the source clock by 4 +00011: divides the source clock by 6 +... + */ +#define USART_GTPR_PSC_SMARTCARD_DIV2 ((uint32_t)(0x1) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV4 ((uint32_t)(0x2) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV6 ((uint32_t)(0x3) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV8 ((uint32_t)(0x4) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV10 ((uint32_t)(0x5) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV12 ((uint32_t)(0x6) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV14 ((uint32_t)(0x7) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV16 ((uint32_t)(0x8) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV18 ((uint32_t)(0x8) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV20 ((uint32_t)(0xa) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV22 ((uint32_t)(0xb) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV24 ((uint32_t)(0xc) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV26 ((uint32_t)(0xd) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV28 ((uint32_t)(0xe) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV30 ((uint32_t)(0xf) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV32 ((uint32_t)(0x10) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV34 ((uint32_t)(0x11) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV36 ((uint32_t)(0x12) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV38 ((uint32_t)(0x13) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV40 ((uint32_t)(0x14) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV42 ((uint32_t)(0x15) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV44 ((uint32_t)(0x16) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV46 ((uint32_t)(0x17) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV48 ((uint32_t)(0x18) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV50 ((uint32_t)(0x19) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV52 ((uint32_t)(0x1a) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV54 ((uint32_t)(0x1b) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV56 ((uint32_t)(0x1c) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV58 ((uint32_t)(0x1d) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV60 ((uint32_t)(0x1e) << USART_GTPR_PSC_Pos) +#define USART_GTPR_PSC_SMARTCARD_DIV62 ((uint32_t)(0x1f) << USART_GTPR_PSC_Pos) + +#define USART_GET_REGISTER(reg)\ +static inline volatile uint32_t* r_CORTEX_M_USART_##reg (uint8_t n){\ + switch(n){\ + case 1:\ + return _r_CORTEX_M_USART_##reg(1);\ + break;\ + case 2:\ + return _r_CORTEX_M_USART_##reg(2);\ + break;\ + case 3:\ + return _r_CORTEX_M_USART_##reg(3);\ + break;\ + case 4:\ + return _r_CORTEX_M_USART_##reg(4);\ + break;\ + case 5:\ + return _r_CORTEX_M_USART_##reg(5);\ + break;\ + case 6:\ + return _r_CORTEX_M_USART_##reg(6);\ + break;\ + default:\ + return NULL;\ + }\ +}\ + +USART_GET_REGISTER(SR) + USART_GET_REGISTER(DR) + USART_GET_REGISTER(BRR) + USART_GET_REGISTER(CR1) + USART_GET_REGISTER(CR2) + USART_GET_REGISTER(CR3) + USART_GET_REGISTER(GTPR) +#endif/*!SOC_USART_REGS_H */ diff --git a/arch/socs/stm32f439/soc-usart.c b/arch/socs/stm32f439/soc-usart.c new file mode 100644 index 0000000..a5e5f8a --- /dev/null +++ b/arch/socs/stm32f439/soc-usart.c @@ -0,0 +1,436 @@ +/* \file soc-usart.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "autoconf.h" +#include "debug.h" +#include "soc-gpio.h" +#include "exported/devices.h" +#include "soc-exti.h" +#include "soc-nvic.h" +#include "soc-rcc.h" +#include "soc-interrupts.h" +#include "soc-usart.h" +#include "soc-usart-regs.h" +#include "gpio.h" + +/**** USART basic Read / Write ****/ +void soc_usart_putc(uint8_t usart, char c) +{ + /* Wait for TX to be ready */ + while (!get_reg(r_CORTEX_M_USART_SR(usart), USART_SR_TXE)) + continue; + *r_CORTEX_M_USART_DR(usart) = c; +} + +/* Instantiate the putc for each USART */ +#define USART_PUTC_CALLBACK(num)\ +void soc_usart##num##_putc(char c)\ +{\ + soc_usart_putc(num, c);\ +}\ + +USART_PUTC_CALLBACK(1) +USART_PUTC_CALLBACK(2) +USART_PUTC_CALLBACK(3) +USART_PUTC_CALLBACK(4) +USART_PUTC_CALLBACK(5) +USART_PUTC_CALLBACK(6) + +void soc_usart_write(uint8_t usart, char *msg, uint32_t len) +{ + while (len--) { + soc_usart_putc(usart, *msg); + msg++; + } +} + +char soc_usart_getc(uint8_t usart) +{ + while (!get_reg(r_CORTEX_M_USART_SR(usart), USART_SR_RXNE)) + continue; + return *r_CORTEX_M_USART_DR(usart); +} + +/* Instantiate the getc for each USART */ +#define USART_GETC_CALLBACK(num)\ +char soc_usart##num##_getc(void)\ +{\ + return soc_usart_getc(num);\ +}\ + +USART_GETC_CALLBACK(1) + USART_GETC_CALLBACK(2) + USART_GETC_CALLBACK(3) + USART_GETC_CALLBACK(4) + USART_GETC_CALLBACK(5) + USART_GETC_CALLBACK(6) + +uint32_t soc_usart_read(uint8_t usart, char *buf, uint32_t len) +{ + uint32_t start_len = len; + while (len--) { + *buf = soc_usart_getc(usart); + if (*buf == '\n') + break; + buf++; + } + return start_len - len; +} + +/**** DMA ****/ +void soc_usart_disable_dma(uint8_t usart) +{ + clear_reg_bits(r_CORTEX_M_USART_CR3(usart), USART_CR3_DMAT_Msk); +} + +void soc_usart_enable_dma(uint8_t usart) +{ + set_reg_bits(r_CORTEX_M_USART_CR3(usart), USART_CR3_DMAT_Msk); +} + +volatile uint32_t *soc_usart_get_data_addr(uint8_t usart) +{ + return r_CORTEX_M_USART_DR(usart); +} + +void soc_usart_set_baudrate(usart_config_t * config) +{ + uint32_t divider = 0; + uint16_t mantissa = 0; + uint8_t fraction = 0; + + /* FIXME we should check CR1 in order to get the OVER8 configuration */ + + /* Compute the divider using the baudrate and the APB bus clock + * (APB1 or APB2) depending on the considered USART */ + divider = soc_usart_get_bus_clock(config) / config->baudrate; + + mantissa = (uint16_t) divider / 16; + fraction = (uint8_t) ((divider - mantissa * 16)); + write_reg_value(r_CORTEX_M_USART_BRR(config->usart), + (((mantissa & 0x0fff) << 4) | (0x0f & fraction))); +} + +/* USART mapping for UART mode (TX, RX), and their configuration */ +#define UART_GPIO_COMMON(po, pi, x) \ + {\ + .kref.port = po,\ + .kref.pin = pi,\ + .mask = GPIO_MASK_SET_MODE | GPIO_MASK_SET_PUPD | GPIO_MASK_SET_SPEED | GPIO_MASK_SET_TYPE | GPIO_MASK_SET_AFR,\ + .mode = GPIO_PIN_ALTERNATE_MODE,\ + .pupd = GPIO_NOPULL,\ + .speed = GPIO_PIN_VERY_HIGH_SPEED,\ + .type = GPIO_PIN_OTYPER_PP,\ + .afr = x,\ + }\ + + +dev_gpio_info_t uart_gpio_config[] = { + /***************************************/ + /* USART1 */ + /* TX is PB6 with alternate function AF7 */ + UART_GPIO_COMMON(GPIO_PB, 6, GPIO_AF_USART1), + /* RX is PB7 with alternate function AF7 */ + UART_GPIO_COMMON(GPIO_PB, 7, GPIO_AF_USART1), + /***************************************/ + /* USART2 */ + /* TX is PA2 with alternate function AF7 */ + UART_GPIO_COMMON(GPIO_PA, 2, GPIO_AF_USART2), + /* RX is PA3 with alternate function AF7 */ + UART_GPIO_COMMON(GPIO_PA, 3, GPIO_AF_USART2), + /***************************************/ + /* USART3 */ + /* TX is PB10 with alternate function AF7 */ + UART_GPIO_COMMON(GPIO_PB, 10, GPIO_AF_USART3), + /* RX is PB11 with alternate function AF7 */ + UART_GPIO_COMMON(GPIO_PB, 11, GPIO_AF_USART3), + /***************************************/ + /* USART4 */ +#ifdef CONFIG_WOOKEY + UART_GPIO_COMMON(GPIO_PA, 0, GPIO_AF_USART4), + UART_GPIO_COMMON(GPIO_PA, 1, GPIO_AF_USART4), +#elif CONFIG_DISCO407 + /* TX is PC10 with alternate function AF8 */ + UART_GPIO_COMMON(GPIO_PC, 10, GPIO_AF_USART4), + /* RX is PC11 with alternate function AF8 */ + UART_GPIO_COMMON(GPIO_PC, 11, GPIO_AF_USART4), +#elif CONFIG_DISCO429 + /* TX is PC10 with alternate function AF8 */ + UART_GPIO_COMMON(GPIO_PC, 10, GPIO_AF_USART4), + /* RX is PC11 with alternate function AF8 */ + UART_GPIO_COMMON(GPIO_PC, 11, GPIO_AF_USART4), +#else +# error "STM32F4xx-based board not supported, check GPIO config" +#endif + /***************************************/ + /* USART5 */ + /* TX is PC12 with alternate function AF8 */ + UART_GPIO_COMMON(GPIO_PC, 12, GPIO_AF_USART5), + /* RX is PD2 with alternate function AF8 */ + UART_GPIO_COMMON(GPIO_PD, 2, GPIO_AF_USART5), + /***************************************/ + /* USART6 */ + /* TX is PC6 with alternate function AF8 */ + UART_GPIO_COMMON(GPIO_PC, 6, GPIO_AF_USART6), + /* RX is PC7 with alternate function AF8 */ + UART_GPIO_COMMON(GPIO_PC, 7, GPIO_AF_USART6), +}; + +/* This is a template configuration for the USART in UART mode */ + +/* FIXME should be rewritten in order to handle all uart configurations + * [RB]: first attempt to implement this ... + */ +static void soc_usart_init_gpio(usart_config_t * config) +{ + dev_gpio_info_t *tx_config; + dev_gpio_info_t *rx_config; + + /* Sanity check */ + if ((config->usart < 1) || (config->usart > 6)) { + panic("Wrong usart %d. You should use USART1 to USART6", config->usart); + } + + switch (config->mode) { + case UART: + tx_config = &uart_gpio_config[2 * (config->usart - 1)]; + rx_config = &uart_gpio_config[(2 * (config->usart - 1)) + 1]; + + if (tx_config->kref.port == 0 && rx_config->kref.port == 0) { + panic + ("UART usart %d does not seem to support UART or to be rooted on the board!", + config->usart); + } + + soc_gpio_configure + (tx_config->kref.port, + tx_config->kref.pin, + tx_config->mode, + tx_config->type, + tx_config->speed, + tx_config->pupd, + tx_config->afr); + + soc_gpio_configure + (rx_config->kref.port, + rx_config->kref.pin, + rx_config->mode, + rx_config->type, + rx_config->speed, + rx_config->pupd, + rx_config->afr); + + /* Configure the */ + break; + default: + panic("Wrong usart mode %d.", config->mode); + } +} + +static void soc_usart_clock_init(usart_config_t * config) +{ + switch (config->usart) { + case 1: + set_reg_bits(r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_USART1EN); + break; + case 2: + set_reg_bits(r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_USART2EN); + break; + case 3: + set_reg_bits(r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_USART3EN); + break; + case 4: + set_reg_bits(r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_UART4EN); + break; + case 5: + set_reg_bits(r_CORTEX_M_RCC_APB1ENR, RCC_APB1ENR_UART5EN); + break; + case 6: + set_reg_bits(r_CORTEX_M_RCC_APB2ENR, RCC_APB2ENR_USART6EN); + break; + default: + panic("Wrong usart %d. You should use USART1 to USART6", config->usart); + } + + return; +} + +/**** IRQ Handlers ****/ + +#define USART_IRQHANDLER(num, type) \ +/* Global variable holding the callback to USART num */\ +cb_usart_data_received_t cb_usart##num##_data_received = NULL;\ +/* Register the IRQ */\ +void U##type##ART##num##_IRQ_Handler(stack_frame_t *sf __attribute__((unused)))\ +{\ + if(cb_usart##num##_data_received != NULL){\ + cb_usart##num##_data_received();\ + }\ +} + +/* Instantiate the IRQs for the 6 USARTs + * The weird second macro argument handles the fact that USART 4 and 5 are in + * UARTs. + */ +USART_IRQHANDLER(1, S) + USART_IRQHANDLER(2, S) + USART_IRQHANDLER(3, S) + USART_IRQHANDLER(4,) + USART_IRQHANDLER(5,) + USART_IRQHANDLER(6, S) + +/* Configure the handlers */ +#define USART_CONFIG_CALLBACKS(num, type) \ + case num:\ + if (config->callback_data_received != NULL){\ + NVIC_EnableIRQ(U##type##ART##num##_IRQ - 0x10);\ + /* Enable dedicated IRQ and register the callback */\ + cb_usart##num##_data_received = config->callback_data_received;\ + }\ + if(config->callback_usart_getc_ptr != NULL){\ + *(config->callback_usart_getc_ptr) = soc_usart##num##_getc;\ + }\ + if(config->callback_usart_putc_ptr != NULL){\ + *(config->callback_usart_putc_ptr) = soc_usart##num##_putc;\ + }\ + break;\ + +static void soc_usart_callbacks_init(usart_config_t * config) +{ + if (config->callback_data_received) { + /* A reception callback has been provided: enable interrupts + * for RX using the control register + */ + set_reg_bits(r_CORTEX_M_USART_CR1(config->usart), USART_CR1_RXNEIE_Msk); + } + switch (config->usart) { + USART_CONFIG_CALLBACKS(1, S) + USART_CONFIG_CALLBACKS(2, S) + USART_CONFIG_CALLBACKS(3, S) + USART_CONFIG_CALLBACKS(4,) + USART_CONFIG_CALLBACKS(5,) + USART_CONFIG_CALLBACKS(6, S) + default: + panic("Wrong usart %d. You should use USART1 to USART6", config->usart); + } + + return; +} + +/**** usart_init ****/ +void soc_usart_init(usart_config_t * config) +{ + + soc_usart_clock_init(config); + soc_usart_init_gpio(config); + soc_usart_set_baudrate(config); + + /* registering the handler */ + /* + switch (config->usart) { + case 0: + case 1: + irq_handler_set(USART1_IRQ, USART1_IRQ_Handler, 0, ID_DEV_UNUSED); + break; + case 2: + irq_handler_set(USART2_IRQ, USART2_IRQ_Handler, 0, ID_DEV_UNUSED); + break; + case 3: + irq_handler_set(USART3_IRQ, USART3_IRQ_Handler, 0, ID_DEV_UNUSED); + break; + case 4: + irq_handler_set(UART4_IRQ, UART4_IRQ_Handler, 0, ID_DEV_UNUSED); + break; + case 5: + irq_handler_set(UART5_IRQ, UART5_IRQ_Handler, 0, ID_DEV_UNUSED); + break; + case 6: + irq_handler_set(USART6_IRQ, USART6_IRQ_Handler, 0, ID_DEV_UNUSED); + break; + default: + irq_handler_set(USART1_IRQ, USART1_IRQ_Handler, 0, ID_DEV_UNUSED); + } + */ + + /* Control register 1 */ + set_reg(r_CORTEX_M_USART_CR1(config->usart), config->parity, + USART_CONFIG_PARITY); + set_reg(r_CORTEX_M_USART_CR1(config->usart), config->options_cr1, + USART_CONFIG_OPTIONS_CR1); + + /* Control register 2 */ + set_reg(r_CORTEX_M_USART_CR2(config->usart), config->stop_bits, + USART_CONFIG_STOP_BITS); + set_reg(r_CORTEX_M_USART_CR1(config->usart), config->options_cr2, + USART_CONFIG_OPTIONS_CR2); + + /* USART 4 and 5 have some configuration limitations: check them before continuing */ + if ((config->hw_flow_control & (USART_CR3_CTSIE_Msk | USART_CR3_CTSE_Msk | + USART_CR3_RTSE_Msk | USART_CR3_SCEN_Msk | + USART_CR3_NACK_Msk)) + && ((config->usart == 4) || (config->usart == 5))) { + panic + ("Usart%d config error: asking for a flag in CR3 unavailable for USART4 and USART5", + config->usart); + } + if ((config->hw_flow_control & (USART_CR3_DMAT_Msk | USART_CR3_DMAR_Msk)) + && (config->usart == 5)) { + panic + ("Usart%d config error: asking for a flag in CR3 unavailable for USART5", + config->usart); + } + if ((config->guard_time_prescaler) + && ((config->usart == 4) || (config->usart == 5))) { + panic + ("Usart%d config error: asking for guard time/prescaler in GTPR unavailable for USART4 and USART5", + config->usart); + } + /* Control register 3 */ + set_reg(r_CORTEX_M_USART_CR3(config->usart), config->hw_flow_control, + USART_CONFIG_HW_FLW_CTRL); + + /* Initialize callbacks */ + soc_usart_callbacks_init(config); + + return; +} + +/* Get the current clock value of the USART bus */ +uint32_t soc_usart_get_bus_clock(usart_config_t * config) +{ + switch (config->usart) { + case 1: + case 6: + return PROD_CLOCK_APB2; + break; + case 2: + case 3: + case 4: + case 5: + return PROD_CLOCK_APB1; + break; + default: + panic("Wrong usart %d. You should use USART1 to USART6", config->usart); + } + + return 0; +} diff --git a/arch/socs/stm32f439/soc-usart.h b/arch/socs/stm32f439/soc-usart.h new file mode 100644 index 0000000..f5fac1d --- /dev/null +++ b/arch/socs/stm32f439/soc-usart.h @@ -0,0 +1,240 @@ +/* \file soc-usart.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SOC_USART_H +#define SOC_USART_H + +#include "types.h" +#include "regutils.h" +#include "soc-interrupts.h" +#include "soc-usart-regs.h" +#include "exported/gpio.h" + +// TODO: differenciate tx_port and rx_port that may differs +static const struct { + char * name; + uint8_t port; /* GPIO_PA, GPIO_PB, ... */ + uint8_t tx_pin; + uint8_t rx_pin; + uint8_t sc_port; + uint8_t sc_tx_pin; + uint8_t sc_ck_pin; + uint8_t irq; + uint8_t af; +} soc_usarts[] = { + { "", 0, 0, 0, 0, 0, 0, 53, 0x7 }, + { "usart1", GPIO_PB, 6, 7, GPIO_PA, 9, 8, 53, 0x7 }, + { "usart2", GPIO_PA, 2, 3, GPIO_PA, 2, 4, 54, 0x7 }, + { "usart3", GPIO_PB, 10, 11, GPIO_PB, 10, 12, 55, 0x7 }, + { "uart4", GPIO_PA, 0, 1, 0, 0, 0, 68, 0x8 }, + { "uart5", GPIO_PC, 12, 2, 0, 0, 0, 69, 0x8 }, + { "usart6", GPIO_PC, 6, 7, GPIO_PC, 6, 8, 89, 0x8 } +}; + + +typedef void (*cb_usart_data_received_t) (void); +typedef char (*cb_usart_getc_t) (void); +typedef void (*cb_usart_putc_t) (char); + +/* Defines the USART mode that we consider + * [RB] TODO: to be completed with other USART modes if/when needed! (IrDA, LIN, ...) + * For now, only the classical UART console mode and the SMARTCARD modes are + * implemented. + */ +typedef enum { UART, SMARTCARD, CUSTOM } usart_mode; + +/* [RB] TODO: add some magic initialization values and assert to avoid manipulation + * of uninitialized structures! + */ +typedef struct __packed { + + uint8_t usart; + usart_mode mode; + uint32_t baudrate; /* USART_BRR:DIV_Mantissa[11:0]: and DIV_Fraction[3:0]: */ + uint32_t word_length; /* USART_CR1:Bit 12 M: Word length */ + uint32_t parity; /* USART_CR1:Bit 9 PS: Parity selection and Bit 10 PCE: Parity control enable */ + uint32_t stop_bits; /* USART_CR2:Bits 13:12 STOP: STOP bits, */ + uint32_t hw_flow_control; /* USART_CR3: + Bit 11 ONEBIT: One sample bit method enable + Bit 10 CTSIE: CTS interrupt enable + Bit 9 CTSE: CTS enable + Bit 8 RTSE: RTS enable + Bit 7 DMAT: DMA enable transmitter + Bit 6 DMAR: DMA enable receiver + Bit 5 SCEN: Smartcard mode enable + Bit 4 NACK: Smartcard NACK enable + Bit 3 HDSEL: Half-duplex selection + Bit 2 IRLP: IrDA low-power + Bit 1 IREN: IrDA mode enable + Bit 0 EIE: Error interrupt enable */ + /* Additional options in CR1 */ + uint32_t options_cr1; /* USART_CR1: + Bit 15 OVER8: + Bit 13 UE: USART enable + Bit 11 WAKE: Wakeup method + Bit 8 PEIE: PE interrupt enable + Bit 7 TXEIE: TXE interrupt enable + Bit 6 TCIE: Transmission complete interrupt enable + Bit 5 RXNEIE: RXNE interrupt enable + Bit 4 IDLEIE: IDLE interrupt enable + Bit 3 TE: Transmitter enable + Bit 2 RE: Receiver enable + Bit 1 RWU: Receiver wakeup + Bit 0 SBK: Send break */ + /* Additional options in CR2 */ + uint32_t options_cr2; /* USART_CR2: + Bit 14 LINEN: LIN mode enable + Bit 11 CLKEN: Clock enable + Bit 10 CPOL: Clock polarity + Bit 9 CPHA: Clock phase + Bit 8 LBCL: Last bit clock pulse + Bit 6 LBDIE: LIN break detection interrupt enable + Bit 5 LBDL: lin break detection length */ + uint32_t guard_time_prescaler; /* USART_GTPR: (used for Smartcard and IrDA modes + * Bits 15:8 GT[7:0]: Guard time value + * Bits 7:0 PSC[7:0]: Prescaler value */ + cb_usart_data_received_t callback_data_received; + cb_usart_getc_t *callback_usart_getc_ptr; + cb_usart_putc_t *callback_usart_putc_ptr; +} usart_config_t; + +#define USART_CONFIG_WORD_LENGTH_BITS_Msk (define USART_CR1_M_Msk) +#define USART_CONFIG_WORD_LENGTH_BITS_Pos 0 + +#define USART_CONFIG_PARITY_Msk (USART_CR1_PS_Msk | USART_CR1_PCE_Msk) +#define USART_CONFIG_PARITY_Pos 0 + +#define USART_CONFIG_STOP_BITS_Msk (USART_CR2_STOP_Msk) +#define USART_CONFIG_STOP_BITS_Pos 0 + +#define USART_CONFIG_OPTIONS_CR1_Msk (USART_CR1_OVER8_Msk \ + | USART_CR1_UE_Msk \ + | USART_CR1_WAKE_Msk \ + | USART_CR1_PEIE_Msk \ + | USART_CR1_TXEIE_Msk \ + | USART_CR1_TCIE_Msk \ + | USART_CR1_RXNEIE_Msk \ + | USART_CR1_IDLEIE_Msk \ + | USART_CR1_TE_Msk \ + | USART_CR1_RE_Msk \ + | USART_CR1_RWU_Msk \ + | USART_CR1_SBK_Msk ) +#define USART_CONFIG_OPTIONS_CR1_Pos 0 + +#define USART_CONFIG_OPTIONS_CR2_Msk ( USART_CR2_LINEN_Msk \ + | USART_CR2_CLKEN_Msk \ + | USART_CR2_CPOL_Msk \ + | USART_CR2_CPHA_Msk \ + | USART_CR2_LBCL_Msk \ + | USART_CR2_LBDIE_Msk \ + | USART_CR2_LBDL_Msk ) +#define USART_CONFIG_OPTIONS_CR2_Pos 0 + +#define USART_CONFIG_HW_FLW_CTRL_Msk (USART_CR3_ONEBIT_Msk \ + | USART_CR3_CTSIE_Msk \ + | USART_CR3_CTSE_Msk \ + | USART_CR3_RTSE_Msk \ + | USART_CR3_DMAT_Msk \ + | USART_CR3_DMAR_Msk \ + | USART_CR3_SCEN_Msk \ + | USART_CR3_NACK_Msk \ + | USART_CR3_HDSEL_Msk \ + | USART_CR3_IRLP_Msk \ + | USART_CR3_IREN_Msk \ + | USART_CR3_EIE_Msk ) +#define USART_CONFIG_HW_FLW_CTRL_Pos 0 + +#define USART_CONFIG_GUARD_TIME_PRESCALER_Msk (USART_GTPR_GT_Msk | USART_GTPR_PSC_Msk) +#define USART_CONFIG_GUARD_TIME_PRESCALER_Pos 0 + +/** + * usart_init - Initialize the USART + * @n: USART to use (1 or 4). + * @callback_data_received: function called when data is received on the RX + * pin. If this argument is NULL, USART IRQs are disabled. + * + * This function initialize USART1 (n = 1) or UART4 (n = 4) as 8N1 at a + * baudrate of 115200 + */ +void soc_usart_init(usart_config_t * config); + +/** + * usart_putc - Send a character + * @c: Character to send. + */ +void soc_usart_putc(uint8_t usart, char c); + +/** + * usart_write - Send a string + * @msg: string of size @len to send. + * @len: size of @msg. + */ +void soc_usart_write(uint8_t usart, char *msg, uint32_t len); + +/** + * usart_getc - Read a character + * Return: The character read. + */ +char soc_usart_getc(uint8_t usart); + +/** + * usart_read - Read a string + * @buf: Address of the buffer in which the read characters will be written. + * The size of the buffer must be at least @len. + * @len: Number of characters to read. + */ +uint32_t soc_usart_read(uint8_t usart, char *buf, uint32_t len); + +/** + * usart_disable_dma - Enable the DMA for USART + * + * Disable for transmit only. + * See also usart_enable_dma. + */ +void soc_usart1_disable_dma(uint8_t usart); + +/** + * usart_enable_dma - Enable the DMA for USART + * + * Enable for transmit only. + * See also usart_disable_dma. + */ +void soc_usart_enable_dma(uint8_t usart); + +/** + * usart_get_data_addr - Getter for the USART's data register address + * Return: The address of the USART's data register where the data should be + * written. + */ +volatile uint32_t *soc_usart_get_data_addr(uint8_t usart); + +/* Get the clock frequency value of the APB bus driving the USART */ +uint32_t soc_usart_get_bus_clock(usart_config_t * config); + +void USART1_IRQ_Handler(stack_frame_t *sf); +void USART2_IRQ_Handler(stack_frame_t *sf); +void USART3_IRQ_Handler(stack_frame_t *sf); +void UART4_IRQ_Handler(stack_frame_t *sf); +void UART5_IRQ_Handler(stack_frame_t *sf); +void USART6_IRQ_Handler(stack_frame_t *sf); + +#endif/*!SOC_USART_H */ diff --git a/arch/socs/stm32f439/startup_stm32f439.s b/arch/socs/stm32f439/startup_stm32f439.s new file mode 100644 index 0000000..bb42645 --- /dev/null +++ b/arch/socs/stm32f439/startup_stm32f439.s @@ -0,0 +1,321 @@ +/** + ****************************************************************************** + * @file startup_stm32f4xx.s + * @author MCD Application Team + * @version V1.0.0 + * @date 30-September-2011 + * @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Configure the clock system and the external SRAM mounted on + * STM324xG-EVAL board to be used as data memory (optional, + * to be enabled by user) + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +.syntax unified +.cpu cortex-m4 +.fpu softvfp +.thumb + +.global g_pfnVectors +.global g_BaseAddress +.global g_StackAddress + +.extern Default_SubHandler + +/* start address for the initialization values of the .data section. defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +.word _sigot +.word _sgot +.word _egot + + +/* +.word _svtors +.word _evtors +*/ +/* + * @brief Globals variables + * @param None + * @retval None + * + */ + +.section .data +g_BaseAddress: + .word 0 +g_StackAddress: + .word 0 + +/* + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval None + */ + +.section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + bl _start /* Entry point address */ +_start: + movs r5, lr + sub r5, #5 /* In thumb mode LR is pointing to PC + 4 bytes + 1 because in thumb mode LR must be odd aligned*/ + sub r2, r5, #0x188 /* Compute vector table address FIXME: We should use dynimic value for VTORS_SIZE */ + ldr r2, [r2] + msr msp, r2 /* Reset stack address to default 0x20002000 */ + + movs r1, #0 + b LoopCopyDataInit +CopyDataInit: /* Copy the data segment initializers from flash to SRAM */ + ldr r3, =_sidata /* start address for the initialization values of the .data section. */ + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 +LoopCopyDataInit: + ldr r0, =_sdata /* start address for the .data section */ + ldr r3, =_edata /* end address for the .data section */ + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + + + ldr r2, =_sbss /* start address for the .bss section */ + b LoopFillZerobss +FillZerobss: /* Zero fill the bss segment. */ + movs r3, #0 + str r3, [r2], #4 +LoopFillZerobss: + ldr r3, = _ebss /* end address for the .bss section */ + cmp r2, r3 + bcc FillZerobss + movs r0, #1 + ldr r1, = g_BaseAddress + str r5, [r1] + dmb + bl main + bx lr + +.size Reset_Handler, .-Reset_Handler + +.section .text.Default_Handler + .weak Default_Handler + .type Default_Handler, %function +Default_Handler: + cpsid i + + /* + * The NVIC has already saved R0-R3, R12, LR, PC and xPSR registers on the + * stack. We save the remaining registers (R4-R11) and LR (with the new + * value) on that previously used stack. + */ + + /* 1) Which stack was previously used ? */ + + tst lr, #4 /* bit 2: (0) MSP (1) PSP stack */ + ite eq /* if equal 0 */ + mrseq r0, msp /* r0 <- MSP */ + mrsne r0, psp /* r0 <- PSP (process stack) */ + + /* + * 2) Save registers on the previously used stack. + * R0 points to the saved registers: + * LR, R4-R11, R0-R3, R12, previous LR, PC, xPSR + */ + + stmfd r0!, {r4-r11, lr} + + /* 3) Adjusting the previously used stack pointer (might be PSP or MSP) */ + + tst lr, #4 /* bit 2: (0) MSP (1) PSP stack */ + ite eq /* if equal 0 */ + msreq msp, r0 /* MSP <- r0 */ + msrne psp, r0 /* PSP <- r0 */ + + /* + * R0 is passed as a parameter. It still points to the saved registers. + * In case of task switching, R0 returned by `Default_SubHandler' might be + * different. + */ + + bl Default_SubHandler + + /* Registers LR, R4-R11 are restored */ + ldmfd r0!, {r4-r11, lr} + + /* Adjusting PSP/MSP so that the NVIC can restore the remaining registers */ + + tst lr, #4 /* bit 2: (0) MSP (1) PSP stack */ + bne psp_use /* if not equal 0 */ + +msp_use: + msr msp, r0 /* MSP <- r0 */ + cpsie i + bx lr + +psp_use: + msr psp, r0 /* PSP <- r0 */ + cmp r1, #1 + bne kern_mode + +user_mode: + mov r0, #3 + msr control, r0 + isb + cpsie i + bx lr + +kern_mode: + mov r0, #2 + msr control, r0 + isb + cpsie i + bx lr +.size Default_Handler, .-Default_Handler + +/****************************************************************************** + * + * The minimal vector table for a Cortex M4. Note that the proper constructs + * must be placed on this to ensure that it ends up at physical address + * 0x0000.0000. + * + ******************************************************************************/ +.section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word Default_Handler + .word Default_Handler + .word Default_Handler + .word Default_Handler + .word Default_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word Default_Handler + .word Default_Handler + .word 0 + .word Default_Handler + .word Default_Handler + + /* + * External Interrupts + */ + .word Default_Handler /* Window WatchDog */ + .word Default_Handler /* PVD through EXTI Line detection */ + .word Default_Handler /* Tamper and TimeStamps through the EXTI line */ + .word Default_Handler /* RTC Wakeup through the EXTI line */ + .word Default_Handler /* FLASH */ + .word Default_Handler /* RCC */ + .word Default_Handler /* EXTI Line0 */ + .word Default_Handler /* EXTI Line1 */ + .word Default_Handler /* EXTI Line2 */ + .word Default_Handler /* EXTI Line3 */ + .word Default_Handler /* EXTI Line4 */ + .word Default_Handler /* DMA1 Stream 0 */ + .word Default_Handler /* DMA1 Stream 1 */ + .word Default_Handler /* DMA1 Stream 2 */ + .word Default_Handler /* DMA1 Stream 3 */ + .word Default_Handler /* DMA1 Stream 4 */ + .word Default_Handler /* DMA1 Stream 5 */ + .word Default_Handler /* DMA1 Stream 6 */ + .word Default_Handler /* ADC1, ADC2 and ADC3s */ + .word Default_Handler /* CAN1 TX */ + .word Default_Handler /* CAN1 RX0 */ + .word Default_Handler /* CAN1 RX1 */ + .word Default_Handler /* CAN1 SCE */ + .word Default_Handler /* External Line[9:5]s */ + .word Default_Handler /* TIM1 Break and TIM9 */ + .word Default_Handler /* TIM1 Update and TIM10 */ + .word Default_Handler /* TIM1 Trigger and Commutation and TIM11 */ + .word Default_Handler /* TIM1 Capture Compare */ + .word Default_Handler /* TIM2 */ + .word Default_Handler /* TIM3 */ + .word Default_Handler /* TIM4 */ + .word Default_Handler /* I2C1 Event */ + .word Default_Handler /* I2C1 Error */ + .word Default_Handler /* I2C2 Event */ + .word Default_Handler /* I2C2 Error */ + .word Default_Handler /* SPI1 */ + .word Default_Handler /* SPI2 */ + .word Default_Handler /* USART1 */ + .word Default_Handler /* USART2 */ + .word Default_Handler /* USART3 */ + .word Default_Handler /* External Line[15:10]s */ + .word Default_Handler /* RTC Alarm (A and B) through EXTI Line */ + .word Default_Handler /* USB OTG FS Wakeup through EXTI line */ + .word Default_Handler /* TIM8 Break and TIM12 */ + .word Default_Handler /* TIM8 Update and TIM13 */ + .word Default_Handler /* TIM8 Trigger and Commutation and TIM14 */ + .word Default_Handler /* TIM8 Capture Compare */ + .word Default_Handler /* DMA1 Stream7 */ + .word Default_Handler /* FSMC */ + .word Default_Handler /* SDIO */ + .word Default_Handler /* TIM5 */ + .word Default_Handler /* SPI3 */ + .word Default_Handler /* UART4 */ + .word Default_Handler /* UART5 */ + .word Default_Handler /* TIM6 and DAC1&2 underrun errors */ + .word Default_Handler /* TIM7 */ + .word Default_Handler /* DMA2 Stream 0 */ + .word Default_Handler /* DMA2 Stream 1 */ + .word Default_Handler /* DMA2 Stream 2 */ + .word Default_Handler /* DMA2 Stream 3 */ + .word Default_Handler /* DMA2 Stream 4 */ + .word Default_Handler /* Ethernet */ + .word Default_Handler /* Ethernet Wakeup through EXTI line */ + .word Default_Handler /* CAN2 TX */ + .word Default_Handler /* CAN2 RX0 */ + .word Default_Handler /* CAN2 RX1 */ + .word Default_Handler /* CAN2 SCE */ + .word Default_Handler /* USB OTG FS */ + .word Default_Handler /* DMA2 Stream 5 */ + .word Default_Handler /* DMA2 Stream 6 */ + .word Default_Handler /* DMA2 Stream 7 */ + .word Default_Handler /* USART6 */ + .word Default_Handler /* I2C3 event */ + .word Default_Handler /* I2C3 error */ + .word Default_Handler /* USB OTG HS End Point 1 Out */ + .word Default_Handler /* USB OTG HS End Point 1 In */ + .word Default_Handler /* USB OTG HS Wakeup through EXTI */ + .word Default_Handler /* USB OTG HS */ + .word Default_Handler /* DCMI */ + .word Default_Handler /* CRYP crypto */ + .word Default_Handler /* Hash and Rng */ + .word Default_Handler /* FPU */ + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/arch/stack_check.c b/arch/stack_check.c new file mode 100644 index 0000000..adddf5e --- /dev/null +++ b/arch/stack_check.c @@ -0,0 +1,54 @@ +/* \file stack_check.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "debug.h" +#include "get_random.h" + +/* Global variable holding the stack canary value */ +volatile uint32_t __stack_chk_guard = 0; + +/* Initialize the stack guard with a random value + * Note: of course, this function must NOT be enforced + * with stack protection! Hence the specific optimization attribute. + */ +__attribute__((optimize("-fno-stack-protector","-O0"))) void init_stack_chk_guard(void){ + uint32_t random; + if(get_random((unsigned char*)&random, sizeof(uint32_t))){ + panic("Failed to initialize the check guard ..."); + } + + /* This operation must not be optimized, hence the -O0 in the optimization + * flag! + */ + __stack_chk_guard = random; + + LOG("The new stack canary is %x\n", __stack_chk_guard); + + return; +} + +void __stack_chk_fail(void){ + /* We have failed to check our stack canary */ + panic("Failed to check the stack guard ..."); + + return; +} diff --git a/arch/stack_check.h b/arch/stack_check.h new file mode 100644 index 0000000..905cecc --- /dev/null +++ b/arch/stack_check.h @@ -0,0 +1,28 @@ +/* \file stack_check.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef __STACK_CHECK_H__ +#define __STACK_CHECK_H__ + +void init_stack_chk_guard(void); + +#endif /* __STACK_CHECK_H__ */ diff --git a/arch/usb_device.h b/arch/usb_device.h new file mode 100644 index 0000000..8c41ccf --- /dev/null +++ b/arch/usb_device.h @@ -0,0 +1,46 @@ +/* \file usb_device.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** @file usb_device.h + * \brief Contains usb descriptors + */ +#ifndef _USB_DEVICE_H +#define _USB_DEVICE_H + +#include "autoconf.h" + +/* Strings */ +#define MAX_DESC_STRING_SIZE 32 +#define LANGUAGE_ENGLISH 0x0409 + +#define STRING_MANUFACTURER CONFIG_USB_DEV_MANUFACTURER +#define STRING_MANUFACTURER_INDEX 1 +#define STRING_PRODUCT CONFIG_USB_DEV_PRODNAME +#define STRING_PRODUCT_INDEX 2 +#define STRING_SERIAL "123456789012345678901234" +#define STRING_SERIAL_INDEX 3 + +#define ID_VENDOR CONFIG_USB_DEV_VENDORID +#define ID_PRODUCT CONFIG_USB_DEV_PRODUCTID + +#endif diff --git a/devices-shared.h b/devices-shared.h new file mode 100644 index 0000000..c8da2c8 --- /dev/null +++ b/devices-shared.h @@ -0,0 +1,48 @@ +/* \file devices-shared.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef DEVICES_SHARED_H_ +#define DEVICES_SHARED_H_ + +typedef enum { + ID_DEV_UNUSED, + ID_DEV1, + ID_DEV2, + ID_DEV3, + ID_DEV4, + ID_DEV5, + ID_DEV6, + ID_DEV7, + ID_DEV8, + ID_DEV9, + ID_DEV10, + ID_DEV11, + ID_DEV12, + ID_DEV13, + ID_DEV14, + ID_DEV15, + ID_DEV16, + ID_DEV_MAX +} e_device_id; + +#endif /*!DEVICES_SHARED_H_ */ diff --git a/devices.c b/devices.c new file mode 100644 index 0000000..3b9e709 --- /dev/null +++ b/devices.c @@ -0,0 +1,556 @@ +/* devices.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "autoconf.h" +#include "perm.h" +#include "devices.h" +#include "soc-interrupts.h" +#include "soc-gpio.h" +#include "soc-devmap.h" +#include "soc-nvic.h" +#include "debug.h" +#include "kernel.h" +#include "gpio.h" +#include "syscalls.h" +#include "exti.h" +#include "libc.h" +#include "sanitize.h" +#include "mpu.h" + +/* +** This table hosts all registered devices for all user tasks. +** It contains data sent by user via sys_init(INIT_REGISTERDEV). +** The infos hosted in this opaque are checked by dev_check_content(). If the +** k_device_t struct is set as DEV_REGISTERED, the user content is considered +** validated. +** It is *not* possible to un-register a device. +*/ +static k_device_t device_tab[ID_DEV_MAX]; + + +/************************************************************************ + * Device package getters and setters + ***********************************************************************/ + +retval_t dev_set_device_map (bool state, e_device_id dev_id) +{ + e_task_id tskid = dev_get_task_from_id(dev_id); + task_t *tsk = NULL; + + tsk = task_get_task(tskid); + if (state == true && tsk->num_devs_mmapped == MPU_MAX_EMPTY_REGIONS) { + return FAILURE; + } + device_tab[dev_id].is_mapped = state; + if (state == true) { + tsk->num_devs_mmapped++; + } else { + tsk->num_devs_mmapped--; + } + return SUCCESS; +} + +e_task_id dev_get_task_from_id (e_device_id dev_id) +{ + return device_tab[dev_id].task_id; +} + + +inline device_t* dev_get_device_from_id (e_device_id dev_id) +{ + return &device_tab[dev_id].udev; +} + +inline uint16_t dev_get_device_size (e_device_id dev_id) +{ + return device_tab[dev_id].udev.size; +} + +inline physaddr_t dev_get_device_addr (e_device_id dev_id) +{ + return device_tab[dev_id].udev.address; +} + +bool dev_is_mapped(e_device_id dev_id) +{ + return device_tab[dev_id].is_mapped; +} + +inline bool dev_is_mapped_voluntary (e_device_id dev_id) +{ + return device_tab[dev_id].udev.map_mode; +} + +inline bool dev_is_device_region_ro (e_device_id dev_id) +{ + return device_tab[dev_id].devinfo->ro; +} + +inline uint8_t dev_get_device_region_mask (e_device_id dev_id) +{ + return device_tab[dev_id].devinfo->mask; +} + + +/** + * \brief return the irq info structure from an IRQ and associated task + * + * \param[in] task the task to which the device belongs + * \param[in] irq the irq number + * + * \return the corresponding irq info structure, or 0 if not found. + */ +dev_irq_info_t *dev_get_irqinfo_from_irq(uint8_t irq) +{ + e_device_id dev_id = get_device_from_interrupt(irq); + + for (int j = 0; j < device_tab[dev_id].udev.irq_num; ++j) { + if (device_tab[dev_id].udev.irqs[j].irq == irq) { + return &device_tab[dev_id].udev.irqs[j]; + } + } + + /* No irq has been matched */ + return NULL; +} + +/* + * \brief return GPIO info from gpio kref identifier + */ +dev_gpio_info_t *dev_get_gpio_from_gpio_kref(gpioref_t kref) +{ + /* + * We loop on all devices to find the given GPIO kref + * FIXME: need for some optimizations to avoid "brute force" + * searching + */ + for (uint8_t i = ID_DEV1; i < ID_DEV_MAX; ++i) { + /* No more devices, just leave loop */ + if (device_tab[i].status == DEV_STATE_NONE) { + break; + } + device_t *udev = (device_t*)&device_tab[i]; + /* We loop on all gpios to find the given GPIO kref */ + for (uint8_t gpio = 0; gpio < udev->gpio_num; ++gpio) { + if (udev->gpios[gpio].kref.val == kref.val) { + return &udev->gpios[gpio]; + } + } + } + return 0; +} + + + +/************************************************************************ + * Device registration functions + * These functions are called when a device is registered, at initialization + * time + ***********************************************************************/ + +/*! + * \brief Register all the task's device ISR in the IRQ manager + * + * ISR will be executed in thread mode, in the task global context, but + * with a dedicated stack and local autonomous context for save/restore, + * to support preemption by IRQ. + */ +uint8_t dev_register_handlers(e_device_id dev_id, e_task_id task_id) +{ + if (device_tab[dev_id].status == DEV_STATE_REGISTERED) { + KERNLOG(DBG_ERR, "dev_register_handlers(): status already set as DEV_STATE_REGISTERED\n"); + return 1; + } + + for (int i = 0; i < device_tab[dev_id].udev.irq_num; ++i) { + + /* Checking if there is not already a user IRQ handler */ + if (is_interrupt_already_used(device_tab[dev_id].udev.irqs[i].irq)) { + KERNLOG(DBG_ERR, + "registering irq handler 0x%x for irq %d fails. This irq is already set\n", + device_tab[dev_id].udev.irqs[i].handler, + device_tab[dev_id].udev.irqs[i].irq); + return 1; + } else { + set_interrupt_handler(device_tab[dev_id].udev.irqs[i].irq, + device_tab[dev_id].udev.irqs[i].handler, task_id, dev_id); + } + } + + return 0; +} + +/* + * This function simply register the GPIO and return a reference handle. + */ +uint8_t dev_register_gpios(e_device_id dev_id, e_task_id task_id) +{ + uint8_t ret; + + if (device_tab[dev_id].status == DEV_STATE_REGISTERED) { + KERNLOG(DBG_ERR, "dev_register_gpios(): status already set as DEV_STATE_REGISTERED\n"); + return 1; + } + + for (int i = 0; i < device_tab[dev_id].udev.gpio_num; ++i) { + /* Then we register the GPIO itself */ + ret = gpio_register_gpio + (task_id, dev_id, &device_tab[dev_id].udev.gpios[i]); + if (ret) { + KERNLOG(DBG_ERR, "device GPIO registering failed!\n"); + return ret; + } + + /* To finish we register possible associated EXTI line */ + ret = exti_register_exti(&device_tab[dev_id].udev.gpios[i]); + if (ret) { + KERNLOG(DBG_ERR, "device GPIO-EXTI registering failed!\n"); + return ret; + } + + KERNLOG(DBG_INFO, + "registered GPIO port %x, pin %x for device %s\n", + device_tab[dev_id].udev.gpios[i].kref.port, + device_tab[dev_id].udev.gpios[i].kref.pin, + device_tab[dev_id].udev.name); + } + + return 0; +} + +/* + * Registering a new device. + * NOTE: If the task configures only some GPIOs without any "real" device + * behind 'devinfo' field will be set as NULL. + */ +uint8_t dev_register_device(e_device_id dev_id, device_t *udev) +{ + struct device_soc_infos *devinfo = NULL; + + if (udev->size != 0) { + devinfo = soc_devmap_find_device(udev->address, udev->size); + if (devinfo == NULL) { + KERNLOG(DBG_WARN, "can't find device %s (addr: %x, size: %x)\n", + udev->name, udev->address, udev->size); + return 1; + } + + memcpy(&device_tab[dev_id].udev, udev, sizeof(device_t)); + device_tab[dev_id].devinfo = devinfo; + device_tab[dev_id].is_mapped = false; + } + + device_tab[dev_id].status = DEV_STATE_REGISTERED; + + KERNLOG(DBG_INFO, "registered device %s (%x)\n", udev->name, udev->address); + return 0; +} + + +/************************************************************************ + * Device Enabling functions + * These functions are called when the sys_init(INIT_DONE) function is + * called by the userspace. + ***********************************************************************/ + + +/* +** This function should be called by syscall sys_init(INIT_LOCK). +** This behavior: +** 1) forces user tasks to use this syscall, locking any future sys_init usage +** 2) enable all devices of the task at one single moment, at the end of init +*/ +uint8_t dev_enable_device(e_device_id dev_id) +{ + if (device_tab[dev_id].status != DEV_STATE_REGISTERED) { + KERNLOG(DBG_ERR, "dev_enable_device(): device status is not DEV_REGISTERED\n"); + return 1; + } + + /* Enable GPIOs if needed */ + dev_enable_gpio(dev_id); + + /* Enable associated IRQs */ + for (uint8_t i = 0; i < MIN(device_tab[dev_id].udev.irq_num, MAX_IRQS); ++i) + { + NVIC_EnableIRQ((uint32_t) device_tab[dev_id].udev.irqs[i].irq - 0x10); + KERNLOG(DBG_INFO, "Enabled IRQ %x, for device %s\n", + device_tab[dev_id].udev.irqs[i].irq, + device_tab[dev_id].udev.name); + } + + /* Enable device itself (RCC, etc.) */ + if (device_tab[dev_id].devinfo != NULL) { + soc_devmap_enable_clock (device_tab[dev_id].devinfo); + KERNLOG(DBG_INFO, "Enabled device %s\n", device_tab[dev_id].udev.name); + } + + /* Device is not tagged as enabled */ + device_tab[dev_id].status = DEV_STATE_ENABLED; + if (device_tab[dev_id].udev.map_mode == DEV_MAP_AUTO) { + device_tab[dev_id].is_mapped = true; + } + return 0; +} + +/* +** Enable all GPIOs of a given device +*/ +uint8_t dev_enable_gpio(e_device_id dev_id) +{ + for (int i = 0; i < MIN(device_tab[dev_id].udev.gpio_num, MAX_GPIOS); ++i) { + gpio_enable_gpio(&device_tab[dev_id].udev.gpios[i]); + if (device_tab[dev_id].udev.gpios[i].exti_trigger != GPIO_EXTI_TRIGGER_NONE) { + exti_enable(device_tab[dev_id].udev.gpios[i].kref); + } + } + return 0; +} + +/************************************************************************ + * Device slotting functions + * These functions manage the devices kernel vector + ***********************************************************************/ + +e_device_id dev_get_free_device_slot(e_task_id task_id, device_t *udev) +{ + for (uint8_t i = ID_DEV1; i < ID_DEV_MAX; ++i) { + if (device_tab[i].status == DEV_STATE_NONE) { + device_tab[i].task_id = task_id; + device_tab[i].status = DEV_STATE_RESERVED; + device_tab[i].udev = *udev; + return i; + } + } + return ID_DEV_UNUSED; +} + +void dev_release_device_slot (e_device_id dev_id) +{ + device_tab[dev_id].task_id = ID_UNUSED; + device_tab[dev_id].devinfo = NULL; + device_tab[dev_id].status = DEV_STATE_NONE; +} + +/************************************************************************ + * Device package initialization function and subfunctions + ***********************************************************************/ + +e_task_id dev_get_task_from_gpio_kref(gpioref_t kref) +{ + /* + * We loop on all devices to find the given GPIO kref + */ + for (uint8_t i = ID_DEV1; i < ID_DEV_MAX; ++i) { + /* No more devices, just leave loop */ + if (device_tab[i].status == DEV_STATE_NONE) { + break; + } + for (uint8_t gpio = 0; gpio < device_tab[i].udev.gpio_num; ++gpio) { + if (device_tab[i].udev.gpios[gpio].kref.val == kref.val) { + return device_tab[i].task_id; + } + } + } + return ID_UNUSED; +} + +/** + * device package initialization function + */ +void dev_init(void) +{ + for (int i = 0; i < ID_DEV_MAX; ++i) { + device_tab[i].task_id = ID_UNUSED; + device_tab[i].status = DEV_STATE_NONE; + } +} + + +/************************************************************************ + * Checking if the user defined device is sound. + ***********************************************************************/ + +/* + * This file check that the device_t structure declare an existing device in + * the current SoC. The address and size should be valid. + * + * All IRQ and GPIO contents should be properly defined and valid. + * + * Furthermore, this function check that the irq list and gpio list is + * homogeneous (no table overflow), to avoid any memory fault in the kernel. +*/ + +retval_t dev_sanitize_user_defined_irq + (device_t *udev, dev_irq_info_t irqinfo, e_task_id task_id) +{ + if ((irqinfo.handler == NULL) || + (!sanitize_is_pointer_in_txt_slot(irqinfo.handler, task_id))) + { + return FAILURE; + } + + if (irqinfo.irq < USER_IRQ_MIN || irqinfo.irq > USER_IRQ_MAX) { + return FAILURE; + } + + if ((irqinfo.mode == IRQ_ISR_FORCE_MAINTHREAD) && + (!perm_ressource_is_granted(PERM_RES_TSK_FISR, task_id))) { + return FAILURE; + } + + for (int i=0; i udev->size - 4) || + (irqinfo.posthook.action[i].read.offset % 4)) { + return FAILURE; + } + break; + case IRQ_PH_WRITE: + KERNLOG(DBG_INFO, "detecting PH_WRITE posthook for irq %x\n", irqinfo.irq); + if ((irqinfo.posthook.action[i].write.offset > udev->size - 4) || + (irqinfo.posthook.action[i].write.offset % 4)) { + return FAILURE; + } + break; + case IRQ_PH_AND: + KERNLOG(DBG_INFO, "detecting PH_AND posthook for irq %x\n", irqinfo.irq); + if ((irqinfo.posthook.action[i].and.offset_dest > udev->size - 4) + || (irqinfo.posthook.action[i].and.offset_dest % 4)) { + return FAILURE; + } + if ((irqinfo.posthook.action[i].and.offset_src > udev->size - 4) + || (irqinfo.posthook.action[i].and.offset_src % 4)) { + return FAILURE; + } + break; + case IRQ_PH_MASK: + KERNLOG(DBG_INFO, "detecting PH_MASK posthook for irq %x\n", irqinfo.irq); + if ((irqinfo.posthook.action[i].mask.offset_dest > udev->size - 4) + || (irqinfo.posthook.action[i].mask.offset_dest % 4)) { + return FAILURE; + } + if ((irqinfo.posthook.action[i].mask.offset_src > udev->size - 4) + || (irqinfo.posthook.action[i].mask.offset_src % 4)) { + return FAILURE; + } + if ((irqinfo.posthook.action[i].mask.offset_mask > udev->size - 4) + || (irqinfo.posthook.action[i].mask.offset_mask % 4)) { + return FAILURE; + } + break; + default: + return FAILURE; + } + } + + return SUCCESS; +} + + +retval_t dev_sanitize_user_defined_gpio + (device_t *udev __attribute__((unused)), dev_gpio_info_t gpioinfo, + e_task_id task_id) +{ + if ((gpioinfo.exti_trigger != GPIO_EXTI_TRIGGER_NONE) && + (!perm_ressource_is_granted(PERM_RES_DEV_EXTI, task_id))) + { + return FAILURE; + } + + if ((gpioinfo.exti_handler != NULL) && + (!sanitize_is_pointer_in_txt_slot(gpioinfo.exti_handler, task_id))) + { + return FAILURE; + } + + return SUCCESS; +} + + +retval_t dev_sanitize_user_device (device_t *udev, e_task_id task_id) +{ + struct device_soc_infos *devinfo = NULL; + retval_t ret; + + if (udev->address == 0 && udev->size == 0) { + KERNLOG(DBG_INFO, + "Registering a device with no memory mapping %s\n", udev->name); + } else { + devinfo = soc_devmap_find_device(udev->address, udev->size); + if (devinfo == NULL) { + KERNLOG(DBG_ERR, "Device %s not found\n", udev->name); + return FAILURE; + } + if (!perm_ressource_is_granted(devinfo->minperm, task_id)) { + KERNLOG(DBG_ERR, "Task %d requiring device %s without associated permissions\n", task_id, udev->name); + return FAILURE; + } + } + + udev->name[15] = '\0'; + + if (udev->irq_num > MAX_IRQS) { + KERNLOG(DBG_ERR, "device %s : invalid udev.irq_num value (%d)\n", + udev->name, udev->irq_num); + return FAILURE; + } + + if (udev->gpio_num > MAX_GPIOS) { + KERNLOG(DBG_ERR, "device %s : invalid udev.gpio_num value (%d)\n", + udev->name, udev->gpio_num); + return FAILURE; + } + + for (int i = 0; i < udev->irq_num; ++i) { + ret = dev_sanitize_user_defined_irq(udev, udev->irqs[i], task_id); + if (ret != SUCCESS) { + KERNLOG(DBG_ERR, "device %s : invalid udev.irqs parameters\n", + udev->name); + return FAILURE; + } + } + + for (int i = 0; i < udev->gpio_num; ++i) { + ret = dev_sanitize_user_defined_gpio(udev, udev->gpios[i], task_id); + if (ret != SUCCESS) { + KERNLOG(DBG_ERR, "device %s : invalid udev.gpios parameters\n", + udev->name); + return FAILURE; + } + } + if (udev->map_mode == DEV_MAP_VOLUNTARY) { + if (!perm_ressource_is_granted(PERM_RES_MEM_DYNAMIC_MAP, task_id)) { + KERNLOG(DBG_ERR, "device %s : voluntary device map not permited\n", + udev->name); + return FAILURE; + } + } + + return SUCCESS; +} + diff --git a/devices.h b/devices.h new file mode 100644 index 0000000..385f34a --- /dev/null +++ b/devices.h @@ -0,0 +1,164 @@ +/* devices.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef DEVICES_H_ +#define DEVICES_H_ + +#include "exported/devices.h" +#include "types.h" +#include "tasks.h" + +typedef enum { + DEV_TYPE_USER, + DEV_TYPE_KERNEL, +} e_dev_type; + +typedef enum { + DEV_STATE_NONE, + DEV_STATE_RESERVED, + DEV_STATE_CREATED, + DEV_STATE_REGISTERED, + DEV_STATE_ENABLED, + DEV_STATE_REG_FAIL, +} e_dev_state; + +typedef struct { + device_t udev; + e_task_id task_id; + bool is_mapped; /* for voluntary devices state */ + const struct device_soc_infos *devinfo; + e_dev_state status; +} k_device_t; + +/************************************************************************ + * Device package getters and setters + ***********************************************************************/ + +retval_t dev_set_device_map (bool state, e_device_id dev_id); + +e_task_id dev_get_task_from_id (e_device_id dev_id); + +bool dev_is_mapped(e_device_id dev_id); + +device_t* dev_get_device_from_id (e_device_id dev_id); + +uint16_t dev_get_device_size (e_device_id dev_id); + +physaddr_t dev_get_device_addr (e_device_id dev_id); + +bool dev_is_mapped_voluntary (e_device_id dev_id); + +bool dev_is_device_region_ro (e_device_id dev_id); + +uint8_t dev_get_device_region_mask (e_device_id dev_id); + +/* +** Registering a new device. This function is call by the sys_init(REGISTER_DEVICE) syscall +*/ +uint8_t dev_register_device(e_device_id, device_t*); + +/** + * \brief return the irq info structure from an IRQ and associated task + * + * \param[in] task the task to which the device belongs + * \param[in] irq the irq number + * + * \return the corresponding irq info structure, or 0 if not found. + */ +dev_irq_info_t *dev_get_irqinfo_from_irq(uint8_t irq); + +e_task_id dev_get_task_from_gpio_kref(gpioref_t kref); + +dev_gpio_info_t *dev_get_gpio_from_gpio_kref(gpioref_t kref); + + +/************************************************************************ + * Device registration functions + ***********************************************************************/ + +/* + * This function simply register the GPIO. It update the user device_t gpio + * struct with the kref corresponding to the concatenation of the GPIO port + * (4bits) and the pin number (4 bits). + * This will permit to the user application to interract with the GPIO using + * a syscall with this kref as an argument. + */ +uint8_t dev_register_gpios(e_device_id dev_id, e_task_id task_id); + + +/*! + * \brief Register all the task's device ISR in the IRQ manager + * + * ISR will be executed in thread mode, in the task global context, but + * with a dedicated stack and local autonomous context for save/restore, + * to support preemption by IRQ. + */ +uint8_t dev_register_handlers(e_device_id dev_id, e_task_id task_id); + +/************************************************************************ + * Device slotting functions + ***********************************************************************/ + +void dev_release_device_slot(e_device_id); + +e_device_id dev_get_free_device_slot(e_task_id, device_t*); + + +/************************************************************************ + * Device Enabling functions + ***********************************************************************/ +/* +** Enable all GPIOs of a given device +*/ +uint8_t dev_enable_gpio(e_device_id); + +/* +** This function should be called by syscall sys_init(INIT_LOCK). +** This behavior: +** 1) forces user tasks to use this syscall, locking any future sys_init usage +** 2) enable all devices of the task at one single moment, at the end of init +*/ +uint8_t dev_enable_device(e_device_id); + + + +/************************************************************************ + * Device sanitation + ***********************************************************************/ +/* + * This file check that the device_t structure declare an existing device in + * the current SoC. The address and size should be valid. + * + * All IRQ and GPIO contents should be properly defined and valid. + * + * Furthermore, this function check that the irq list and gpio list is + * homogeneous (no table overflow), to avoid any memory fault in the kernel. +*/ +retval_t dev_sanitize_user_device (device_t *udev, e_task_id task_id); + +/************************************************************************ + * Device package initialization function and subfunctions + ***********************************************************************/ +void dev_init(void); + +#endif /*!DEVICES_H_ */ diff --git a/dma-shared.h b/dma-shared.h new file mode 100644 index 0000000..3877147 --- /dev/null +++ b/dma-shared.h @@ -0,0 +1,50 @@ +/* dma-shared.h + * + * Copyright (C) 2018 ANSSI + * All rights reserved. + * + * This software may be modified and distributed under the terms + * of the BSD license. See the LICENSE file for details. + */ + +#ifndef DMA_ENUMS_H_ +# define DMA_ENUMS_H_ + +#ifdef CONFIG_KERNEL_DMA_ENABLE + +typedef enum { + ID_DMA_UNUSED = 0, + ID_DMA1, + ID_DMA2, + ID_DMA3, + ID_DMA4, + ID_DMA5, + ID_DMA6, + ID_DMA7, + ID_DMA8 +} e_dma_id; + +/** + * \brief current dma record status. + */ +typedef enum { + DMA_UNUSED, + + /** + * The DMA Steam is just declared but requires sys_ipc(DMA_RECONF) to + * be operationnal. Only the DMA controller, stream and channel are + * verified. + */ + DMA_INITIALIZED, + + /** + * The DMA stream is already properly set. It is possible to use + * sys_ipc(DMA_RELOAD) immediatly. The structure fields are all highly + * tested + */ + DMA_CONFIGURED +} dma_status_t; + +#endif + +#endif diff --git a/dma.c b/dma.c new file mode 100644 index 0000000..4e69bbd --- /dev/null +++ b/dma.c @@ -0,0 +1,553 @@ +/* dma.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "dma.h" +#include "soc-nvic.h" +#include "soc-dma.h" +#include "kernel.h" +#include "debug.h" +#include "autoconf.h" +#include "sanitize.h" +#include "libc.h" +#include "soc-devmap.h" +#include "tasks.h" + +#ifdef CONFIG_KERNEL_DMA_ENABLE +/* Ewok support up to 16 declared DMA streams at a time */ +#define MAX_DMAS 8 + +static k_dma_t dma_tab[MAX_DMAS]; +uint8_t num_dmas = ID_DMA1; + +static e_dma_id dma_get_dma_slot(void) +{ + if (num_dmas < MAX_DMAS) { + return num_dmas++; + } + return 0; +} + +bool dma_same_dma_stream_channel (e_dma_id id, const dma_t *dma) +{ + return (dma->dma == dma_tab[id].udma.dma && + dma->stream == dma_tab[id].udma.stream && + dma->channel == dma_tab[id].udma.channel); +} + +/** + * \brief check if there is no previously registered dma collisioning + * + * A DMA controller can serve only one configuration per controller/stream + * pair, whatever the channel is. + * + * \param[in] dma the current requested dma information + * + * \return true if the requested dma is free to use + */ +bool dma_stream_is_already_registered(const __user dma_t *dma) +{ + for (uint8_t id = ID_DMA1; id < num_dmas; id++) { + if (dma_same_dma_stream_channel (id, dma)) { + KERNLOG(DBG_ERR, "dma %d stream %d channel %d is already registered!\n", dma->dma, dma->stream, dma->channel); + return true; + } + } + return false; +} + +/** + * \brief load the DMA channel specified by its kernel identifier + */ +void dma_enable_dma_stream(e_dma_id dma_id) // FIXME - rename +{ + if (dma_tab[dma_id].status == DMA_CONFIGURED) { + soc_dma_enable(dma_tab[dma_id].udma.dma, dma_tab[dma_id].udma.stream); + } +} + +/** + * \brief disable the DMA channel specified by its kernel identifier + */ +void dma_disable_dma_stream(e_dma_id dma_id) +{ + if (dma_tab[dma_id].status == DMA_CONFIGURED) { + soc_dma_disable(dma_tab[dma_id].udma.dma, dma_tab[dma_id].udma.stream); + } + +} + +/*********************************************************** + * Kernel main syscalls control-flow related function + ***********************************************************/ + +/* +** Return true if all necessary fields are set in order to make the DMA +** works without risk. the enable bit can be set. +*/ +static bool dma_is_complete_dma(dma_t * dma) +{ + if (dma->in_addr == 0 || + dma->out_addr == 0 || + dma->size == 0 || + (dma->dir == MEMORY_TO_PERIPHERAL && dma->in_handler == 0) || + (dma->dir == PERIPHERAL_TO_MEMORY && dma->out_handler == 0)) + { + return false; + } else { + return true; + } +} + +uint32_t ts0, ts1, ts2, ts3, ts4, ts5, ts6 = 0; + +/** + * \brief reconfigure a previously declared DMA stream + * + * This function reconfigure fields of a previously declared DMA stream of + * the caller task, using the mask argument. Authorized fields are the + * ones described in the dma_reconf_mask_t. + * + * \param[in/out] dma the user-provided new DMA configuration. May be + * incomplete, reduced to the DMA fields to reconfigure + * \param[in/out] kdma the kernel dma structure to update + * \param[in] mask the reconfiguration mask provided by the user + * \param[in] caller the task requesting the reconfiguration + * \param[in] mode task mode at syscall time (main thread or ISR thread) + * + * \return 0 if the reconfiguration succeeded, or 1 if an invalid value has + * been found. + */ +uint8_t dma_reconf_dma(__user dma_t *dma, + e_dma_id dma_id, + uint8_t mask, + e_task_id caller) +{ + /* + * Sanitizing buffer require the correct buffer size. If not set in + * the user-provided structure, the previous size (hosted in the kdma_t + * structure will be used. We update the dma_t structure with the good + * size before sanitation to permit a correct buffers boundcheck + */ + if (!(mask & DMA_RECONF_BUFSIZE)) { + dma->size = dma_tab[dma_id].udma.size; + } + + /* + * Now that we have checked the user structure, we can reconfigure + * the kernel structure with the user-provided fields, using the + * user-provided mask + */ + /* Update DMA direction (PERIPHERAL_TO_MEMORY, MEMORY_TO_PERIPHERAL...) */ + if (mask & DMA_RECONF_DIR) { + dma_tab[dma_id].udma.dir = dma->dir; + } + + /* Update buffer size if requested */ + if (mask & DMA_RECONF_BUFSIZE) { + dma_tab[dma_id].udma.size = dma->size; + } + + /* Update input buffer if requested */ + if (mask & DMA_RECONF_BUFIN) { + dma_tab[dma_id].udma.in_addr = dma->in_addr; + } + + /* Update output buffer if requested */ + if (mask & DMA_RECONF_BUFOUT) { + dma_tab[dma_id].udma.out_addr = dma->out_addr; + } + + /* Update DMA stream mode (direct/FIFO/... if requested */ + if (mask & DMA_RECONF_MODE) { + dma_tab[dma_id].udma.mode = dma->mode; + } + + /* Update DMA stream priority if requested */ + if (mask & DMA_RECONF_PRIO) { + switch (dma->dir) { + case MEMORY_TO_PERIPHERAL: + dma_tab[dma_id].udma.in_prio = dma->in_prio; + break; + case PERIPHERAL_TO_MEMORY: + dma_tab[dma_id].udma.out_prio = dma->out_prio; + break; + default: + break; + } + } + + /* Update DMA ISR handlers if requested */ + if (mask & DMA_RECONF_HANDLERS) { + switch (dma->dir) { + case MEMORY_TO_PERIPHERAL: + dma_tab[dma_id].udma.in_handler = dma->in_handler; + set_interrupt_handler(dma_tab[dma_id].devinfo->irq, + dma->in_handler, caller, ID_DEV_UNUSED); + break; + case PERIPHERAL_TO_MEMORY: + dma_tab[dma_id].udma.out_handler = dma->out_handler; + set_interrupt_handler(dma_tab[dma_id].devinfo->irq, + dma->out_handler, caller, ID_DEV_UNUSED); + break; + default: + break; + } + } + + soc_dma_reconf(dma_tab[dma_id].udma.dma, dma_tab[dma_id].udma.stream, + &dma_tab[dma_id].udma, DMA_RECONFIGURE, mask); + + /* + * To finish, we have to check if the completed DMA structure has all + * needed informations to permit DMA stream activation. If not, the + * kernel waits for another DMA reconfiguration. + */ + if (dma_is_complete_dma(&dma_tab[dma_id].udma)) { + dma_tab[dma_id].status = DMA_CONFIGURED; + soc_dma_enable(dma_tab[dma_id].udma.dma, dma_tab[dma_id].udma.stream); + } + ts6 = soc_dwt_getcycles(); + return 0; + +} + +/** + * \brief sanitize the user-specified DMA structure + * + * If the mask is null, all user fields are checked for invalid + * content (addresses, size, etc.). This is the case for initial + * dma configuration. + * + * If the mask is non-null, it is considered as a dma_reconf_mode_t + * enumerate and is used as is to detect which field has to be sanitized. + * This is the case for DMA reconfiguration. + * + * \param[in] dma the user-specified structure + * \param[in] task the task requesting the DMA + * \param[in] mask the field mask to limit the sanitation. 0 means no limit + * \param[in] mode task mode at syscall time (main thread or ISR thread) + * + * \return 0 if the structure is good, or non-zero + */ +inline uint8_t dma_sanitize_dma(dma_t *dma, + e_task_id caller, + uint8_t mask, + e_task_mode mode) +{ + /******************************************** + * Sanitize for DMA declaration + ********************************************/ + if (mask == 0) { + mask = 255; /* set all configurable field enabled */ + } + + if (mask == 255) { + if (dma->stream >= DMA_NB_STREAM) { + KERNLOG(DBG_ERR, "%s: dma stream %d invalid\n", task_get_name(caller), dma->stream); + goto ret_inval; + } + if (dma->dma > DMA_NB_CONTROLER) { + KERNLOG(DBG_ERR, "%s: dma controller %d invalid\n", task_get_name(caller), dma->dma); + goto ret_inval; + } + } + + + /************************************************* + * Sanitize for DMA declaration & reconfiguration + *************************************************/ + + /* Buffer size */ + if (mask & DMA_RECONF_BUFSIZE) { + } + + /* Direction */ + if (mask & DMA_RECONF_DIR) { + if ( dma->dir != PERIPHERAL_TO_MEMORY + && dma->dir != MEMORY_TO_PERIPHERAL) + { + KERNLOG(DBG_ERR, "%s: dma direction %x invalid\n", task_get_name(caller), dma->dir); + KERNLOG(DBG_ERR, "dma direction MEMORY_TO_MEMORY is forbidden by now\n"); + goto ret_inval; + } + } + + /* Input Buffer */ + if (mask & DMA_RECONF_BUFIN) { + if ((dma->dir != PERIPHERAL_TO_MEMORY)) { + if (!( sanitize_is_data_pointer_in_any_slot((void *)dma->in_addr, dma->size, caller, mode) + || sanitize_is_data_pointer_in_dma_shm((void *)dma->in_addr, dma->size, DMA_SHM_ACCESS_RD, caller) + || (dma->in_addr == 0) /* bufin not initialized */)) + { + KERNLOG(DBG_ERR, "%s: dma input buf %x invalid\n", task_get_name(caller), dma->in_addr); + goto ret_inval; + } + } + } + + /* Security TODO: Buffers in peripherals (in for PERIPHERAL_TO_MEMORY, out for MEMORY_TO_PERIPHERAL) should + * be mapped in the task's list of devices memories. Add a generic sanitize for _is_in_mapped_devices() */ + + /* Output Buffer */ + if (mask & DMA_RECONF_BUFOUT) { + if ((dma->dir != MEMORY_TO_PERIPHERAL)) { + if (!( sanitize_is_data_pointer_in_slot((void *)dma->out_addr, dma->size, caller, mode) + || sanitize_is_data_pointer_in_dma_shm((void *)dma->out_addr, dma->size, DMA_SHM_ACCESS_WR, caller) + || (dma->out_addr == 0) /* bufout not initialized */)) + { + KERNLOG(DBG_ERR, "%s: dma output buf %x invalid\n", task_get_name(caller), dma->out_addr); + goto ret_inval; + } + } + } + + /* DMA ISR handlers */ + if (mask & DMA_RECONF_HANDLERS) { + switch (dma->dir) { + case MEMORY_TO_PERIPHERAL: + if (!( sanitize_is_pointer_in_txt_slot((void *)dma->in_handler, caller) + || (dma->in_handler == 0))) + { + KERNLOG(DBG_ERR, "%s: dma in handler %x invalid\n", task_get_name(caller), dma->in_handler); + goto ret_inval; + } + break; + case PERIPHERAL_TO_MEMORY: + if (!( sanitize_is_pointer_in_txt_slot((void *)dma->out_handler, caller) + || (dma->in_handler == 0))) + { + KERNLOG(DBG_ERR, "%s: dma out handler %x invalid\n", task_get_name(caller), dma->out_handler); + goto ret_inval; + } + break; + default: + break; + } + } + + /* End of sanitation */ + return 0; + + ret_inval: + return 1; +} + +/** + * \brief Initialize the DMA controller + * + * The DMA controller is configured but not enabled. + * + * \param[in] dma the task's kernel dma structure + * \param[in] caller the task requesting the init + * \param[in] dma structure kernel identifier + * + * \return 0. + */ +uint8_t dma_init_dma(__user dma_t *dma, + e_task_id caller, + e_dma_id *id) +{ + e_dma_id dma_id = 0; + + dma_id = dma_get_dma_slot(); + if (!dma_id) { + goto ret_busy; + } + + // and duplicate in kernel + memcpy(&dma_tab[dma_id], dma, sizeof(dma_t)); + const struct device_soc_infos *devinfo = soc_devices_get_dma(dma->dma, dma->stream); + dma_tab[dma_id].task = caller; + dma_tab[dma_id].status = DMA_INITIALIZED; + dma_tab[dma_id].devinfo = devinfo; + + // registering IRQ handler FIXME: check between in or out + switch (dma_tab[dma_id].udma.dir) { + case MEMORY_TO_PERIPHERAL: + set_interrupt_handler + (dma_tab[dma_id].devinfo->irq, dma_tab[dma_id].udma.in_handler, + caller, ID_DEV_UNUSED); + break; + case PERIPHERAL_TO_MEMORY: + set_interrupt_handler + (dma_tab[dma_id].devinfo->irq, dma_tab[dma_id].udma.out_handler, + caller, ID_DEV_UNUSED); + break; + case MEMORY_TO_MEMORY: + // TODO... + break; + } + + set_reg_bits(dma_tab[dma_id].devinfo->rcc_enr, dma_tab[dma_id].devinfo->rcc_enb); + soc_dma_init(dma_tab[dma_id].udma.dma, dma_tab[dma_id].udma.stream, &dma_tab[dma_id].udma); + *id = dma_id; + return 0; + +ret_busy: + return 1; +} + +/** + * \brief Enable the DMA IRQ line. + * + * Enable CEN bit of DMA stream CR register & TCIE/HTIE/TEIE/DMEIE bits are + * volunaty set by IPC_DMA_RECONF/RELOAD syscall. This permit to wait for a + * potential other task to initialize a device (e.g. CRYP) before starting + * the DMA. This make the userspace task mastering the DMA start time. + * + * \param[in] dma the kernel dma structure to enable. + * + * \return 0. + */ +uint8_t dma_enable_dma_irq(e_dma_id dma) +{ + /* activate IRQ line for stream */ + NVIC_EnableIRQ((uint32_t) dma_tab[dma].devinfo->irq - 0x10); /* minus core interrupts */ + KERNLOG(DBG_INFO, "Enabled IRQ %x, for device %s\n", + dma_tab[dma].devinfo->irq - 16, dma_tab[dma].devinfo->name); + return 0; +} + + + +/**************************************************** + * Kernel DMA module init + ***************************************************/ + +/** + * \brief Kernel DMA subsystem init + * + * Enable the clock input of the DMA controllers. + */ +void dma_init(void) +{ + const struct device_soc_infos *devinfo; + + // Activate RCC input for DMA1 & 2. + devinfo = soc_devices_get_dma(1, 0); + set_reg_bits(devinfo->rcc_enr, devinfo->rcc_enb); + devinfo = soc_devices_get_dma(2, 0); + set_reg_bits(devinfo->rcc_enr, devinfo->rcc_enb); + //soc_dma_reset(); +} + +/**************************************************** + * Kernel internal utility function + ***************************************************/ + +/** + * \brief clean the pending interrupt in the DMA controller + * + * This is not a NVIC-level cleaning here, but a SR cleaning + * + * \param [in] calller the task associated to the IRQ + * \param [in] irq the IRQ number as managed in soc-interrupts.h + * + */ +void dma_clean_int(const e_task_id caller, uint8_t irq) +{ + k_dma_t *kdma; + task_t *caller_task = task_get_task(caller); + + for (uint8_t i = 0; i < caller_task->num_dmas; ++i) { + kdma = &dma_tab[caller_task->dma[i]]; + if (kdma->devinfo->irq == irq) { + soc_dma_clean_int(kdma->udma.dma, kdma->udma.stream); + break; + } + } +} + +/** + * \brief return the DMA status register of the given controller + * + * \param [in] calller the task associated to the IRQ + * \param [in] irq the IRQ number as managed in soc-irq.h + * + */ +uint32_t dma_get_status(e_task_id caller, uint8_t irq) // FIXME - irq or interrupt ? +{ + k_dma_t *kdma; + uint32_t status = 0; + task_t *caller_task = task_get_task(caller); + + for (uint8_t i = 0; i < caller_task->num_dmas; ++i) { + kdma = &dma_tab[caller_task->dma[i]]; // FIXME + if (kdma->devinfo->irq == irq) { // FIXME + status = soc_dma_get_status(kdma->udma.dma, kdma->udma.stream); + break; + } + } + return status; +} + +/********************************************************* + * DMA SHM related + ********************************************************/ + +/** + * \brief check the dma_shm_t user-provided content + * + * \return 0 if structure is clean, or 1 if invalid. + */ +uint8_t dma_shm_sanitize(dma_shm_t *dmashm, e_task_id caller, e_task_mode mode) +{ + /* target doesn't exist or is not a user task ? */ + if (!task_is_user(dmashm->target)) { + KERNLOG(DBG_ERR, "Invalid task %d declaring DMA SHM\n", caller); + return 1; + } + + /* The user application has tried to spoof its own identifier */ + if (dmashm->source != caller) { + KERNLOG(DBG_ERR, + "DMA SHM source identifier is not own by caller task %d\n", + caller); + return 1; + } + +#ifdef CONFIG_KERNEL_DOMAIN + /* if target is not in the same domain, return inval instead of + denied to avoid giving some hint to the task about other domains's + tasks id. + */ + if (!perm_same_ipc_domain(dmashm->target, caller)) { + KERNLOG(DBG_ERR, + "DMA SHM target %d doesn't exist or is not in the same IPC domain\n", + dmashm->target); + return 1; + } +#endif + + /* check region address and size */ + if (!sanitize_is_data_pointer_in_slot((void*)dmashm->address, dmashm->size, caller, mode)) { + KERNLOG(DBG_ERR, + "DMA SHM buffer %x is not owned by the declaring task\n", + dmashm->address); + return 1; + } + + return 0; +} + +#endif diff --git a/dma.h b/dma.h new file mode 100644 index 0000000..ce10c6c --- /dev/null +++ b/dma.h @@ -0,0 +1,200 @@ +/* \file dma.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef DMA_H +#define DMA_H + +/** + * \file dma + * + * \brief this is the kernel, arch-generic support for secure DMA + * + * This file declare the kernel internal API for secure DMA API. This file + * exports types and prototypes only if CONFIG_KERNEL_DMA_ENABLE is set in + * kernel Kconfig. + * + */ + +#include "types.h" +#include "exported/dmas.h" +#include "tasks.h" +#include "dma-shared.h" +#include "autoconf.h" + +#ifdef CONFIG_KERNEL_DMA_ENABLE + +/** + * \brief kernel DMA record, containing the user-configured DMA record + * + * In order to keep kernel-specific metadata internals, the kernel use + * this structure in union with dma_t user-specified structure. + * This permit to expose the dma_t structure in the exported/dma.h header + * and keep the complete dma kernel structure here. + * the dma_t structure is keeped as a udma param in the k_dma_t + * structure + */ +typedef struct { + dma_t udma; + e_task_id task; + dma_status_t status; + const struct device_soc_infos *devinfo; +} k_dma_t; + +/** + * \brief sanitize the user-specified DMA structure + * + * If the mask is null, all user fields are checked for invalid + * content (addresses, size, etc.). This is the case for initial + * dma configuration. + * + * If the mask is non-null, it is considered as a dma_reconf_mode_t + * enumerate and is used as is to detect which field has to be sanitized. + * This is the case for DMA reconfiguration. + * + * \param[in] dma the user-specified structure + * \param[in] task the task requesting the DMA + * \param[in] mask the field mask to limit the sanitation. 0 means no limit + * + * \return 0 if the structure is good, or non-zero + */ +uint8_t dma_sanitize_dma(dma_t *dma, + e_task_id caller, + uint8_t mask, + e_task_mode mode); + +/** + * \brief Initialize the DMA controller + * + * The DMA is configured but *not* enabled. Enabling the DMA (i.e. starting + * a memory copy) is a voluntary configuration action from the task. + * + * \param[in] dma the user DMA structure + * \param[in] task the task requesting the DMA + * \param[out] DMA handle identifier + * + * \return 0 if the DMA is configured properly, or non-zero + */ +uint8_t dma_init_dma(dma_t *dma, + e_task_id task, + e_dma_id *id); + + +/** + * \brief reconfigure a previously declared DMA stream + * + * This function reconfigure fields of a previously declared DMA stream of + * the caller task, using the mask argument. Authorized fields are the + * ones described in the dma_reconf_mask_t. + * + * \param[in/out] dma the user-provided new DMA configuration. May be + * incomplete, reduced to the DMA fields to reconfigure + * \param[in/out] kdma the kernel dma structure to update + * \param[in] mask the reconfiguration mask provided by the user + * \param[in] caller the task requesting the reconfiguration + * + * \return 0 if the reconfiguration succeeded, or 1 if an invalid value has + * been found. + */ +uint8_t dma_reconf_dma(__user dma_t *dma, + e_dma_id dma_id, + uint8_t mask, + e_task_id caller); + +/** + * \brief Enable the DMA IRQ line. + * + * Enable CEN bit of DMA stream CR register & TCIE/HTIE/TEIE/DMEIE bits are + * volunaty set by IPC_DMA_RECONF/RELOAD syscall. This permit to wait for a + * potential other task to initialize a device (e.g. CRYP) before starting + * the DMA. This make the userspace task mastering the DMA start time. + * + * \param[in] dma the kernel dma structure to enable. + * + * \return 0. + */ +uint8_t dma_enable_dma_irq(e_dma_id dma); + +/** + * \brief Kernel DMA subsystem init + * + * Enable the clock input of the DMA controllers. + */ +void dma_init(void); + +/** + * \brief return the DMA status register of the given controller + * + * \param [in] calller the task associated to the IRQ + * \param [in] irq the IRQ number as managed in soc-interrupts.h + * + */ +uint32_t dma_get_status(e_task_id caller, uint8_t irq); + +/** + * \brief clean the pending interrupt in the DMA controller + * + * This is not a NVIC-level cleaning here, but a SR cleaning + * + * \param [in] calller the task associated to the IRQ + * \param [in] irq the IRQ number as managed in soc-irq.h + * + */ +void dma_clean_int(e_task_id caller, uint8_t irq); + +/** + * \brief check the dma_shm_t user-provided content + * + * \return 0 if structure is clean, or 1 if invalid. + */ +uint8_t dma_shm_sanitize(dma_shm_t *dmashm, e_task_id caller, e_task_mode mode); + +/* + * \return true if the dma config and the related dma_tab[id] share the same dma/stream/channel + */ +bool dma_same_dma_stream_channel (e_dma_id id, const dma_t *dma); + +/** + * \brief check if there is no previously registered dma collisioning + * + * A DMA controller can serve only one configuration per controller/stream + * pair, whatever the channel is. + * + * \param[in] dma the current requested dma information + * + * \return true if the requested dma is free to use + */ +bool dma_stream_is_already_registered(const __user dma_t *dma); + +/** + * \brief load the DMA channel specified by its kernel identifier + */ +void dma_enable_dma_stream(e_dma_id dma_id); + +/** + * \brief disable the DMA channel specified by its kernel identifier + */ +void dma_disable_dma_stream(e_dma_id dma_id); + + +#endif +#endif diff --git a/exported/devices.h b/exported/devices.h new file mode 100644 index 0000000..cb0b8e7 --- /dev/null +++ b/exported/devices.h @@ -0,0 +1,111 @@ +/* \file devices.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef KERNEL_DEVICES_H +#define KERNEL_DEVICES_H + +/* + * Remember to include libstd types.h header for stdint support + */ +#include "gpio.h" +#include "irq.h" + +/* +** Per device max values +*/ + +#define MAX_IRQS 4 /**< The maximum number of IRQ lines per device*/ + +typedef enum { + /** + * automatically map device at sys_init(INIT_DONE) time. The device can't + * be unmap by the task and is mapped once for all. + */ + DEV_MAP_AUTO, + /** + * map the device voluntary using sys_cfg(CFG_DEV_MAP, devid). + * The device can be unmap using sys_cfg(CFG_DEV_UNMAP, devid). + * The device is *not* mapped at sys_init(INIT_DONE) and its mapping time + * slots is under the control of the task. + * Mapping the device voluntary requires a specific permission. + */ + DEV_MAP_VOLUNTARY +} dev_map_mode_t; + + +/** +** \brief this is the main device declaration structure for userspace drivers +** +** These information MUST be declared before sys_init(INIT_DONE) and no +** device/handler registration will be authorized after. Devices will be +** activated by sys_init(INIT_DONE). +** +** PS: Local applications are not considered as a source of a potential attack +** before the call of sys_init(INIT_DONE). Only remote attackers are considered +** in this scheme (through USB communication, etc.) +*/ +typedef struct { + /**< Device name. + * For pretty printing + */ + char name[16]; + + /**< Device base address. + * Device memory mapped address, as defined in the SoC or board + * datasheet. The kernel checks it against the SoC/board devmap. + */ + physaddr_t address; + + /**< Device memory mapping size + * Memory mapped size (in bytes). Mandatory to map the device in the task + * address space (during context switching). Its size is checked against + * the SoC/board devmap. + */ + uint16_t size; + + /**< Number of IRQ lines associated to the device. + * How many entries in irqs[] array are used. + */ + uint8_t irq_num; + + /**< Number of GPIO lines associated to the device. + * How many entries in gpios[] array are used. + */ + uint8_t gpio_num; + + /**< Type of device mapping (automatic or voluntary). + */ + dev_map_mode_t map_mode; + + /**< List or configured IRQs + * For each entry, a structure dev_irq_info_t is set \sa dev_irq_info_t + */ + dev_irq_info_t irqs[MAX_IRQS]; + + /**< List of configured GPIOs + * For each slot, a structure dev_gpio_info_t is set \sa dev_gpio_info_t + */ + dev_gpio_info_t gpios[MAX_GPIOS]; + +} device_t; + +#endif diff --git a/exported/dmas.h b/exported/dmas.h new file mode 100644 index 0000000..42ea214 --- /dev/null +++ b/exported/dmas.h @@ -0,0 +1,171 @@ +/* \file dmas.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef EXPORTED_DMAS_H_ +#define EXPORTED_DMAS_H_ + +#include "../tasks-shared.h" + +typedef enum { + /** Reconfigure handlers (in or out, depending on direction) */ + DMA_RECONF_HANDLERS = 0b0000001, + /** Reconfigure source buffer */ + DMA_RECONF_BUFIN = 0b0000010, + /** Reconfigure destination buffer */ + DMA_RECONF_BUFOUT = 0b0000100, + /** Reconfigure buffer size (in bytes) */ + DMA_RECONF_BUFSIZE = 0b0001000, + /** Reconfigure DMA mode */ + DMA_RECONF_MODE = 0b0010000, + /** Reconfigure DMA priority */ + DMA_RECONF_PRIO = 0b0100000, + /** Reconfigure DMA direction */ + DMA_RECONF_DIR = 0b1000000, + /** Reconfigure all fields (handlers, buffers, size, mode and priority */ + DMA_RECONF_ALL = 0b1111111, +} dma_reconf_mask_t; + +typedef enum { + /** Direct mode: copy source address content */ + DMA_DIRECT_MODE = 0, + /** FIFO mode: using FIFO indirection of address pointers */ + DMA_FIFO_MODE = 1, + /** Circular mode: using a circular buffer */ + DMA_CIRCULAR_MODE = 2 +} dma_mode_t; + +typedef enum { + /** From device memory to main memory (flash, (S)RAM) */ + PERIPHERAL_TO_MEMORY = 0, + /** From main memory (flash, (S)RAM) to device memory */ + MEMORY_TO_PERIPHERAL, + /** From main memory to main memory */ + MEMORY_TO_MEMORY +} dma_dir_t; + +/** +** \brief DMA Stream priority +** +** A best practice is to define a higher priority for device to memory than +** for memory to device stream when targetting the same device, avoiding +** device contention +*/ +typedef enum { + DMA_PRI_LOW, /**< Low piority, lower one */ + DMA_PRI_MEDIUM, /**< Medium priority */ + DMA_PRI_HIGH, /**< High priority */ + DMA_PRI_VERY_HIGH /**< Very high priority */ +} dma_prio_t; + +/** +** \brief DMA Data unit size +*/ +typedef enum { + DMA_DS_BYTE, /**< Data unit is one byte sized */ + DMA_DS_HALFWORD, /**< Data unit is Half-Word sized */ + DMA_DS_WORD /**< Data unit is Word sized */ +} dma_datasize_t; + +typedef enum { + /** No burst */ + DMA_BURST_SINGLE, + /** 4 bytes burst reading */ + DMA_BURST_INC4, + /** 8 bytes burst reading */ + DMA_BURST_INCR8, + /** 16 bytes burst reading */ + DMA_BURST_INCR16 +} dma_burst_t; + +typedef enum { + /** Flow control is made by DMA controller */ + DMA_FLOWCTRL_DMA = 0, + /** Flow control is made by target peripheral */ + DMA_FLOWCTRL_DEV = 1, +} dma_flowctrl_t; + +typedef void (*user_dma_handler_t) (uint8_t irq, uint32_t status); + +/** +** \brief This is the global user DMA controler structure definition. +** +** This structure is passed to the kernel in order to declare a DMA channel. +** The DMA is configured by the kernel after parameters check (task slotting, etc.) +** The task ISR handlers will be able to reload the DMA controler but will not be +** authorized to reconfigure the in/out address or size of the DMA controler. Such +** operation requires the usage of a specific syscall. +** +** The DMA channel must correspond to an existing device that has already been declared +** by the task. Otherwhise, the DMA declaration returns SYS_E_DENIED. +** +** All the structure's fields are compared with the current SoC's DMA mapping to +** validate that the corresponding stream is able to respond to the request +*/ +typedef struct { + physaddr_t in_addr; /**< DMA input base address, for memory to memory or to peripheral only */ + physaddr_t out_addr; /**< DMA output base address for peripheral to memory or memory to memory only */ + dma_prio_t in_prio; /**< DMA priority for memory to peripheral */ + dma_prio_t out_prio; /**< DMA priority for peripheral to peripheral */ + uint16_t size; /**< DMA output size to copy (in bytes, whatever the datasize is) */ + uint8_t dma; /**< DMA controler identifier, (starting with 1 for DMA1, 2 for DMA2, etc.) */ + uint8_t channel; /**< DMA channel to configure */ + uint8_t stream; /**< DMA stream to configure */ + dma_flowctrl_t flow_control; /**< DMA Flow controller */ + dma_dir_t dir; /**< Current DMA direction */ + dma_mode_t mode; /**< Current DMA mode */ + bool mem_inc; /**< DMA increment for memory, when set to 0, the device doesn't increment + the memory address at each read */ + bool dev_inc; /**< DMA increment for device, with the same behavior as the mem_inc, but + for the device. Typically set to 0 when the DMA read (or write) to (from) + a register */ + dma_datasize_t datasize; /**< data unit size (byte, HW or Word, varies depending on the device specifications */ + dma_burst_t mem_burst; /**< type of DMA burst mode */ + dma_burst_t dev_burst; /**< type of DMA burst mode */ + user_dma_handler_t in_handler; + /**< associated ISR, with one argument (irqnum), see types.h */ + user_dma_handler_t out_handler; + /**< associated ISR, with one argument (irqnum), see types.h */ +} dma_t; + + +/** +** \brief DMA shared memory access mode +*/ +typedef enum { + DMA_SHM_ACCESS_RD, /**< The DMA SHR is a DMA source address only */ + DMA_SHM_ACCESS_WR, /**< The DMA SHR is a DMA destination address only */ +} dma_shm_access_t; + +/** +** \brief DMA shared memory structure +** This structure host the DMA hared memory informations passed to the +** kernel when declaring a DMA SHM with another task +*/ +typedef struct { + e_task_id target; /**< target task authorized to initiate a DMA transfer to/from this region */ + e_task_id source; /**< Your own id */ + uint32_t address; /**< the region base address */ + uint16_t size; /**< the region size (in bytes) */ + dma_shm_access_t mode; /**< the region access rights */ +} dma_shm_t; + +#endif /*!EXPORTED_DMAS_H_ */ diff --git a/exported/gpio.h b/exported/gpio.h new file mode 100644 index 0000000..1c554f8 --- /dev/null +++ b/exported/gpio.h @@ -0,0 +1,230 @@ +/* + * \file gpio.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef KERNEL_GPIO_H +#define KERNEL_GPIO_H +/* + * Remember to include libstd types.h header for stdint support + */ + +/**< The maximum number of GPIO lines per device*/ +#define MAX_GPIOS 16 + +typedef void (*user_handler_t) (uint8_t irq, uint32_t status, uint32_t data); + +/* + * GPIO Alternate functions (numeric values) + */ +typedef enum { + GPIO_AF_AF0 = 0x0, + GPIO_AF_AF1 = 0x1, + GPIO_AF_AF2 = 0x2, + GPIO_AF_AF3 = 0x3, + GPIO_AF_AF4 = 0x4, + GPIO_AF_AF5 = 0x5, + GPIO_AF_AF6 = 0x6, + GPIO_AF_AF7 = 0x7, + GPIO_AF_AF8 = 0x8, + GPIO_AF_AF9 = 0x9, + GPIO_AF_AF10 = 0xa, + GPIO_AF_AF11 = 0xb, + GPIO_AF_AF12 = 0xc, + GPIO_AF_AF13 = 0xd, + GPIO_AF_AF14 = 0xe, + GPIO_AF_AF15 = 0xf +} gpio_af_t; + +/* + * GPIO alternate functions + * human readable values, using macros, these are still gpio_af_t. + */ +#define GPIO_AF_SYSTEM GPIO_AF_AF0 +#define GPIO_AF_TIM1 GPIO_AF_AF1 +#define GPIO_AF_TIM2 GPIO_AF_AF1 +#define GPIO_AF_TIM3 GPIO_AF_AF2 +#define GPIO_AF_TIM4 GPIO_AF_AF2 +#define GPIO_AF_TIM5 GPIO_AF_AF2 +#define GPIO_AF_TIM8 GPIO_AF_AF3 +#define GPIO_AF_TIM9 GPIO_AF_AF3 +#define GPIO_AF_TIM10 GPIO_AF_AF3 +#define GPIO_AF_TIM11 GPIO_AF_AF3 +#define GPIO_AF_I2C1 GPIO_AF_AF4 +#define GPIO_AF_I2C2 GPIO_AF_AF4 +#define GPIO_AF_I2C3 GPIO_AF_AF4 +#define GPIO_AF_SPI1 GPIO_AF_AF5 +#define GPIO_AF_SPI2 GPIO_AF_AF5 +#define GPIO_AF_SPI3 GPIO_AF_AF6 +#define GPIO_AF_USART1 GPIO_AF_AF7 +#define GPIO_AF_USART2 GPIO_AF_AF7 +#define GPIO_AF_USART3 GPIO_AF_AF7 +#define GPIO_AF_USART4 GPIO_AF_AF8 +#define GPIO_AF_UART4 GPIO_AF_AF8 +#define GPIO_AF_USART5 GPIO_AF_AF8 +#define GPIO_AF_UART5 GPIO_AF_AF8 +#define GPIO_AF_USART6 GPIO_AF_AF8 +#define GPIO_AF_CAN1 GPIO_AF_AF9 +#define GPIO_AF_CAN2 GPIO_AF_AF9 +#define GPIO_AF_TIM12 GPIO_AF_AF9 +#define GPIO_AF_TIM13 GPIO_AF_AF9 +#define GPIO_AF_TIM14 GPIO_AF_AF9 +#define GPIO_AF_OTG_FS GPIO_AF_AF10 +#define GPIO_AF_OTG_HS GPIO_AF_AF10 +#define GPIO_AF_ETH GPIO_AF_AF11 +#define GPIO_AF_FSMC GPIO_AF_AF12 +#define GPIO_AF_SDIO GPIO_AF_AF12 +#define GPIO_AF_OTG_HS_FS GPIO_AF_AF12 +#define GPIO_AF_DCMI GPIO_AF_AF13 +#define GPIO_AF_EVENTOUT GPIO_AF_AF15 + +/** + * GPIO inputs mode + */ +typedef enum { + GPIO_NOPULL = 0, + /**< GPIO pin in No Pull mode */ + GPIO_PULLUP = 1, + /**< GPIO pin in Pull UP mode */ + GPIO_PULLDOWN = 2, + /**< GPIO pin in Pull Down mode */ +} gpio_pupd_t; + +/** + * GPIO direction + */ +typedef enum { + GPIO_PIN_INPUT_MODE = 0, + /**< GPIO pin in input mode */ + GPIO_PIN_OUTPUT_MODE = 1, + /**< GPIO pin in output mode */ + GPIO_PIN_ALTERNATE_MODE = 2, + /**< GPIO pin in anternative mode */ + GPIO_PIN_ANALOG_MODE = 3 + /**< GPIO pin in analogic mode */ +} gpio_mode_t; + +/** + * GPIO speed, depending on the value measured (timer, sensor...) + */ +typedef enum { + GPIO_PIN_LOW_SPEED = 0, + /**< GPIO pin in low speed mode */ + GPIO_PIN_MEDIUM_SPEED = 1, + /**< GPIO pin in medium speed mode */ + GPIO_PIN_HIGH_SPEED = 2, + /**< GPIO pin in high speed mode */ + GPIO_PIN_VERY_HIGH_SPEED = 3, + /**< GPIO pin in very high speed mode */ +} gpio_speed_t; + +/** + * GPIO ouputs mode + */ +typedef enum { + GPIO_PIN_OTYPER_PP = 0, + /**< GPIO pin in Push-Pull mode */ + GPIO_PIN_OTYPER_OD = 1, + /**< GPIO pin in Open-Drain mode */ +} gpio_type_t; + + +typedef enum { + GPIO_MASK_SET_MODE = 0b000000001, + GPIO_MASK_SET_TYPE = 0b000000010, + GPIO_MASK_SET_SPEED = 0b000000100, + GPIO_MASK_SET_PUPD = 0b000001000, + GPIO_MASK_SET_BSR_R = 0b000010000, + GPIO_MASK_SET_BSR_S = 0b000100000, + GPIO_MASK_SET_LCK = 0b001000000, + GPIO_MASK_SET_AFR = 0b010000000, + GPIO_MASK_SET_EXTI = 0b100000000, + GPIO_MASK_SET_ALL = 0b111111111, +} gpio_mask_t; + + +typedef enum { + /** No EXTI line for this GPIO */ + GPIO_EXTI_TRIGGER_NONE = 0, + /** Trigger intterupt on rising edge only */ + GPIO_EXTI_TRIGGER_RISE, + /** Trigger intterupt on falling edge only */ + GPIO_EXTI_TRIGGER_FALL, + /** Trigger intterupt on both rising and falling edges */ + GPIO_EXTI_TRIGGER_BOTH +} gpio_exti_trigger_t; + +/** +** \brief This is the GPIO informational structure for user drivers +** +** A device may require GPIO configuration. If yes, +** this structure must be fullfill by the userspace but the +** configuration is done by the kernel (no direct mapping of +** the GPIO configuration registers) +*/ +typedef union { + struct { + unsigned char pin : 4; + unsigned char port : 4; + }; + unsigned char val; +} gpioref_t; + +/* GPIO ports */ +#define GPIO_PA 0 +#define GPIO_PB 1 +#define GPIO_PC 2 +#define GPIO_PD 3 +#define GPIO_PE 4 +#define GPIO_PF 5 +#define GPIO_PG 6 +#define GPIO_PH 7 +#define GPIO_PI 8 + +typedef struct { + gpio_mask_t mask; + + /**< GPIO kernel reference + * = concatenation of the GPIO port (4 bits) and the pin number (4 bits) + * + * If set at 1 before registration, the kernel will dynamicaly allocate + * a free port/pin and update kref accordingly. + * + * If set to 0 before registration, the kernel will use port & pin + * directly. GPIO port use at registration are named using 'A', 'B', ... + * up to the last GPIO port available (e.g. 'I' for STM32F4xx) + */ + gpioref_t kref; + + gpio_mode_t mode; + gpio_pupd_t pupd; + gpio_type_t type; + gpio_speed_t speed; + uint32_t afr; + uint32_t bsr_r; + uint32_t bsr_s; + uint32_t lck; + gpio_exti_trigger_t exti_trigger; + user_handler_t exti_handler; + +} dev_gpio_info_t; + +#endif diff --git a/exported/irq.h b/exported/irq.h new file mode 100644 index 0000000..c7b9136 --- /dev/null +++ b/exported/irq.h @@ -0,0 +1,165 @@ +/* \file irq.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef KERNEL_IRQ_H +#define KERNEL_IRQ_H + +/* Max number of post IRQ hooks */ +#define DEV_MAX_PH_INSTR 10 + +/** + ** \brief type of posthook the kernel can manage at interrupt time + ** before the ISR is being executed. Be carefull that this may + ** impact the device state. The kernel can give back one of the + ** registers back to the ISR using the status argument of the ISR. + */ +typedef enum { + IRQ_PH_NIL = 0, /**< No action */ + IRQ_PH_READ, /**< Read a value from a register */ + IRQ_PH_WRITE, /**< Write a value in a regiser */ + IRQ_PH_AND, /**< Read a register, apply a bitwise AND operation + ** and write the result in a register */ + IRQ_PH_MASK /**< Read a register, write it to another one, using a + ** third register as write mask */ +} dev_irq_ph_action_t; + +typedef struct { + uint16_t offset; /**< Offset of the register to read */ + uint32_t value; /**< Value read */ +} dev_irq_ph_read_t; + +/** + ** \brief when asking to write a given register, a write mask is probably + ** needed. The write table is based on write offset/write mask + */ +typedef struct { + uint16_t offset; /**< Offset of the register to write */ + uint32_t value; /**< Value to write */ + uint32_t mask; /**< Associated write mask */ +} dev_irq_ph_write_t; + +typedef struct { + uint16_t offset_dest; /**< Offset of the register to write */ + uint16_t offset_src; /**< Offset of the register with the mask */ + uint32_t mask; /**< The masking value */ + uint8_t mode; +} dev_irq_ph_and_t; + +typedef struct { + uint16_t offset_dest; /**< The offset of the register to write */ + uint16_t offset_src; /**< The offset of the register to use as value */ + uint16_t offset_mask; /**< The offset of the tregister to use as mask */ + uint8_t mode; +} dev_irq_ph_mask_t; + +#define MODE_STANDARD 0 /**< val = val */ +#define MODE_NOT 1 /**< val = ~val */ + +typedef struct { + dev_irq_ph_action_t instr; + union { + dev_irq_ph_read_t read; + dev_irq_ph_write_t write; + dev_irq_ph_and_t and; + dev_irq_ph_mask_t mask; + }; +} dev_irq_ph_instruction_t; + +/** + ** \brief this is the IRQ post-hook structure + ** This permit to declare to the kernel what can be done at IRQ time to + ** avoid IRQ burst or any other invalid behavior from devices. + */ +typedef struct { + /** The posthook identifier */ + dev_irq_ph_instruction_t action[DEV_MAX_PH_INSTR]; + + /** From which register the status is read ? */ + uint16_t status; + + /** From which register the data is read ? */ + uint16_t data; +} dev_irq_ph_t; + +/** + ** \brief Impact of the ISR on the main thread execution + */ +typedef enum { + /** ISR awakes the main tread but has no impact on scheduler policy */ + IRQ_ISR_STANDARD = 0, + /** ISR ask for a single, forced execution of its main thread */ + IRQ_ISR_FORCE_MAINTHREAD = 1, + /** ISR doesn't awake the main thread (use case without main thread or idle + ** main thread) */ + IRQ_ISR_WITHOUT_MAINTHREAD = 2, +} dev_irq_isr_scheduling_t; + +/** + * \brief This is the IRQ handler informational structure for user drivers + * + * A device may require one or more interrupt handlers. If yes, this + * structure must be fullfill for each interrupt by the userspace. + * The kernel will do the corresponding work to execute the handler + * when the corresponding IRQ rise. Yet, the handler will be executed: + * - with the user task's privileges + * - in thread mode (preemptible by HW interrupts) + * - with the corresponding device (and only this one) mapped + */ +typedef struct { + /**< The IRQ handler. Will be executed with its own stack. + * This handler will have access to the stack content (variables, + * functions, etc.) but can't modify the task's context (task's + * main thread stack or processor state). + * By now, user IRQ hanler can't execute syscalls. This is due to + * the fact that syscalls require context switch which may lead to + * the execution of another ISR, which will delete the current ISR + * stack (the physical memory of the stack is shared between ISR). + * As a consequence, any syscall will return SYS_E_DENIED. Please + * interact with your task and let it do the syscalls after instead. + * The handler address is checked. It must be own by the task. + */ + user_handler_t handler; + + /**< The IRQ number associated to the handler. + * This is the real IRQ number as if the ISR was directly executed in + * kernel mode. Yet the kernel will manage the IRQ/FIQ mode and the ISR + * will be delayed in thread mode, where it can be preempted by FIQ/IRQ. + * The IRQ number must correspond to an existing SoC device allowed by + * the kernel. + */ + uint8_t irq; + + /**< Type of post-ISR impact, see dev_irq_isr_scheduling_t description */ + dev_irq_isr_scheduling_t mode; + + /**< Most of IRQ-based devices require small actions in handler + * mode, to avoid IT burst. This posthook permit to ask the kernel + * to execute some basic action on the device registers to clean + * the interrupt or read the status registers. + * These action must be on offsets (starting at device base address) + * into the device's user-mapped address (i.e. the userspace would + * have been able to do the same in its ISR). + */ + dev_irq_ph_t posthook; +} dev_irq_info_t; + +#endif diff --git a/exported/sleep.h b/exported/sleep.h new file mode 100644 index 0000000..43c742c --- /dev/null +++ b/exported/sleep.h @@ -0,0 +1,32 @@ +/* \file sleep.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef KERNEL_SLEEP_H_ +#define KERNEL_SLEEP_H_ + +typedef enum { + SLEEP_MODE_INTERRUPTIBLE, + SLEEP_MODE_DEEP +} sleep_mode_t; + + +#endif/*!KERNEL_SLEEP_H_*/ diff --git a/exported/syscalls.h b/exported/syscalls.h new file mode 100644 index 0000000..9b51a7d --- /dev/null +++ b/exported/syscalls.h @@ -0,0 +1,146 @@ +/* \file syscalls.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _KERNEL_SYSCALLS_H_ +#define _KERNEL_SYSCALLS_H_ + +#include "autoconf.h" + +/* + * IPC broadcast magic number + */ +#define ANY_APP 0xff + +/** +** \private +** enumerate defining the syscall to execute (value in r0) +** yield: require a schedule and set task as unschedulable while no IT for it arrise +** register_irq_handler: ask to be called by the generic kernel IRQ handler for the +** corresponding IRQ +** +** register_device_access: at schedule() time, the memory region corresponding to the device +** is mapped RW for the user otherwhise, its stays unaccessible +** +** This enumerate is used by the libstd and should not be used directly by the user application +** or at its own risk. See libstd's syscall.h header for libstd kernel API. +*/ +typedef enum { + SYS_YIELD = 0, + SYS_INIT, + SYS_IPC, + SYS_CFG, + SYS_GETTICK, + SYS_RESET, + SYS_SLEEP, + SYS_LOCK +} e_syscall_type; + +/** +** \brief Definition of the INIT syscall types +*/ +typedef enum { + /** request device access */ + INIT_DEVACCESS = 0, + /** request HW DMA controlled access */ + INIT_DMA, + /** declare a DMA shared region with another task, giving it the right + to initiate a DMA transaction from or toward it */ + INIT_DMA_SHM, + /** request the identifier of another task, giving its name */ + INIT_GETTASKID, + /** finishing task init, any IPC_INIT* ipc will return DENIED */ + INIT_DONE, + /** number of INIT commands */ + INIT_MAX, +} e_init_type; + +/** +** \brief Definition of all the IPC syscall types +*/ +typedef enum { + /** Logging using kernel serial output */ + IPC_LOG = 0, + + /** Waiting data from another task (blocking syscall) */ + IPC_RECV_SYNC, + + /** Sending data to another task (executed just after), or + * return busy if the target already have an ipc content to read */ + IPC_SEND_SYNC, + + /** Read a waiting ipc content or returns SYS_E_INVAL if nothing to read */ + IPC_RECV_ASYNC, + + /** Sending data to another task (no forcing scheduling). If the target + * already have an ipc content to read, the data is lost (busy is returned) */ + IPC_SEND_ASYNC, +} e_ipc_type; + +typedef enum { + /** Set value in a GPIO previously registered and enabled */ + CFG_GPIO_SET, + + /** Get value from a GPIO previously registered and enabled */ + CFG_GPIO_GET, + + /** Reconfigure the DMA, given a new dma_t structure for one of the task's + * predeclared DMA Streams */ + CFG_DMA_RECONF, + + /** Reload a DMA Stream, given a dma_t structure with DMA Controller, Stream + * & channel identifier that is already owned by the task */ + CFG_DMA_RELOAD, + + /** Disable a DMA stream, which can be re-enable later using + * CFG_DMA_RELOAD or CFG_DMA_RECONF */ + CFG_DMA_DISABLE, + /** Map a device set as DEV_MAP_VOLUNTARY */ + CFG_DEV_MAP, + /** unmap a device set as DEV_MAP_VOLUNTARY */ + CFG_DEV_UNMAP, +} e_cfg_type; + +//[PTH] TODO: differentiate a synchronous send/recv and an asynchronous (with loss) one + +typedef enum { + PREC_MILLI = 0, /**< request for number of milliseconds since startup */ + PREC_MICRO, /**< request for number of microseconds since startup */ + PREC_CYCLE /**< request for number of CPU cycles since startup */ +} e_tick_type; + +typedef enum { + LOCK_ENTER, + LOCK_EXIT +} e_lock_type; + +/** +** \brief Syscalls return values +*/ +typedef enum { + SYS_E_DONE = 0, /**< Syscall has succesfully being executed */ + SYS_E_INVAL, /**< Invalid input data */ + SYS_E_DENIED, /**< Permission is denied */ + SYS_E_BUSY, /**< Target is busy OR not enough ressources OR ressource is already used */ + SYS_E_MAX, /**< Number of possible return values */ +} e_syscall_ret; + +#endif /*!kernel/syscalls.h */ diff --git a/exti-handler.c b/exti-handler.c new file mode 100644 index 0000000..92bf1d9 --- /dev/null +++ b/exti-handler.c @@ -0,0 +1,168 @@ +/* exti-handler.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "exti-handler.h" +#include "soc-exti.h" +#include "soc-nvic.h" +#include "tasks.h" +#include "tasks-shared.h" +#include "sched.h" +#include "isr.h" +#include "devices.h" +#include "debug.h" + +/********************************************** + * EXTI kernel handler + *********************************************/ + +/* + * This procedure is executed for each active EXTI line. + * To avoid code duplication, an inlined function is used. This + * procedure is called by the handler only for pending EXTI lines. + */ +static inline void exti_handle_line(uint8_t exti_line, + uint8_t irq, + stack_frame_t *stack_frame) +{ + gpioref_t kref; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + /* No possible typecasting from uint8_t to :4 */ + kref.pin = exti_line; +#pragma GCC diagnostic pop + + /* Clear the EXTI pending bit for this line */ + soc_exti_clear_pending(kref.pin); + + /* Get back the configured GPIO port for this line */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + /* No possible typecasting from uint8_t to :4 */ + kref.port = soc_exti_get_syscfg_exticr_port(kref.pin); +#pragma GCC diagnostic pop + + /* Get back from kernel devices list the corresponding GPIO structure + * and create a 'fake' IRQ cell as if the user ISR is directly manage the + * EXTI IRQ, in order to use the postpone ISR function. */ + dev_gpio_info_t *gpio = dev_get_gpio_from_gpio_kref(kref); + + if (!gpio) { + /* No registered GPIO found ! The EXTI IP is not properly configured. */ + NVIC_ClearPendingIRQ((uint32_t)(irq - 0x10)); + KERNLOG(DBG_ERR, "Unable to find GPIO port associated with EXTI line %d\n"); + } else { + s_irq cell = { + .irq = irq, + .irq_handler = (irq_handler_t) gpio->exti_handler, + .task_id = dev_get_task_from_gpio_kref(gpio->kref), + .count = 0 }; + /* We keep the task_frame transmission from postpone_isr... + * Remember that for IRQ lines 5 to 15, postpone_isr may be called more + * that one time in the same handler + */ + stack_frame = postpone_isr(irq, &cell, stack_frame); + } +} + +/* + * Why a specific handler for EXTI ? + * This is required to get back the GPIO pin/port couple from the EXTI + * line. This may be complex when the EXTI line is multiplexed + * (case if lines 5->15). + * This handler: + * 1) get back the IRQ number + * 2) If this is a multiplexed IRQ, get back the effective + * associated EXTI line(s) (more than one can be pending in the same time) + * 3) For each of theses lines, get back the corresponding registered GPIO + * and associated task + * 4) We call postpone_isr directly, creating a custom IRQ cell, as final ISR + * are effective user ISRs. + * + * We do not use postpone_isr here because there is no bijection between + * IRQ and ISR handlers (due to EXTI lines multiplexing). As a consequence, + * a signe IRQ may lead to multiple GPIO lines for multiple tasks. + */ +stack_frame_t *exti_handler(stack_frame_t * stack_frame) +{ + uint8_t int_num; + uint32_t pending_lines = 0; + + /* + * It's sad to get back again the IRQ here, but as a generic kernel + * IRQ handler, the IRQ number is not passed as first argument + * Only postpone_isr get it back. + * TODO: give irq as first argument of *all* handler ? + */ + interrupt_get_num(int_num); + int_num &= 0x1ff; + + switch (int_num) { + /* EXTI0: pin 0 */ + case EXTI0_IRQ: { + exti_handle_line(0, int_num, stack_frame); + break; + } + /* EXTI0: pin 1 */ + case EXTI1_IRQ: { + exti_handle_line(1, int_num, stack_frame); + break; + } + /* EXTI0: pin 2 */ + case EXTI2_IRQ: { + exti_handle_line(2, int_num, stack_frame); + break; + } + /* EXTI0: pin 3 */ + case EXTI3_IRQ: { + exti_handle_line(3, int_num, stack_frame); + break; + } + /* EXTI0: pin 4 */ + case EXTI4_IRQ: { + exti_handle_line(4, int_num, stack_frame); + break; + } + /* EXTI0: pin 5 to 9 */ + case EXTI9_5_IRQ: { + pending_lines = soc_exti_get_pending_lines(int_num); + for (uint8_t i = 0; i < 5; ++i) { + if (pending_lines & (uint32_t)(0x1 << i)) { + exti_handle_line((uint8_t)(5 + i), int_num, stack_frame); + } + } + break; + } + /* EXTI0: pin 10 to 15 */ + case EXTI15_10_IRQ: + pending_lines = soc_exti_get_pending_lines(int_num); + for (uint8_t i = 0; i < 6; ++i) { + if (pending_lines & (uint32_t)(0x1 << i)) { + exti_handle_line((uint8_t)(10 + i), int_num, stack_frame); + } + } + break; + } + return stack_frame; +} + diff --git a/exti-handler.h b/exti-handler.h new file mode 100644 index 0000000..31fa0a2 --- /dev/null +++ b/exti-handler.h @@ -0,0 +1,49 @@ +/* \file exti-handler.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef EXTI_HANDLER_H_ +#define EXTI_HANDLER_H_ + +#include "tasks.h" + +/*! + * Why a specific handler for EXTI ? + * This is required to get back the GPIO pin/port couple from the EXTI + * line. This may be complex when the EXTI line is multiplexed + * (case if lines 5->15). + * This handler: + * 1) get back the IRQ number + * 2) If this is a multiplexed IRQ, get back the effective + * associated EXTI line(s) (more than one can be pending in the same time) + * 3) For each of theses lines, get back the corresponding registered GPIO + * and associated task + * 4) We call postpone_isr directly, creating a custom IRQ cell, as final ISR + * are effective user ISRs. + * + * We do not use postpone_isr here because there is no bijection between + * IRQ and ISR handlers (due to EXTI lines multiplexing). As a consequence, + * a signe IRQ may lead to multiple GPIO lines for multiple tasks. + */ +stack_frame_t *exti_handler(stack_frame_t * stack_frame); + +#endif/*!EXTI_HANDLER_H_*/ diff --git a/exti.c b/exti.c new file mode 100644 index 0000000..1e630da --- /dev/null +++ b/exti.c @@ -0,0 +1,82 @@ +/* \file exti.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "exti.h" +#include "exti-handler.h" +#include "tasks.h" +#include "sched.h" +#include "devices.h" +#include "soc-exti.h" +#include "tasks-shared.h" +#include "debug.h" + + +/********************************************** + * EXTI kernel utility functions + *********************************************/ + +/* + * Register a new EXTI line. This checks that the EXTI line is not + * already registered. + */ +uint8_t exti_register_exti(dev_gpio_info_t *gpio) +{ + return soc_exti_config(gpio); +} + +/* + * Enable (i.e. activate at EXTI and NVIC level) the EXTI line. + * This is done by calling soc_exti_enable() only. No generic call here. + */ +uint8_t exti_enable(gpioref_t kref) +{ + soc_exti_enable(kref); + return 0; +} + + +/** + * \brief disable a given line + * + * \returns 0 of EXTI line has been properly disabled, or non-null value + */ +uint8_t exti_disable(gpioref_t kref) +{ + soc_exti_disable(kref); + return 0; +} + +void exti_init(void) +{ + /* + * Registering kernel handler for EXTI + */ + set_interrupt_handler(EXTI0_IRQ, exti_handler, 0, ID_DEV_UNUSED); + set_interrupt_handler(EXTI1_IRQ, exti_handler, 0, ID_DEV_UNUSED); + set_interrupt_handler(EXTI2_IRQ, exti_handler, 0, ID_DEV_UNUSED); + set_interrupt_handler(EXTI3_IRQ, exti_handler, 0, ID_DEV_UNUSED); + set_interrupt_handler(EXTI4_IRQ, exti_handler, 0, ID_DEV_UNUSED); + set_interrupt_handler(EXTI9_5_IRQ, exti_handler, 0, ID_DEV_UNUSED); + set_interrupt_handler(EXTI15_10_IRQ, exti_handler, 0, ID_DEV_UNUSED); + soc_exti_init(); +} diff --git a/exti.h b/exti.h new file mode 100644 index 0000000..3594c53 --- /dev/null +++ b/exti.h @@ -0,0 +1,38 @@ +/* \file exti.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef EXTI_H_ +#define EXTI_H_ + +#include "gpio.h" +#include "types.h" + +void exti_init(void); + +uint8_t exti_disable(gpioref_t kref); + +uint8_t exti_enable(gpioref_t kref); + +uint8_t exti_register_exti(dev_gpio_info_t *gpio); + +#endif /*! EXTI_H_*/ diff --git a/generated/.placehorder b/generated/.placehorder new file mode 100644 index 0000000..e69de29 diff --git a/gnatprep.def b/gnatprep.def new file mode 100644 index 0000000..54bc315 --- /dev/null +++ b/gnatprep.def @@ -0,0 +1 @@ +* "config.def" -u -c diff --git a/gpio.c b/gpio.c new file mode 100644 index 0000000..59341d9 --- /dev/null +++ b/gpio.c @@ -0,0 +1,281 @@ +/* gpio.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "gpio.h" +#include "tasks.h" +#include "debug.h" + +/* + * Table of current GPIO state, set to 0x1 when the GPIO is used by a driver + * Its position in the table define its number (port/pin) + * GPIO pin number and naming is generic. The number of ports varies, which makes + * only gpios_max_num differs depending on the SoC. + */ +uint8_t gpio_state[] = { + 0x0, /* GPIOA pin 0 */ + 0x0, /* GPIOA pin 1 */ + 0x0, /* GPIOA pin 2, USART2 */ + 0x0, /* GPIOA pin 3, USART2 */ + 0x0, /* GPIOA pin 4 */ + 0x0, /* GPIOA pin 5 */ + 0x0, /* GPIOA pin 6 */ + 0x0, /* GPIOA pin 7 */ + 0x0, /* GPIOA pin 8 */ + 0x0, /* GPIOA pin 9 */ + 0x0, /* GPIOA pin a */ + 0x0, /* GPIOA pin b */ + 0x0, /* GPIOA pin c */ + 0x0, /* GPIOA pin d */ + 0x0, /* GPIOA pin e */ + 0x0, /* GPIOA pin f */ + /**/ + 0x0, /* GPIOB pin 0 */ + 0x0, /* GPIOB pin 1 */ + 0x0, /* GPIOB pin 2 */ + 0x0, /* GPIOB pin 3 */ + 0x0, /* GPIOB pin 4 */ + 0x0, /* GPIOB pin 5 */ + 0x0, /* GPIOB pin 6, USART1*/ + 0x0, /* GPIOB pin 7, USART1 */ + 0x0, /* GPIOB pin 8 */ + 0x0, /* GPIOB pin 9 */ + 0x0, /* GPIOB pin a, USART3 */ + 0x0, /* GPIOB pin b, USART3 */ + 0x0, /* GPIOB pin c */ + 0x0, /* GPIOB pin d */ + 0x0, /* GPIOB pin e */ + 0x0, /* GPIOB pin f */ + /**/ + 0x0, /* GPIOC pin 0 */ + 0x0, /* GPIOC pin 1 */ + 0x0, /* GPIOC pin 2, USART5 */ + 0x0, /* GPIOC pin 3 */ + 0x0, /* GPIOC pin 4 */ + 0x0, /* GPIOC pin 5 */ + 0x0, /* GPIOC pin 6, USART6 */ + 0x0, /* GPIOC pin 7, USART6 */ + 0x0, /* GPIOC pin 8 */ + 0x0, /* GPIOC pin 9 */ + 0x0, /* GPIOC pin a, USART4 */ + 0x0, /* GPIOC pin b, USART4 */ + 0x0, /* GPIOC pin c, USART5 */ + 0x0, /* GPIOC pin d */ + 0x0, /* GPIOC pin e */ + 0x0, /* GPIOC pin f */ + /**/ + 0x0, /* GPIOD pin 0 */ + 0x0, /* GPIOD pin 1 */ + 0x0, /* GPIOD pin 2 */ + 0x0, /* GPIOD pin 3 */ + 0x0, /* GPIOD pin 4 */ + 0x0, /* GPIOD pin 5 */ + 0x0, /* GPIOD pin 6 */ + 0x0, /* GPIOD pin 7 */ + 0x0, /* GPIOD pin 8 */ + 0x0, /* GPIOD pin 9 */ + 0x0, /* GPIOD pin a */ + 0x0, /* GPIOD pin b */ + 0x0, /* GPIOD pin c */ + 0x0, /* GPIOD pin d */ + 0x0, /* GPIOD pin e */ + 0x0, /* GPIOD pin f */ + /**/ + 0x0, /* GPIOE pin 0 */ + 0x0, /* GPIOE pin 1 */ + 0x0, /* GPIOE pin 2 */ + 0x0, /* GPIOE pin 3 */ + 0x0, /* GPIOE pin 4 */ + 0x0, /* GPIOE pin 5 */ + 0x0, /* GPIOE pin 6 */ + 0x0, /* GPIOE pin 7 */ + 0x0, /* GPIOE pin 8 */ + 0x0, /* GPIOE pin 9 */ + 0x0, /* GPIOE pin a */ + 0x0, /* GPIOE pin b */ + 0x0, /* GPIOE pin c */ + 0x0, /* GPIOE pin d */ + 0x0, /* GPIOE pin e */ + 0x0, /* GPIOE pin f */ + /**/ + 0x0, /* GPIOF pin 0 */ + 0x0, /* GPIOF pin 1 */ + 0x0, /* GPIOF pin 2 */ + 0x0, /* GPIOF pin 3 */ + 0x0, /* GPIOF pin 4 */ + 0x0, /* GPIOF pin 5 */ + 0x0, /* GPIOF pin 6 */ + 0x0, /* GPIOF pin 7 */ + 0x0, /* GPIOF pin 8 */ + 0x0, /* GPIOF pin 9 */ + 0x0, /* GPIOF pin a */ + 0x0, /* GPIOF pin b */ + 0x0, /* GPIOF pin c */ + 0x0, /* GPIOF pin d */ + 0x0, /* GPIOF pin e */ + 0x0, /* GPIOF pin f */ + /**/ + 0x0, /* GPIOG pin 0 */ + 0x0, /* GPIOG pin 1 */ + 0x0, /* GPIOG pin 2 */ + 0x0, /* GPIOG pin 3 */ + 0x0, /* GPIOG pin 4 */ + 0x0, /* GPIOG pin 5 */ + 0x0, /* GPIOG pin 6 */ + 0x0, /* GPIOG pin 7 */ + 0x0, /* GPIOG pin 8 */ + 0x0, /* GPIOG pin 9 */ + 0x0, /* GPIOG pin a */ + 0x0, /* GPIOG pin b */ + 0x0, /* GPIOG pin c */ + 0x0, /* GPIOG pin d */ + 0x0, /* GPIOG pin e */ + 0x0, /* GPIOG pin f */ + /**/ + 0x0, /* GPIOH pin 0 */ + 0x0, /* GPIOH pin 1 */ + 0x0, /* GPIOH pin 2 */ + 0x0, /* GPIOH pin 3 */ + 0x0, /* GPIOH pin 4 */ + 0x0, /* GPIOH pin 5 */ + 0x0, /* GPIOH pin 6 */ + 0x0, /* GPIOH pin 7 */ + 0x0, /* GPIOH pin 8 */ + 0x0, /* GPIOH pin 9 */ + 0x0, /* GPIOH pin a */ + 0x0, /* GPIOH pin b */ + 0x0, /* GPIOH pin c */ + 0x0, /* GPIOH pin d */ + 0x0, /* GPIOH pin e */ + 0x0, /* GPIOH pin f */ + /**/ + 0x0, /* GPIOI pin 0 */ + 0x0, /* GPIOI pin 1 */ + 0x0, /* GPIOI pin 2 */ + 0x0, /* GPIOI pin 3 */ + 0x0, /* GPIOI pin 4 */ + 0x0, /* GPIOI pin 5 */ + 0x0, /* GPIOI pin 6 */ + 0x0, /* GPIOI pin 7 */ + 0x0, /* GPIOI pin 8 */ + 0x0, /* GPIOI pin 9 */ + 0x0, /* GPIOI pin a */ + 0x0, /* GPIOI pin b */ + 0x0, /* GPIOI pin c */ + 0x0, /* GPIOI pin d */ + 0x0, /* GPIOI pin e */ + 0x0, /* GPIOI pin f */ +}; + +uint8_t gpio_max_num = sizeof(gpio_state) / sizeof(uint8_t); + + +/** + * \brief Check if the GPIO is already used or not + * + * \param[in] gpio GPIO identifier, corresponding to the gpio structure + * kref field + * \return true if the GPIO is free to use, false if the GPIO is already used. + */ +static bool gpio_is_free(gpioref_t kref) +{ + if (kref.val < gpio_max_num && gpio_state[kref.val] == 0x0) { + return true; + } + return false; +} + +/** + * \brief register the GPIO identified by the gpio param + * This function only set the given GPIO as used, making future + * call to gpio_is_free() returning false. + * + * \param[in] gpio GPIO identifier, corresponding to the gpio structure + * kref field + * + * \return nothing, the gpio is reserved. This function doesn't check + */ +uint8_t gpio_register_gpio + (e_task_id task_id, e_device_id dev_id, const dev_gpio_info_t * gpio) +{ + task_id = task_id; + dev_id = dev_id; + + if (!gpio_is_free(gpio->kref)) { + KERNLOG(DBG_ERR, "Given gpio %x is already used!\n", gpio->kref.val); + return 1; + } + + gpio_state[gpio->kref.val] = 1; + return 0; +} + +/** + * \brief Enable (configure) the GPIO + * + * This function also activate the RCC line of the GPIO before its + * configuration. + * + * \param[in] the gpio structure associated to the GPIO + * + * \return 0 if configuration has finished successfully, or non-zero value + */ +uint8_t gpio_enable_gpio(const dev_gpio_info_t * gpio) +{ +#if CONFIG_DEBUG > 2 + KERNLOG("enabled GPIO port %c, pin %x\n", gpio->kref.port, + gpio->kref.pin); +#endif + return soc_gpio_set_config(gpio); +} + +/************************************************** + * Prototypes for nominal phase + *************************************************/ + +/** + * \brief set the value val in the GPIO identified by the first argument + * + * The GPIO must be in output mode. The value is normalized in this function. + * + * \param[in] gpio the gpio structure identifying the GPIO + * \param[in] val the value used to set the GPIO + */ +void gpio_set_value(gpioref_t kref, uint8_t val) +{ + soc_gpio_set_value(kref, val); +} + +/** + * \brief get the value of the GPIO identified by the first argument + * + * The GPIO must be in input mode. The value is normalized in this function. + * + * \param[in] gpio the gpio structure identifying the GPIO + * + * \return the value read in the GPIO input value register. + */ +uint8_t gpio_get_value(gpioref_t kref) +{ + return soc_gpio_get(kref); +} + diff --git a/gpio.h b/gpio.h new file mode 100644 index 0000000..5e57653 --- /dev/null +++ b/gpio.h @@ -0,0 +1,86 @@ +/* \file gpio.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef KERN_GPIO_ +#define KERN_GPIO_ + +#include "types.h" +#include "kernel.h" +#include "exported/devices.h" +#include "soc-gpio.h" + +/*********************************************** + * Prototypes for initialization phase + **********************************************/ + +/** + * \brief register the GPIO identified by the gpio param + * This function only set the given GPIO as used, making future + * call to gpio_is_free() returning false. + * + * \param[in] gpio GPIO identifier, corresponding to the gpio structure + * kref field + * + * \return 0 on success + */ +uint8_t gpio_register_gpio + (e_task_id task_id, e_device_id dev_id, const dev_gpio_info_t * gpio); + +/** + * \brief Enable (configure) the GPIO + * + * This function also activate the RCC line of the GPIO before its + * configuration. + * + * \param[in] the gpio structure associated to the GPIO + * + * \return 0 if configuration has finished successfully, or non-zero value + */ +uint8_t gpio_enable_gpio(const dev_gpio_info_t * gpio); + +/************************************************** + * Prototypes for nominal phase + *************************************************/ + +/** + * \brief set the value val in the GPIO identified by the first argument + * + * The GPIO must be in output mode. The value is normalized in this function. + * + * \param[in] gpio the gpio structure identifying the GPIO + * \param[in] val the value used to set the GPIO + */ +void gpio_set_value(gpioref_t kref, uint8_t val); + +/** + * \brief get the value of the GPIO identified by the first argument + * + * The GPIO must be in input mode. The value is normalized in this function. + * + * \param[in] gpio the gpio structure identifying the GPIO + * + * \return the value read in the GPIO input value register. + */ +uint8_t gpio_get_value(gpioref_t kref); + +#endif /*!KERN_GPIO_ */ diff --git a/init.c b/init.c new file mode 100644 index 0000000..1443cb8 --- /dev/null +++ b/init.c @@ -0,0 +1,231 @@ +/* \file init.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * @file main.c + * + * EwoK kernel main + * + */ + +#include "autoconf.h" +#include "debug.h" + +#ifdef CONFIG_ARCH_CORTEX_M4 +#include "m4-systick.h" +#else +#error "no systick support for other by now!" +#endif + +#include "tasks.h" +#include "soc-init.h" +#include "soc-usart.h" +#include "soc-usart-regs.h" +#include "soc-layout.h" +#include "soc-interrupts.h" +#include "soc-flash.h" +#include "soc-rng.h" +#include "stack_check.h" +#include "m4-cpu.h" +#include "product.h" + +#ifdef CONFIG_FPU_ENABLE +#include "m4-fpu.h" +#endif +#include "soc-dwt.h" + +#include "m4-core.h" +#include "shared.h" +#include "buttons.h" +#include "mpu.h" +#include "kernel.h" +#include "sched.h" +#include "devices.h" +#include "processor.h" +#include "softirq.h" +#include "syscalls.h" +#include "dma.h" +#include "exti.h" +#include "usart.h" + +#define r_CORTEX_M_NVIC_ICER0 REG_ADDR(NVIC_BASE + (uint32_t)0x80) +#define NVIC_ICER r_CORTEX_M_NVIC_ICER0 + + +/* + ok. I'm the kernel. This information is passed to some arch specific code of the BSP + that is kernel specific (not generic with the loader) +*/ + +/* +** Shared vars are hosted in the SHR section, out of the firmware. This is used by +** the firmwares, the DFUs and the loader to communicate with each-others, to manage the +** Wookey firmware and DFU update +*/ +extern const shr_vars_t shared_vars; + +#ifdef CONFIG_ADAKERNEL + /* Specific Ada runtime elaboration code */ +extern void kernelinit(void); +extern void interrupts_init(void); +#endif + +#define YELLOW "\x1b[1;33;40m" +#define WHITE "\x1b[0;37;40m" + +/* + * We use the local -fno-stack-protector flag for main because + * the stack protection has not been initialized yet. + */ +__attribute__ ((optimize("-fno-stack-protector"))) +int main(int argc, char *args[]) +{ + char *base_address = 0; + + disable_irq(); + +#ifdef CONFIG_ADAKERNEL + /* Specific Ada runtime elaboration code */ + kernelinit(); + interrupts_init(); +#endif + + /* Configure the USART in UART mode, this is the kernel console initialization */ + debug_console_init(); + dbg_log(YELLOW "EWOK - Embedded lightWeight Opensource Kernel" WHITE "\n\n"); + dbg_flush(); + + KERNLOG(DBG_INFO, "booting...\n"); + + /* + * Initialization of DWT. This is required for time measurement + * (required for sys_get_systick()). + */ + soc_dwt_init(); + +#ifdef CONFIG_KERNEL_DMA_ENABLE + /* + * EwoK can be configured without DMA support. If DMA is supported, the DMA kernel + * vector is initialized here + */ + dma_init(); +#endif + +#ifdef CONFIG_FPU_ENABLE + /* + * If the FPU is supported, the FPU is configured and the associated IRQ handler + * is registered here + */ + fpu_enable(); +#endif + + /* + * Initialize the EXTI support. This is required for IT-triggered GPIOs + */ + exti_init(); + + /* + * The kernel is a PIE executable. Its base address is given in first argument, + * based on the loader informations + */ + if (argc == 1) { + base_address = (char *)args[0]; + system_init((uint32_t) base_address - VTORS_SIZE); + } else { + panic("Unable to get base address to support PIE"); + } + + /* + * Let's print the first informational data on USART. Kernel remains silent when + * DEBUG is set to 0 + */ + +#if CONFIG_DEBUG > 0 + /* debug mode, uart support is a kernel function, otherwise, it is a userspace app */ + KERNLOG(DBG_INFO, "Built date: %s at %s\n", __DATE__, __TIME__); +#ifdef CONFIG_STM32F4 + KERNLOG(DBG_INFO, "Board: STM32F429\n"); +#else + KERNLOG(DBG_INFO, "Board: STM32F407\n"); +#endif + KERNLOG(DBG_INFO, "==============================\n"); +#endif + + /* + * Initialize the stack protection, based on the hardware RNG device + */ + init_stack_chk_guard(); + + /* + * Let's configure the MPU. This is the most imortant part of the early kernel init. + * After this sequence, the kernel is executed with the MPU activated and can generate + * memory fault in case of invalid access. + */ + if (mpu_kernel_init()) { + ERROR("MPU Configuration failed !\n"); + dbg_flush(); + panic("MPU fail, stopping.\n"); + } + full_memory_barrier(); + + /* create user tasks, each one has its init fn executed + * (this function register all interrupts and devices accesses using syscalls, + * associated devices are also initialized by this function after having registered irq/dev) + */ + task_init(); + + /* Initialize devices vector */ + dev_init(); + + /* Initialize kernel devices (usart, led,...) */ + usart_init(); + + /* Initialize softirq ring buffer and globals */ + softirq_init(); + + /* + * The kernel has finished its initialization, the first thread can now be executed + */ + KERNLOG(DBG_INFO, "==============================\n"); + + /* + * Now that the kernel has finished to initialized tasks context, let's update + * the systick handler to execute the sheduler + */ + + /* + * scheduling initialization (registering of PendSV and Systick handlers, initialization + * and sched subsystem and execution of the first thread) is done now. + * The first thread is IDLE. It will wait for any interrupt, waiting for the first systick + * which will generate the first effective scheduling. + */ + sched_init(); + + /* + * There is no more kernel thread after this point. sched_init never returns. Any execution + * of the bellowing lines is an abnormal event. + */ + panic("Why am I here ?\n"); + + return 0; +} diff --git a/ipc.c b/ipc.c new file mode 100644 index 0000000..10fc58a --- /dev/null +++ b/ipc.c @@ -0,0 +1,63 @@ +/* \file ipc.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "ipc.h" +#include "tasks.h" + +void ipc_init_endpoint (ipc_endpoint_t *ep) +{ + ep->from = ID_UNUSED; + ep->to = ID_UNUSED; + ep->state = FREE; + ep->size = 0; + for (int i=0; idata[i] = 0; + } +} + +void ipc_init_endpoints (void) +{ + for (int i=0; i + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef IPC_H_ +#define IPC_H_ + +#include "types.h" +#include "tasks-shared.h" + +#define MAX_IPC_ENDPOINTS 10 +#define ANY_APP 0xff +#define MAX_IPC_MSG 128 + + +typedef enum { + /* IPC endpoint is unused */ + FREE, + /* IPC endpoint is used and is ready for message passing */ + READY, + /* send() block until the receiver read the message */ + WAIT_FOR_RECEIVER +} ipc_endpoint_state_t; + + +typedef struct { + e_task_id from; /* sender id */ + e_task_id to; /* receiver id */ + ipc_endpoint_state_t state; + char data[MAX_IPC_MSG]; + logsize_t size; /* Must be < MAX_IPC_MSG */ +} ipc_endpoint_t; + +/* Global array of IPC EndPoints */ +ipc_endpoint_t ipc_endpoints[MAX_IPC_ENDPOINTS]; + +/* Init IPC endpoints */ +void ipc_init_endpoints (void); + +/* Get a free IPC endpoint */ +ipc_endpoint_t* ipc_get_endpoint (void); + +/* Release a used IPC endpoint */ +void ipc_release_endpoint (ipc_endpoint_t *ep); + + + +#endif /*! IPC_H_ */ diff --git a/isr.c b/isr.c new file mode 100644 index 0000000..38a3cd2 --- /dev/null +++ b/isr.c @@ -0,0 +1,88 @@ +/* isr.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "soc-nvic.h" +#include "soc-interrupts.h" +#include "soc-dma.h" +#include "dma.h" +#include "softirq.h" +#include "posthook.h" +#include "tasks.h" +#include "debug.h" +#include "sched.h" + +/* +** Replace the weak implementation of libbsp +** this function postpone the ISR execution in softirq context +*/ +stack_frame_t *postpone_isr + (uint8_t irq, s_irq *cell, stack_frame_t * stack_frame) +{ + /* Status and data register to push to ISR as argument, if needed */ + uint32_t regs[2] = { 0 }; + + task_t* caller; + + caller = task_get_task (cell->task_id); + if (caller == NULL) { + panic("postpone_isr(): invalid task id %d\n", cell->task_id); + } + + /* + * If current ISR is handled by kernel, just execute it + * and go back to work without requesting schedule + */ + if (caller->type == TASK_TYPE_KERNEL) { + cell->irq_handler(stack_frame); + return stack_frame; + } + + /* + * Acknowledge interrupt: + * - Timer and DMA are managed by the kernel + * - Devices managed by user tasks should use the posthook mechanism + * to acknowledge interrupt in order to avoid bursts. + */ +#if defined(CONFIG_KERNEL_DMA_ENABLE) + else if (soc_is_dma_irq(irq)) { + regs[0] = dma_get_status(cell->task_id, irq); + dma_clean_int(cell->task_id, irq); // clear SR register + } +#endif + else { + /* Post-hook */ + int_posthook_exec(irq, regs); + } + + /* + * All user ISR have their Pending IRQ bit clean here + * SR is cleaned by softirq user ISR handler + */ + NVIC_ClearPendingIRQ((uint32_t)(irq - 0x10)); + + softirq_query(SFQ_USR_ISR, cell->task_id, cell->irq, + (physaddr_t) cell->irq_handler, regs); + + return stack_frame; +} + diff --git a/isr.h b/isr.h new file mode 100644 index 0000000..cdb3222 --- /dev/null +++ b/isr.h @@ -0,0 +1,16 @@ +/* isr.h + * + * Copyright (C) 2018 ANSSI + * All rights reserved. + * + * This software may be modified and distributed under the terms + * of the BSD license. See the LICENSE file for details. + */ + +#ifndef SOC_ISR_ +#define SOC_ISR_ + +stack_frame_t *postpone_isr + (uint8_t irq, s_irq *cell, stack_frame_t * stack_frame); + +#endif diff --git a/kernel.dfu1.ld.in b/kernel.dfu1.ld.in new file mode 100644 index 0000000..4cb27ea --- /dev/null +++ b/kernel.dfu1.ld.in @@ -0,0 +1,107 @@ +/* fwx.ld */ + +INCLUDE BUILDDIR/layout.ld + +_estack = _kern_init_msp_stack; + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + }>DFU1_KERN + + /* The program code and other data goes into FLASH */ + .text : + { + _stext = .; /* create a global symbol at data start */ + *startup*(.text.Reset_Handler) + *(.text*) + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + _exit = .; + }>DFU1_KERN + + /* used by the startup to initialize got */ + _sigot = .; + .got : AT ( _sigot ) { + . = ALIGN(4); + _sgot = .; + /* *(.got.plt) + * We don't need plt segment + * since we do not need dynamic library relocation + */ + *(.got) + *(.got*) + . = ALIGN(4); + _egot = .; + }>DFU1_KERN + /* used by the startup to initialize data */ + _sidata = .; + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + _edata = .; /* define a global symbol at data end */ + }>RAM_KERN + + /* Shared variables */ + .shared : { + . = ALIGN(4); + KEEP(*(.shared)) ; + }>SHR + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *debug.o(.bss) + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + }>RAM_KERN + + /* heap_stack section, used to check that there is enough RAM left */ + ._heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + 4096; /* kernel idle thread stack */ + . = . + 4096; /* kernel initial thread stack */ + . = . + 8192; /* softirq thread stack */ + . = . + 4096; /* user ISR stack (remapped region) */ + . = ALIGN(4); + }>RAM_KERN + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libgcc.a ( * ) + } + +} diff --git a/kernel.dfu2.ld.in b/kernel.dfu2.ld.in new file mode 100644 index 0000000..4128816 --- /dev/null +++ b/kernel.dfu2.ld.in @@ -0,0 +1,107 @@ +/* fwx.ld */ + +INCLUDE BUILDDIR/layout.ld + +_estack = _kern_init_msp_stack; + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + }>DFU2_KERN + + /* The program code and other data goes into FLASH */ + .text : + { + _stext = .; /* create a global symbol at data start */ + *startup*(.text.Reset_Handler) + *(.text*) + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + _exit = .; + }>DFU2_KERN + + /* used by the startup to initialize got */ + _sigot = .; + .got : AT ( _sigot ) { + . = ALIGN(4); + _sgot = .; + /* *(.got.plt) + * We don't need plt segment + * since we do not need dynamic library relocation + */ + *(.got) + *(.got*) + . = ALIGN(4); + _egot = .; + }>DFU2_KERN + /* used by the startup to initialize data */ + _sidata = .; + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + _edata = .; /* define a global symbol at data end */ + }>RAM_KERN + + /* Shared variables */ + .shared : { + . = ALIGN(4); + KEEP(*(.shared)) ; + }>SHR + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *debug.o(.bss) + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + }>RAM_KERN + + /* heap_stack section, used to check that there is enough RAM left */ + ._heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + 4096; /* kernel idle thread stack */ + . = . + 4096; /* kernel initial thread stack */ + . = . + 8192; /* softirq thread stack */ + . = . + 4096; /* user ISR stack (remapped region) */ + . = ALIGN(4); + }>RAM_KERN + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libgcc.a ( * ) + } + +} diff --git a/kernel.fw1.ld.in b/kernel.fw1.ld.in new file mode 100644 index 0000000..1433f68 --- /dev/null +++ b/kernel.fw1.ld.in @@ -0,0 +1,107 @@ +/* fwx.ld */ + +INCLUDE BUILDDIR/layout.ld + +_estack = _kern_init_msp_stack; + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + }>FW1_KERN + + /* The program code and other data goes into FLASH */ + .text : + { + _stext = .; /* create a global symbol at data start */ + *startup*(.text.Reset_Handler) + *(.text*) + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + _exit = .; + }>FW1_KERN + + /* used by the startup to initialize got */ + _sigot = .; + .got : AT ( _sigot ) { + . = ALIGN(4); + _sgot = .; + /* *(.got.plt) + * We don't need plt segment + * since we do not need dynamic library relocation + */ + *(.got) + *(.got*) + . = ALIGN(4); + _egot = .; + }>FW1_KERN + /* used by the startup to initialize data */ + _sidata = .; + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + _edata = .; /* define a global symbol at data end */ + }>RAM_KERN + + /* Shared variables */ + .shared : { + . = ALIGN(4); + KEEP(*(.shared)) ; + }>SHR + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *debug.o(.bss) + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + }>RAM_KERN + + /* heap_stack section, used to check that there is enough RAM left */ + ._heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + 4096; /* kernel idle thread stack */ + . = . + 4096; /* kernel initial thread stack */ + . = . + 8192; /* softirq thread stack */ + . = . + 4096; /* user ISR stack (remapped region) */ + . = ALIGN(4); + }>RAM_KERN + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libgcc.a ( * ) + } + +} diff --git a/kernel.fw2.ld.in b/kernel.fw2.ld.in new file mode 100644 index 0000000..6777c3d --- /dev/null +++ b/kernel.fw2.ld.in @@ -0,0 +1,107 @@ +/* fwx.ld */ + +INCLUDE BUILDDIR/layout.ld + +_estack = _kern_init_msp_stack; + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + }>FW2_KERN + + /* The program code and other data goes into FLASH */ + .text : + { + _stext = .; /* create a global symbol at data start */ + *startup*(.text.Reset_Handler) + *(.text*) + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + _exit = .; + }>FW2_KERN + + /* used by the startup to initialize got */ + _sigot = .; + .got : AT ( _sigot ) { + . = ALIGN(4); + _sgot = .; + /* *(.got.plt) + * We don't need plt segment + * since we do not need dynamic library relocation + */ + *(.got) + *(.got*) + . = ALIGN(4); + _egot = .; + }>FW2_KERN + /* used by the startup to initialize data */ + _sidata = .; + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + _edata = .; /* define a global symbol at data end */ + }>RAM_KERN + + /* Shared variables */ + .shared : { + . = ALIGN(4); + KEEP(*(.shared)) ; + }>SHR + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *debug.o(.bss) + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + }>RAM_KERN + + /* heap_stack section, used to check that there is enough RAM left */ + ._heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + 4096; /* kernel idle thread stack */ + . = . + 4096; /* kernel initial thread stack */ + . = . + 8192; /* softirq thread stack */ + . = . + 4096; /* user ISR stack (remapped region) */ + . = ALIGN(4); + }>RAM_KERN + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libgcc.a ( * ) + } + +} diff --git a/kernel.h b/kernel.h new file mode 100644 index 0000000..47e4f3d --- /dev/null +++ b/kernel.h @@ -0,0 +1,54 @@ +/* \file kernel.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef KERNEL_H +#define KERNEL_H + +#include "types.h" +#include "m4-systick.h" + +/* global kernel defines */ + +#define __KERNEL + +#define ANSI_COLOR_BLUE "\x1b[37;44m" +#define ANSI_COLOR_RED "\x1b[37;41m" +#define ANSI_COLOR_RESET "\x1b[37;40m" + +#define KERNLOG(level, fmt, ...) \ + if (level <= DBG_ERR) { \ + DEBUG(level, ANSI_COLOR_RED "[%ld] kernel: " fmt ANSI_COLOR_RESET, (unsigned long) core_systick_get_ticks(), ##__VA_ARGS__); \ + } else { \ + DEBUG(level, ANSI_COLOR_BLUE "[%ld] kernel: " fmt ANSI_COLOR_RESET, (unsigned long) core_systick_get_ticks(), ##__VA_ARGS__); \ + } + +/* for visibility purpose, to mark all userspace variable in kernel code */ +#define __user + +/* kernel specific types */ +typedef physaddr_t *stackaddr_t; /* stack @ */ +typedef uint16_t reghval_t; /* register high-half value */ +typedef uint16_t reglval_t; /* register low-half value */ +typedef uint32_t regval_t; /* register value */ + +#endif /*!KERNEL_H */ diff --git a/kernel.ld.in b/kernel.ld.in new file mode 120000 index 0000000..89c619d --- /dev/null +++ b/kernel.ld.in @@ -0,0 +1 @@ +kernel.fw1.ld.in \ No newline at end of file diff --git a/layout.h b/layout.h new file mode 100644 index 0000000..39bfc79 --- /dev/null +++ b/layout.h @@ -0,0 +1,46 @@ +/* \file layout.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef LAYOUT_H_ +#define LAYOUT_H_ + +#include "soc-layout.h" +#include "types.h" + + +#define STACK_TOP_IDLE RAM_KERN_BASE + RAM_KERN_SIZE +#define STACK_SIZE_IDLE 4*KBYTE + +#define STACK_TOP_SOFTIRQ RAM_KERN_BASE + RAM_KERN_SIZE - (4*KBYTE) +#define STACK_SIZE_SOFTIRQ 8*KBYTE + +#define STACK_TOP_ISR RAM_KERN_BASE + RAM_KERN_SIZE - (12*KBYTE) +#define STACK_SIZE_ISR 4*KBYTE + +static inline bool frame_is_kernel(physaddr_t frame) { + if (frame < STACK_TOP_IDLE && frame > STACK_TOP_ISR) { + return true; + } + return false; +} + +#endif /*!LAYOUT_H_*/ diff --git a/libabsp.adc b/libabsp.adc new file mode 100644 index 0000000..0ce2632 --- /dev/null +++ b/libabsp.adc @@ -0,0 +1,4 @@ +pragma restrictions(no_elaboration_code); +pragma restrictions(no_secondary_stack); +pragma restrictions(no_finalization); +pragma restrictions(no_exception_handlers); diff --git a/libabsp.gpr b/libabsp.gpr new file mode 100644 index 0000000..779ebeb --- /dev/null +++ b/libabsp.gpr @@ -0,0 +1,52 @@ +library project Libabsp is + + for Languages use ("Ada"); + + for Source_Dirs use + ("arch/Ada", + "arch/cores/" & external("ARCH") & "/Ada", + "arch/socs/" & external("SOCNAME") & "/Ada"); + + for Library_Dir use external("BUILD_DIR") & "/Ada/lib"; + for Object_Dir use external("BUILD_DIR") & "/Ada"; + for Target use external("ADA_ARCH"); + for Runtime ("ada") use external("ADA_PROFILE"); + for Library_Name use "absp"; + for Library_Kind use "static"; + + package Compiler is + + basic := + ("-fstack-usage", -- Generate .su file with informations about the + -- amount of stack used + "-gnateG", -- Generate preprocessed source + "-gnatet=target.atp", + "-gnatec=" & Libabsp'Project_Dir & "libabsp.adc", + "-gnatn", -- Enable pragma Inline + "-gnatwa", -- Turn on all warnings + "-gnatw.X", -- Turn off warnings for export/import + "-gnatwe"); -- Treat all warnings as errors + + verif := + ("-gnato", -- Turn on all checks + "-gnatVa"); -- Turn on all validity checks + + no_verif := + ("-gnatp", -- Turn off all checks + "-gnatVn"); -- Turn off all validity checks + + for Default_Switches ("ada") use ("-O3", "-g") & basic & verif; + for Switches ("soc-dma.adb") use ("-Os", "-g") & basic & verif; + + -- Proved SPARK code + for Switches ("soc-dwt.adb") use ("-O3", "-g") & basic & no_verif; + for Switches ("m4-mpu.adb") use ("-O3", "-g") & basic & no_verif; + + end Compiler; + + package Binder is + for Default_Switches ("ada") use ("-n"); + end Binder; + +end Libabsp; + diff --git a/libkernel.adc b/libkernel.adc new file mode 100644 index 0000000..1a546eb --- /dev/null +++ b/libkernel.adc @@ -0,0 +1,3 @@ +pragma restrictions(no_secondary_stack); +pragma restrictions(no_finalization); +pragma restrictions(no_exception_handlers); diff --git a/libkernel.gpr b/libkernel.gpr new file mode 100644 index 0000000..2ebbda5 --- /dev/null +++ b/libkernel.gpr @@ -0,0 +1,123 @@ +with "./libabsp.gpr"; + +library project Libkernel is + + for Languages use ("Ada"); + + for Source_Dirs use + ("Ada", + "Ada/syscalls", + "Ada/exported", + "Ada/generated"); + + for Library_Dir use external("BUILD_DIR") & "/Ada/lib"; + for Object_Dir use external("BUILD_DIR") & "/Ada"; + for Target use external("ADA_ARCH"); + for Runtime ("ada") use external("ADA_PROFILE"); + for Library_Name use "kernel"; + for Library_Kind use "static"; + + for Library_Interface use + ("applications", + "c", + "c.kernel", + "c.socinfo", + "debug", + "ewok", + "ewok.devices", + "ewok.devices.interfaces", + "ewok.devices_shared", + "ewok.dma", + "ewok.dma.interfaces", + "ewok.dma_shared", + "ewok.exported", + "ewok.exported.devices", + "ewok.exported.dma", + "ewok.exported.gpios", + "ewok.exported.interrupts", + "ewok.exported.sleep", + "ewok.exti", + "ewok.exti.handler", + "ewok.exti.interfaces", + "ewok.gpio", + "ewok.interrupts", + "ewok.interrupts.handler", + "ewok.interrupts.interfaces", + "ewok.ipc", + "ewok.isr", + "ewok.layout", + "ewok.mpu", + "ewok.mpu.handler", + "ewok.mpu.interfaces", + "ewok.perm", + "ewok.perm_auto", + "ewok.sanitize", + "ewok.sched", + "ewok.sched.interfaces", + "ewok.softirq", + "ewok.syscalls", + "ewok.syscalls.cfg", + "ewok.syscalls.cfg.gpio", + "ewok.syscalls.cfg.mem", + "ewok.syscalls.dma", + "ewok.syscalls.gettick", + "ewok.syscalls.handler", + "ewok.syscalls.init", + "ewok.syscalls.ipc", + "ewok.syscalls.sleep", + "ewok.syscalls.yield", + "ewok.tasks", + "ewok.tasks_shared", + "ewok.sleep", + "ewok.posthook", + "processor", + "rings", + "sections"); + + + Local_Path := "."; + + package Compiler is + + basic := + ("-fstack-usage", -- Generate .su file with informations about the + -- amount of stack used + "-gnateG", -- Generate preprocessed source + "-gnatep=" & Libkernel'Project_Dir & "gnatprep.def", -- Preprocessing data file + "-gnatet=target.atp", + "-gnatec=" & Libkernel'Project_Dir & "libkernel.adc", + "-gnatn", -- Enable pragma Inline + "-gnatwa", -- Turn on all warnings + "-gnatw.X", -- Turn off warnings for export/import + "-gnatwe"); -- Treat all warnings as errors + + verif := + ("-gnato", -- Turn on all checks + "-gnatVa"); -- Turn on all validity checks + + no_verif := + ("-gnatp", -- Turn off all checks + "-gnatVn"); -- Turn off all validity checks + + -- Ada code + for Default_Switches ("ada") use ("-Os", "-g") & basic & verif; + + for Switches ("ewok-sched.adb") use ("-O3", "-g") & basic & verif; + for Switches ("ewok-tasks.adb") use ("-O3", "-g") & basic & verif; + for Switches ("ewok-syscalls-handler.adb") + use ("-O3", "-g") & basic & verif; + for Switches ("ewok-interrupts-handler.adb") + use ("-O3", "-g") & basic & verif; + + -- Proved SPARK code + for Switches ("ewok-perm.adb") use ("-Os", "-g") & basic & no_verif; + + end Compiler; + + + package Binder is + for Default_Switches ("ada") use ("-n"); + end Binder; + +end Libkernel; + diff --git a/mpu-handler.c b/mpu-handler.c new file mode 100644 index 0000000..83a7d29 --- /dev/null +++ b/mpu-handler.c @@ -0,0 +1,83 @@ +/* \file mpu-handler.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "m4-mpu.h" +#include "shared.h" +#include "autoconf.h" +#include "soc-layout.h" +#include "soc-scb.h" +#include "debug.h" +#include "tasks.h" +#include "kernel.h" +#include "mpu.h" +#include "sched.h" + +#define HANDLERLOG(fmt, ...) \ + dbg_log(ANSI_COLOR_RED fmt ANSI_COLOR_RESET, ##__VA_ARGS__) + +/* +** This is the classical Memory Fault handler. Can be used in both loader and kernel cases, but +** has to be registered manually if needed (for e.g. by mpu_init() part). +*/ +stack_frame_t* MemManage_Handler(stack_frame_t * frame) +{ + task_t *current; + current = sched_get_current(); + + uint32_t mmsr = *((uint32_t *) r_CORTEX_M_SCB_MMSR); + + /* basic default when no 'current' task */ + if (!current) { + HANDLERLOG("MPU error: No current task\n"); + dbg_flush(); + while (1) ; + } + + /* stack errors */ + if (mmsr & SCB_CFSR_MMFSR_MLSPERR_Msk) { + HANDLERLOG("MPU error: Corrupted Stack\n"); + } + + if (mmsr & SCB_CFSR_MMFSR_DACCVIOL_Msk) { + HANDLERLOG("MPU error: Instruction access violation\n"); + } + if (mmsr & SCB_CFSR_MMFSR_DACCVIOL_Msk) { + HANDLERLOG("MPU error: Data access violation\n"); + } + + HANDLERLOG("mmsr:%x, current:%d (%s), sp:%x, pc:%x\n", + mmsr, current->id, current->name, frame, frame->pc); + + /* On memory fault, the task is no more scheduled */ + dbg_flush(); + + if (current->mode == TASK_MODE_MAINTHREAD) { + current->state[TASK_MODE_MAINTHREAD] = TASK_STATE_FAULT; + } else { + current->state[TASK_MODE_ISRTHREAD] = TASK_STATE_FAULT; + } + + request_schedule(); + + return frame; +} diff --git a/mpu.c b/mpu.c new file mode 100644 index 0000000..e127a46 --- /dev/null +++ b/mpu.c @@ -0,0 +1,244 @@ +/* \file mpu.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "m4-mpu.h" +#include "soc-layout.h" +#include "layout.h" +#include "shared.h" +#include "autoconf.h" +#include "debug.h" +#include "tasks.h" +#include "kernel.h" +#include "mpu.h" +#include "sched.h" +#include "generated/apps_layout.h" + +extern const shr_vars_t shared_vars; +extern void MemManage_Handler(void); + +uint8_t mpu_regions_schedule(uint8_t region_number, + physaddr_t addr, + uint16_t size, e_region_type type, uint8_t mask) +{ + region_config my_region; + + my_region.size = size; + my_region.region_number = region_number; + my_region.addr = (uint32_t) addr; + + switch (type) { + case MPU_REGION_USER_DEV: + my_region.access_perm = MPU_REGION_RW_RW; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_YES; + my_region.s = MPU_PERMISSION_YES; + my_region.mask = mask; + if (core_mpu_region_config(&my_region)) { + return 1; + } + break; + case MPU_REGION_RO_USER_DEV: + my_region.access_perm = MPU_REGION_RW_RO; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_YES; + my_region.s = MPU_PERMISSION_YES; + my_region.mask = mask; + if (core_mpu_region_config(&my_region)) { + return 1; + } + break; + + case MPU_REGION_USER_TXT: + my_region.access_perm = MPU_REGION_RO_RO; + my_region.xn = MPU_PERMISSION_NO; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_NO; + my_region.mask = mask; + if (core_mpu_update_subregion_mask(&my_region)) { + return 1; + } + break; + case MPU_REGION_USER_RAM: + my_region.access_perm = MPU_REGION_RW_RW; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_YES; + my_region.mask = mask; + if (core_mpu_update_subregion_mask(&my_region)) { + return 1; + } + break; + case MPU_REGION_BOOTROM: + my_region.access_perm = MPU_REGION_NO_NO; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_NO; + my_region.mask = 0; + if (core_mpu_region_config(&my_region)) { + return 1; + } + break; + case MPU_REGION_ISR_RAM: + my_region.access_perm = MPU_REGION_RW_RW; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_YES; + my_region.mask = 0; + if (core_mpu_region_config(&my_region)) { + return 1; + } + break; + } + return 0; +} + +uint8_t mpu_kernel_init(void) +{ + region_config my_region; + + /* registering kernel memory fault handler */ + set_interrupt_handler(MEMMANAGE_IRQ, MemManage_Handler, 0, ID_DEV_UNUSED); + + core_mpu_init(1, NULL); + KERNLOG(DBG_NOTICE, "MPU Initialized\n"); + dbg_flush(); + + /* SHR */ + my_region.region_number = 0; + my_region.addr = SHR_BASE; + my_region.size = MPU_REGION_SIZE_32Kb; + my_region.access_perm = MPU_REGION_RO_RO; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_NO; + my_region.mask = 0; + + if (core_mpu_region_config(&my_region)) { + ERROR("Unable to map SHR !\n"); + return 1; + } + + /* Current kernel code */ + my_region.region_number = 1; + my_region.addr = TXT_KERN_REGION_BASE; + my_region.size = TXT_KERN_REGION_SIZE; + my_region.access_perm = MPU_REGION_RO_NO; + my_region.xn = MPU_PERMISSION_NO; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_NO; + my_region.mask = 0; + + if (core_mpu_region_config(&my_region)) { + ERROR("Unable to map kernel !\n"); + return 1; + } + + /* Devices: TODO 512Kb should be abstracted in soc-layout */ + my_region.region_number = 2; + my_region.addr = PERIPH_BASE; + my_region.size = MPU_REGION_SIZE_512Kb; + my_region.access_perm = MPU_REGION_RW_NO; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_YES; + my_region.s = MPU_PERMISSION_YES; + my_region.mask = 0; + + if (core_mpu_region_config(&my_region)) { + ERROR("Unable to map devices !\n"); + return 1; + } + + /* kernel data + stacks */ + my_region.region_number = 3; + my_region.addr = RAM_KERN_BASE; + my_region.size = RAM_KERN_REGION_SIZE; + my_region.access_perm = MPU_REGION_RW_NO; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_YES; + my_region.mask = 0; + + if (core_mpu_region_config(&my_region)) { + ERROR("Unable to map kernel RAM !\n"); + return 1; + } + + /* SRAM_USER area */ + my_region.region_number = 4; + my_region.addr = RAM_USER_BASE; + my_region.size = RAM_USER_REGION_SIZE; + my_region.access_perm = MPU_REGION_RW_RW; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_YES; + my_region.mask = 0; + + if (core_mpu_region_config(&my_region)) { + ERROR("Unable to map kernel RAM !\n"); + return 1; + } + + /* USER txt area */ + my_region.region_number = 5; + my_region.addr = TXT_USER_REGION_BASE; + my_region.size = TXT_USER_REGION_SIZE; + my_region.access_perm = MPU_REGION_RO_RO; + my_region.xn = MPU_PERMISSION_NO; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_NO; + my_region.mask = 0; + + if (core_mpu_region_config(&my_region)) { + ERROR("Unable to map user text !\n"); + return 1; + } + + + /* + * User ISR stack + * Note: STM32F4 MPU does not properly handle overlapping memory regions. + * We may need to disable the MPU during sub-region reconfiguration + * to avoid some hardware (?) bug. + */ + + my_region.region_number = 6; + my_region.addr = (uint32_t) STACK_TOP_ISR - STACK_SIZE_ISR; + my_region.size = MPU_REGION_SIZE_4Kb; + my_region.access_perm = MPU_REGION_RW_RW; + my_region.xn = MPU_PERMISSION_YES; + my_region.b = MPU_PERMISSION_NO; + my_region.s = MPU_PERMISSION_YES; + my_region.mask = 0; + if (core_mpu_region_config(&my_region)) { + ERROR("Unable to lock isr ram !\n"); + return 1; + } + + KERNLOG(DBG_NOTICE, "MPU Configured\n"); + dbg_flush(); + + core_mpu_enable(1); + KERNLOG(DBG_NOTICE, "MPU Enabled\n"); + dbg_flush(); + return 0; +} diff --git a/mpu.h b/mpu.h new file mode 100644 index 0000000..1ebfc23 --- /dev/null +++ b/mpu.h @@ -0,0 +1,68 @@ +/* \file mpu.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef KERNEL_MPU +#define KERNEL_MPU + +#ifdef CONFIG_ARCH_ARMV7M +#include "m4-mpu.h" +#else +#error "no MPU arch-specific backend found!" +#endif + +#ifdef CONFIG_SHM +/* last slot is always mapped for SHM */ +static const uint8_t mpu_region_mask[] = + { 0x7e, 0x7d, 0x7b, 0x77, 0x6f, 0x5f, 0x3f }; +#else +static const uint8_t mpu_region_mask[] = + { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf }; +#endif + +typedef enum { + MPU_REGION_USER_RAM = 0, + MPU_REGION_USER_TXT, + MPU_REGION_USER_DEV, + MPU_REGION_RO_USER_DEV, + MPU_REGION_BOOTROM, + MPU_REGION_ISR_RAM, +} e_region_type; + +/* +** Define the max number of independent MPU region usable by userspace to map their device +** This depends on the MPU permissions and the kernel usage of the MPU. +** [PTH]: TODO: Should be a consquence of the configuration (Kconfig set) +*/ +#define MPU_MAX_EMPTY_REGIONS 2 +#define MPU_BOOT_ROM_REGION 3 +#define MPU_USER_RAM_REGION 4 +#define MPU_USER_TXT_REGION 5 +#define MPU_USER_ISR_RAM_REGION 6 + +uint8_t mpu_kernel_init(void); + +uint8_t mpu_regions_schedule(uint8_t region_number, + physaddr_t addr, + uint16_t size, e_region_type type, uint8_t mask); + +#endif /*!KERNEL_MPU */ diff --git a/perm.c b/perm.c new file mode 100644 index 0000000..d3f3017 --- /dev/null +++ b/perm.c @@ -0,0 +1,289 @@ +/* perm.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "regutils.h" +#include "perm.h" +#include "tasks.h" +#include "gen_perms.h" +#include "debug.h" + +/* + * These defines are not used by now (they require the usage of a + * macro construction, which impact the perm.h interface. + * + * The goal here is to keep the perm.h API as much generic and + * substituable as possible, avoiding any side impact of the + * perm internals + * + * The Ressource register is fully described in EwoK Sphinx documentation + * See EwoK API>Permissions for more informations + */ +#define PERM_RES_DEV_DMA_Pos 31 +#define PERM_RES_DEV_DMA_Msk ((uint32_t)1 << PERM_RES_DEV_DMA_Pos) + +#define PERM_RES_DEV_CRYPTO_Pos 29 +#define PERM_RES_DEV_CRYPTO_Msk ((uint32_t)3 << PERM_RES_DEV_CRYPTO_Pos) + +#define PERM_RES_DEV_BUSES_Pos 28 +#define PERM_RES_DEV_BUSES_Msk ((uint32_t)1 << PERM_RES_DEV_BUSES_Pos) + +#define PERM_RES_DEV_EXTI_Pos 27 +#define PERM_RES_DEV_EXTI_Msk ((uint32_t)1 << PERM_RES_DEV_EXTI_Pos) + +#define PERM_RES_DEV_TIM_Pos 26 +#define PERM_RES_DEV_TIM_Msk ((uint32_t)1 << PERM_RES_DEV_TIM_Pos) + +#define PERM_RES_TIM_GETCYCLES_Pos 22 +#define PERM_RES_TIM_GETCYCLES_Msk ((uint32_t)3 << PERM_RES_TIM_GETCYCLES_Pos) + +#define PERM_RES_TSK_FISR_Pos 15 +#define PERM_RES_TSK_FISR_Msk ((uint32_t)1 << PERM_RES_TSK_FISR_Pos) + +#define PERM_RES_TSK_FIPC_Pos 14 +#define PERM_RES_TSK_FIPC_Msk ((uint32_t)1 << PERM_RES_TSK_FIPC_Pos) + +#define PERM_RES_TSK_RESET_Pos 13 +#define PERM_RES_TSK_RESET_Msk ((uint32_t)1 << PERM_RES_TSK_RST_Pos) + +#define PERM_RES_TSK_UPGRADE_Pos 12 +#define PERM_RES_TSK_UPGRADE_Msk ((uint32_t)1 << PERM_RES_TSK_UPG_Pos) + +#define PERM_RES_MEM_DYNAMIC_MAP_Pos 7 +#define PERM_RES_MEM_DYNAMIC_MAP_Msk ((uint32_t)1 << PERM_RES_TSK_FIPC_Pos) + +static ressource_reg_t perm_get_ressource_register(e_task_id task_identifier) +{ + /* + * In C, table rows start with 0. EwoK id start with 1, + * we need to decrement id in consequence + */ + return ressource_perm_tab[task_identifier - 1]; + +} + +/** + * \brief test if a task is allow to declare a DMA SHM with another task + * + * Here we are based on a symetric paradigm (i.e. when a + * task is allowed to declare a DMA SHM with another task, the other + * task is allowed to host a DMA SHM from it). Nonetheless it + * is still an half duplex communication channel (DMA SHM are + * read-only or write-only, accessible only by the DMA controler + * and never mapped into the task memory slot). + * + * \param[in] from the task which want to declare a DMA SHM + * \param[in] tto the task target of the DMA SHM peering + * + * \return true if the permission is granted, of false + * + */ +bool perm_dmashm_is_granted(e_task_id from, + e_task_id to) +{ + /* + * In C, table rows start with 0. EwoK id start with 1, + * we need to decrement id in consequence + */ + return com_dmashm_perm[from - 1][to - 1]; +} + +/** + * \brief test if a task is allow to send an IPC to another task + * + * Here we are based on a symetric paradigm (i.e. when a + * task is allowed to send an IPC to another task, the other + * task is allowed to receive an IPC from it). Nonetheless it + * is still an half duplex communication channel. + * + * \param[in] from the task which want to send an IPC data + * \param[in] tto the task target of the IPC + * + * \return true if the permission is granted, of false + * + */ +bool perm_ipc_is_granted(e_task_id from, + e_task_id to) +{ + /* + * In C, table rows start with 0. EwoK id start with 1, + * we need to decrement id in consequence + */ + return com_ipc_perm[from - 1][to - 1]; +} + + +/** + * \brief test if the ressource is allowed for the task + * + * A typical example of such an API is the following: + * if (!perm_ressource_is_granted(PERM_RES_DEV_DMA, mytask)) { + * goto ret_denied; + * } + * + * \param[in] perm_name the name of the permission + * \param[in] task the task requiring the permission + * + * \return true if the permission is granted, of false + * + */ +bool perm_ressource_is_granted(res_perm_t perm_name, + e_task_id task_id) +{ + uint32_t field = 0; + uint32_t perm = 0; + uint8_t field_pos; + uint32_t field_mask; + ressource_reg_t reg = perm_get_ressource_register(task_id); + + /* + * Here we use a 'naive' switch/case instead of human-optimized code + * or thing like res_perm_t indiced table to get back the permission + * field based on the permission enumerate + * + * This permit to: + * - avoid using .data content + * - let the compiler optimize this simple implementation + * - keep the code as much readable as possible + * + * Using a permission enumerate (without any bitfield consideration) + * also permit to support new permissions and bit field order replacement + * without impact on the perm API. + * + * This is also an advantage to keep a compatible API with the perm Ada + * code, which does not use a bitfield but a complete Ada record for the + * ressource register. + */ + switch (perm_name) { + /* Device specific permissions */ + case PERM_RES_DEV_DMA: + perm = (uint32_t)1 << 31; + field_mask = (uint32_t)1 << 31; + field_pos = 31; + break; + case PERM_RES_DEV_CRYPTO_CFG: + perm = (uint32_t)2 << 29; + field_mask = (uint32_t)3 << 29; + field_pos = 29; + break; + case PERM_RES_DEV_CRYPTO_USR: + perm = (uint32_t)1 << 29; + field_mask = (uint32_t)3 << 29; + field_pos = 29; + break; + case PERM_RES_DEV_CRYPTO_FULL: + perm = (uint32_t)3 << 29; + field_mask = (uint32_t)3 << 29; + field_pos = 29; + break; + case PERM_RES_DEV_BUSES: + perm = (uint32_t)1 << 28; + field_mask = (uint32_t)1 << 28; + field_pos = 28; + break; + case PERM_RES_DEV_EXTI: + perm = (uint32_t)1 << 27; + field_mask = (uint32_t)1 << 27; + field_pos = 27; + break; + case PERM_RES_DEV_TIM: + perm = (uint32_t)1 << 26; + field_mask = (uint32_t)1 << 26; + field_pos = 26; + break; + /* Time specific permissions */ + case PERM_RES_TIM_GETMILLI: + perm = (uint32_t)1 << 22; + field_mask = (uint32_t)1 << 22; + field_pos = 22; + break; + case PERM_RES_TIM_GETMICRO: + perm = (uint32_t)1 << 23; + field_mask = (uint32_t)1 << 23; + field_pos = 23; + break; + case PERM_RES_TIM_GETCYCLE: + perm = (uint32_t)3 << 22; + field_mask = (uint32_t)3 << 22; + field_pos = 22; + break; + /* Task specific permissions */ + case PERM_RES_TSK_FISR: + perm = (uint32_t)1 << 15; + field_mask = (uint32_t)1 << 15; + field_pos = 15; + break; + case PERM_RES_TSK_FIPC: + perm = (uint32_t)1 << 14; + field_mask = (uint32_t)1 << 14; + field_pos = 14; + break; + case PERM_RES_TSK_RESET: + perm = (uint32_t)1 << 13; + field_mask = (uint32_t)1 << 13; + field_pos = 13; + break; + case PERM_RES_TSK_UPGRADE: + perm = (uint32_t)1 << 12; + field_mask = (uint32_t)1 << 12; + field_pos = 12; + break; + case PERM_RES_MEM_DYNAMIC_MAP: + perm = (uint32_t)1 << 7; + field_mask = (uint32_t)1 << 7; + field_pos = 7; + break; + default: + return false; + break; + } + + field = get_reg_value(®, field_mask, field_pos); + if (field == (perm >> field_pos)) { + return true; + } + return false; +} + + +#ifdef CONFIG_KERNEL_DOMAIN +/** + * \brief test if two tasks are in the same security domain + * + * \param[in] from first task which want to communicate + * \param[in] to target of the first task IPC + * + * \return true if the tasks are in the same domain, or false + */ +bool perm_same_ipc_domain(e_task_id src, e_task_id dst) +{ + if (src == ANY_APP || dst == ANY_APP) { + return true; + } + task_t* tasks_list = task_get_tasks_list(); + if (tasks_list[src].domain == tasks_list[dst].domain) { + return true; + } + return false; +} +#endif + diff --git a/perm.h b/perm.h new file mode 100644 index 0000000..6231192 --- /dev/null +++ b/perm.h @@ -0,0 +1,116 @@ +/* \file perm.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef PERM_H_ +#define PERM_H_ + +#include "types.h" +#include "tasks.h" + +typedef enum { + PERM_RES_DEV_DMA, + PERM_RES_DEV_CRYPTO_USR, + PERM_RES_DEV_CRYPTO_CFG, + PERM_RES_DEV_CRYPTO_FULL, + PERM_RES_DEV_BUSES, + PERM_RES_DEV_EXTI, + PERM_RES_DEV_TIM, + PERM_RES_TIM_GETMILLI, + PERM_RES_TIM_GETMICRO, + PERM_RES_TIM_GETCYCLE, + PERM_RES_TSK_FISR, + PERM_RES_TSK_FIPC, + PERM_RES_TSK_RESET, + PERM_RES_TSK_UPGRADE, + PERM_RES_MEM_DYNAMIC_MAP +} res_perm_t; + + +/** + * \brief test if a task is allow to declare a DMA SHM with another task + * + * Here we are based on a symetric paradigm (i.e. when a + * task is allowed to declare a DMA SHM with another task, the other + * task is allowed to host a DMA SHM from it). Nonetheless it + * is still an half duplex communication channel (DMA SHM are + * read-only or write-only, accessible only by the DMA controler + * and never mapped into the task memory slot). + * + * \param[in] from the task which want to declare a DMA SHM + * \param[in] tto the task target of the DMA SHM peering + * + * \return true if the permission is granted, of false + * + */ +bool perm_dmashm_is_granted(e_task_id from, + e_task_id to); + +/** + * \brief test if a task is allow to send an IPC to another task + * + * Here we are based on a symetric paradigm (i.e. when a + * task is allowed to send an IPC to another task, the other + * task is allowed to receive an IPC from it). Nonetheless it + * is still an half duplex communication channel. + * + * \param[in] from the task which want to send an IPC data + * \param[in] tto the task target of the IPC + * + * \return true if the permission is granted, of false + * + */ +bool perm_ipc_is_granted(e_task_id from, + e_task_id to); + +/** + * \brief test if the ressource is allowed for the task + * + * A typical example of such an API is the following: + * if (!perm_ressource_is_granted(PERM_RES_DEV_DMA, mytask)) { + * goto ret_denied; + * } + * + * \param[in] perm_name the name of the permission + * \param[in] task the task requiring the permission + * + * \return true if the permission is granted, of false + * + */ +bool perm_ressource_is_granted(res_perm_t perm_name, + e_task_id task_id); + + +#ifdef CONFIG_KERNEL_DOMAIN +/** + * \brief test if two tasks are in the same security domain + * + * \param[in] from first task which want to communicate + * \param[in] to target of the first task IPC + * + * \return true if the tasks are in the same domain, or false + */ +bool perm_same_ipc_domain(e_task_id src, + e_task_id dst); +#endif + +#endif /*!PERM_H_ */ diff --git a/posthook.c b/posthook.c new file mode 100644 index 0000000..b8773ab --- /dev/null +++ b/posthook.c @@ -0,0 +1,186 @@ +/* \file posthook.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "soc-usart.h" +#include "posthook.h" +#include "regutils.h" +#include "debug.h" +#include "m4-cpu.h" + +uint32_t int_posthook_exec_irq + (e_device_id dev_id, dev_irq_info_t *irq, uint32_t *regs) +{ + uint32_t val, mask; + bool found; + physaddr_t addr = dev_get_device_addr(dev_id); + + for (int i=0; iposthook.action[i].instr) { + case IRQ_PH_NIL: + break; + + case IRQ_PH_READ: + val = read_reg_value((volatile uint32_t*) + (addr + irq->posthook.action[i].read.offset)); + irq->posthook.action[i].read.value = val; + if (irq->posthook.status == irq->posthook.action[i].read.offset) + { + regs[0] = val; + } + if (irq->posthook.data == irq->posthook.action[i].read.offset) { + regs[1] = val; + } + break; + + case IRQ_PH_WRITE: + set_reg_value((volatile uint32_t*) + (addr + irq->posthook.action[i].write.offset), + irq->posthook.action[i].write.value, + irq->posthook.action[i].write.mask, + 0); + break; + + case IRQ_PH_AND: + /* Retrieving the already read register value */ + found = false; + for (int j=0;jposthook.action[j].instr == IRQ_PH_READ && + irq->posthook.action[j].read.offset == + irq->posthook.action[i].and.offset_src) + { + val = irq->posthook.action[j].read.value; + found = true; + break; + } + } + + if (found == false) { + val = read_reg_value((volatile uint32_t*) + (addr + irq->posthook.action[i].and.offset_src)); + } + + /* If there is no '1' bits in common between val and mask, + * mask is zero and no action is necessary */ + mask = irq->posthook.action[i].and.mask & val; + + switch (irq->posthook.action[i].and.mode) { + case MODE_STANDARD: + break; + case MODE_NOT: + val = ~val; + break; + default: + break; + } + + /* Setting the 'offset_dest' register */ + set_reg_value((volatile uint32_t*) + (addr + irq->posthook.action[i].and.offset_dest), val, mask, 0); + + break; + + case IRQ_PH_MASK: + found = false; + for (int j=0;jposthook.action[j].instr == IRQ_PH_READ && + irq->posthook.action[j].read.offset == + irq->posthook.action[i].mask.offset_src) + { + val = irq->posthook.action[j].read.value; + found = true; + break; + } + } + if (found == false) { + val = read_reg_value((volatile uint32_t*) + (addr + irq->posthook.action[i].mask.offset_src)); + } + + found = false; + for (int j=0;jposthook.action[j].instr == IRQ_PH_READ && + irq->posthook.action[j].read.offset == + irq->posthook.action[i].mask.offset_mask) + { + mask = irq->posthook.action[j].read.value; + found = true; + break; + } + } + if (found == false) { + mask = read_reg_value((volatile uint32_t*) + (addr + irq->posthook.action[i].mask.offset_mask)); + } + + mask &= val; + + switch (irq->posthook.action[i].and.mode) { + case MODE_STANDARD: + break; + case MODE_NOT: + val = ~val; + break; + default: + break; + } + + set_reg_value((volatile uint32_t*) + (addr + irq->posthook.action[i].mask.offset_dest), val, mask, 0); + break; + + default: + KERNLOG(DBG_ERR, "unknown posthook instruction"); + break; + } + } + + return 0; +} + +/* +** This function considers that the device posthook has been sanitized at +** device register time. +*/ +uint32_t int_posthook_exec(uint8_t irq, uint32_t *regs) +{ + device_t *udev; + e_device_id dev_id; + + dev_id = get_device_from_interrupt(irq); + if (dev_id == ID_DEV_UNUSED) { + goto end; + } + + udev = dev_get_device_from_id (dev_id); + + for (uint8_t i = 0; i < udev->irq_num; ++i) { + if (udev->irqs[i].irq == irq) { + int_posthook_exec_irq(dev_id, &udev->irqs[i], regs); + break; + } + } + +end: + return 0; +} + diff --git a/posthook.h b/posthook.h new file mode 100644 index 0000000..e15ec9e --- /dev/null +++ b/posthook.h @@ -0,0 +1,34 @@ +/* \file posthook.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef POSTHOOK_H_ +#define POSTHOOK_H_ + +#include "autoconf.h" +#include "tasks.h" +#include "devices.h" +#include "types.h" + +uint32_t int_posthook_exec(uint8_t irq, uint32_t *regs); + +#endif/*!POSTHOOK_H_*/ diff --git a/processor.h b/processor.h new file mode 100644 index 0000000..d7b4302 --- /dev/null +++ b/processor.h @@ -0,0 +1,35 @@ +/* \file processor.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef PROCESSOR_H_ +#define PROCESSOR_H_ + +#include "processor.h" +#include "m4-core.h" + +static inline void processor_init(void) +{ + core_processor_init_modes(); +} + +#endif /*!PROCESSOR_H_ */ diff --git a/prove/Makefile b/prove/Makefile new file mode 100644 index 0000000..a1a6c80 --- /dev/null +++ b/prove/Makefile @@ -0,0 +1,25 @@ +PROJ_FILES = ../../ + +-include $(PROJ_FILES)/Makefile.conf + +all: + gnatprove -P prove.gpr --RTS=$(CONFIG_ADA_RUNTIME)/arm-eabi/lib/gnat/zfp-stm32f4 --mode=all -U + +check: + gnatprove -P prove.gpr --RTS=$(CONFIG_ADA_RUNTIME)/arm-eabi/lib/gnat/zfp-stm32f4 --mode=check_all -U + +flow: + gnatprove -P prove.gpr --RTS=$(CONFIG_ADA_RUNTIME)/arm-eabi/lib/gnat/zfp-stm32f4 --mode=flow -U + +prove: + gnatprove -P prove.gpr --RTS=$(CONFIG_ADA_RUNTIME)/arm-eabi/lib/gnat/zfp-stm32f4 --mode=prove -U + +test: + gnatprove -P prove.gpr --RTS=$(CONFIG_ADA_RUNTIME)/arm-eabi/lib/gnat/zfp-stm32f4 --mode=all -u test.ads test.adb + +clean: + rm -rf $(PROJ_FILES)/kernel/prove/gnatprove/*.ali + +distclean: + rm -rf $(PROJ_FILES)/kernel/prove/gnatprove + diff --git a/prove/README.md b/prove/README.md new file mode 100644 index 0000000..f05db97 --- /dev/null +++ b/prove/README.md @@ -0,0 +1,46 @@ + +Installer le `prover` SPARK +=========================== +Le binaire est sur `https://www.adacore.com/download`. + + apt-get install lib32ncurses5 + apt-get install libc6-i386 + +Configurer le `prover` SPARK +============================ +Toute la procédure est décrite ici : + + https://docs.adacore.com/spark2014-docs/html/ug/en/appendix/alternative_provers.html#alternative-provers + + +Installer la dernière version de CVC4 +--------------------------------------- + +Nécessite l'installation de la `libgmp` : + + apt-get install libgmp-dev + +Installer directement le binaire binaires : + + http://cvc4.cs.stanford.edu/downloads/builds/x86_64-linux-opt/ + cp ~/Downloads/cvc4-1.5-x86_64-linux-opt /opt/spark2014/bin/cvc4 + chmod +x /opt/spark2014/bin/cvc4 + +Ou bien recompiler à partir des sources : + + http://cvc4.cs.stanford.edu/downloads/builds/src/ + ./configure --prefix=/opt/cvc4-1.5 + + +Installer la dernière version de Z3 +------------------------------------- +Debian : + + apt-get install z3 + +Ou bien recompiler à partir des sources : + + https://github.com/Z3Prover/z3 + + + diff --git a/prove/gnatprep.def b/prove/gnatprep.def new file mode 100644 index 0000000..54bc315 --- /dev/null +++ b/prove/gnatprep.def @@ -0,0 +1 @@ +* "config.def" -u -c diff --git a/prove/prove.gpr b/prove/prove.gpr new file mode 100644 index 0000000..920d923 --- /dev/null +++ b/prove/prove.gpr @@ -0,0 +1,32 @@ +project Prove is + + for Source_Dirs use + ("../Ada", + "../Ada/exported", + "../Ada/syscalls", + "../Ada/generated", + "../arch/Ada", + "../arch/cores/armv7-m/Ada", + "../arch/socs/stm32f439/Ada"); + + for Runtime ("Ada") use "zfp-stm32f4"; + for Target use "arm-eabi"; + + package Builder is + for Global_Compilation_Switches ("Ada") use + ("-gnatep=" & Prove'Project_Dir & "gnatprep.def", + "-gnateT=" & Prove'Project_Dir & "target.atp", + "--RTS=/opt/adacore-arm-eabi/arm-eabi/lib/gnat/zfp-stm32f4"); + end Builder; + + package Prove is + for Switches use + ("-j0", -- will use all cores of the machine + "--steps=0", -- maximum number of proof steps (0 = unlimited) + "--level=4", + "--proof=per_check", + "--prover=cvc4,z3,altergo", + "--timeout=5"); -- prover timeout in seconds + end Prove; + +end Prove; diff --git a/prove/target.atp b/prove/target.atp new file mode 100644 index 0000000..3493aeb --- /dev/null +++ b/prove/target.atp @@ -0,0 +1,28 @@ +Bits_BE 0 +Bits_Per_Unit 8 +Bits_Per_Word 32 +Bytes_BE 0 +Char_Size 8 +Double_Float_Alignment 0 +Double_Scalar_Alignment 0 +Double_Size 64 +Float_Size 32 +Float_Words_BE 0 +Int_Size 32 +Long_Double_Size 64 +Long_Long_Size 64 +Long_Size 32 +Maximum_Alignment 8 +Max_Unaligned_Field 64 +Pointer_Size 32 +Short_Enums 1 +Short_Size 16 +Strict_Alignment 1 +System_Allocator_Alignment 8 +Wchar_T_Size 32 +Words_BE 0 + +HF 3 I 16 16 +float 6 I 32 32 +double 15 I 64 64 +long double 15 I 64 64 diff --git a/regutils.h b/regutils.h new file mode 100644 index 0000000..aa3ac9c --- /dev/null +++ b/regutils.h @@ -0,0 +1,250 @@ +/* + * \file regutils.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef REGUTILS_H_ +#define REGUTILS_H_ +#include "types.h" + +#define REG_ADDR(addr) ((volatile uint32_t *)(addr)) +#define REG_VALUE(reg, value, pos, mask) ((reg) |= (((value) << (pos)) & (mask))) + +#define SET_BIT(REG, BIT) ((REG) |= (BIT)) +#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) +#define READ_BIT(REG, BIT) ((REG) & (BIT)) +#define CLEAR_REG(REG) ((REG) = (0x0)) + +#define ARRAY_SIZE(array, type) (sizeof(array) / sizeof(type)) + +/* implicit convertion to int */ +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +__INLINE uint8_t min_u8(uint8_t x, uint8_t y) +{ + if (x < y) + return x; + else + return y; +} + +/* + * These macros assume that the coding style (bits_name_Msk and bits_name_Pos) + * is respected when defining registers bitfields + */ +#define set_reg(REG, VALUE, BITS) set_reg_value(REG, VALUE, BITS##_Msk, BITS##_Pos) +#define get_reg(REG, BITS) get_reg_value(REG, BITS##_Msk, BITS##_Pos) + +__INLINE uint32_t get_reg_value(volatile const uint32_t * reg, uint32_t mask, + uint8_t pos); +__INLINE int8_t set_reg_value(volatile uint32_t * reg, uint32_t value, + uint32_t mask, uint8_t pos); + +__INLINE uint32_t read_reg_value(volatile uint32_t * reg); +__INLINE uint16_t read_reg16_value(volatile uint16_t * reg); +__INLINE void write_reg_value(volatile uint32_t * reg, uint32_t value); +__INLINE void write_reg16_value(volatile uint16_t * reg, uint16_t value); + +__INLINE void set_reg_bits(volatile uint32_t * reg, uint32_t value); +__INLINE void clear_reg_bits(volatile uint32_t * reg, uint32_t value); + +__INLINE uint32_t to_big32(uint32_t value); +__INLINE uint16_t to_big16(uint16_t value); +__INLINE uint32_t to_little32(uint32_t value); +__INLINE uint16_t to_little16(uint16_t value); +__INLINE uint32_t from_big32(uint32_t value); +__INLINE uint16_t from_big16(uint16_t value); +__INLINE uint32_t from_little32(uint32_t value); +__INLINE uint16_t from_little16(uint16_t value); + +__INLINE uint32_t get_reg_value(volatile const uint32_t * reg, uint32_t mask, + uint8_t pos) +{ + if ((mask == 0x00) || (pos > 31)) + return 0; + + return (uint32_t) (((*reg) & mask) >> pos); +} + +__INLINE uint16_t get_reg16_value(volatile uint16_t * reg, uint16_t mask, + uint8_t pos) +{ + if ((mask == 0x00) || (pos > 15)) + return 0; + + return (uint16_t) (((*reg) & mask) >> pos); +} + +__INLINE int8_t set_reg_value(volatile uint32_t * reg, uint32_t value, + uint32_t mask, uint8_t pos) +{ + uint32_t tmp; + + if (pos > 31) + return -1; + + if (mask == 0xFFFFFFFF) { + (*reg) = value; + } else { + tmp = read_reg_value(reg); + tmp &= ~mask; + tmp |= (value << pos) & mask; + write_reg_value(reg, tmp); + } + + return 0; +} + +__INLINE int8_t set_reg16_value(volatile uint16_t * reg, uint16_t value, + uint16_t mask, uint8_t pos) +{ + uint16_t tmp; + + if (pos > 15) + return -1; + + if (mask == 0xFFFF) { + (*reg) = value; + } else { + tmp = read_reg16_value(reg); + tmp &= (uint16_t) ~ mask; + tmp |= (uint16_t) ((value << pos) & mask); + write_reg16_value(reg, tmp); + } + + return 0; +} + +__INLINE uint32_t read_reg_value(volatile uint32_t * reg) +{ + return get_reg_value(reg, 0xFFFFFFFF, 0); +} + +__INLINE uint16_t read_reg16_value(volatile uint16_t * reg) +{ + return get_reg16_value(reg, 0xFFFF, 0); +} + +__INLINE void write_reg_value(volatile uint32_t * reg, uint32_t value) +{ + set_reg_value(reg, value, 0xFFFFFFFF, 0); +} + +__INLINE void write_reg16_value(volatile uint16_t * reg, uint16_t value) +{ + set_reg16_value(reg, value, 0xFFFF, 0); +} + +__INLINE void set_reg_bits(volatile uint32_t * reg, uint32_t value) +{ + *reg |= value; +} + +__INLINE void set_reg16_bits(volatile uint16_t * reg, uint16_t value) +{ + *reg |= value; +} + +__INLINE void clear_reg_bits(volatile uint32_t * reg, uint32_t value) +{ + *reg &= (uint32_t) ~ (value); +} + +__INLINE uint32_t to_big32(uint32_t value) +{ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return ((value & 0xff) << 24) | ((value & 0xff00) << 8) + | ((value & 0xff0000) >> 8) | ((value & 0xff000000) >> 24); +#else + return value; +#endif +} + +__INLINE uint16_t to_big16(uint16_t value) +{ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return (uint16_t) ((value & 0xff) << 8) | (uint16_t) ((value & 0xff00) >> + 8); +#else + return value; +#endif +} + +__INLINE uint32_t to_little32(uint32_t value) +{ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return ((value & 0xff) << 24) | ((value & 0xff00) << 8) + | ((value & 0xff0000) >> 8) | ((value & 0xff000000) >> 24); +#else + return value; +#endif +} + +__INLINE uint16_t to_little16(uint16_t value) +{ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return ((value & 0xff) << 8) | ((value & 0xff00) >> 8); +#else + return value; +#endif +} + +__INLINE uint32_t from_big32(uint32_t value) +{ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return value; +#else + return ((value & 0xff) << 24) | ((value & 0xff00) << 8) + | ((value & 0xff0000) >> 8) | ((value & 0xff000000) >> 24); +#endif +} + +__INLINE uint16_t from_big16(uint16_t value) +{ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return value; +#else + return (uint16_t) ((value & 0xff) << 8) | (uint16_t) ((value & 0xff00) >> + 8); +#endif +} + +__INLINE uint32_t from_little32(uint32_t value) +{ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return value; +#else + return ((value & 0xff) << 24) | ((value & 0xff00) << 8) + | ((value & 0xff0000) >> 8) | ((value & 0xff000000) >> 24); +#endif +} + +__INLINE uint16_t from_little16(uint16_t value) +{ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return value; +#else + return ((value & 0xff) << 8) | ((value & 0xff00) >> 8); +#endif +} + +#endif /*!REGUTILS_H_ */ diff --git a/sanitize.c b/sanitize.c new file mode 100644 index 0000000..b03c5e8 --- /dev/null +++ b/sanitize.c @@ -0,0 +1,181 @@ +/* sanitize.c + * + * Copyright (C) 2018 ANSSI + * All rights reserved. + * + * This software may be modified and distributed under the terms + * of the BSD license. See the LICENSE file for details. + */ + +#include "types.h" +#include "sanitize.h" +#include "tasks.h" +#include "autoconf.h" +#include "layout.h" + +/* + * FIXME: add isr stack slotting in task_t struct + */ + +/** + * @file sanitize.c + * @brief Generic data sanitation for user entries + * +** This file implements the generic input sanitation for syscalls. +** It does not perform structure content check (logical values for +** device_t or dma_t for example), but verify that pointers, string +** or identifiers are valid in term of memory mapping, to avoid any +** invalid kernel memory access or memory access from one task slot +** to another +*/ + +/************************************************************** + * About task slotting + **************************************************************/ + +/*! + * @brief return true if the pointer target a scalar value in task RAM slot + * @param[in] ptr 32 bits data pointer + * @param[in] t associated user task kernel structure + * + * @return true if ptr point to an address in the RAM slot of the task + */ +bool sanitize_is_pointer_in_slot(__user void *ptr, + e_task_id caller, + e_task_mode mode) +{ + + const task_t *t = task_get_task(caller); + if ((physaddr_t) ptr >= t->ram_slot_start + && (physaddr_t) ptr + 4 <= t->ram_slot_end) { + return true; + } else if (mode == TASK_MODE_ISRTHREAD) { + if ( (physaddr_t) ptr >= (STACK_TOP_ISR - STACK_SIZE_ISR) + && (physaddr_t) ptr < STACK_TOP_ISR) { + return true; + } + } + return false; +} + +/*! + * @brief return true if the pointer target a scalar value in task .text or .rodata slot + * @param[in] ptr 32 bits data pointer + * @param[in] t associated user task kernel structure + * + * @return true if ptr point to an address in the .text or .rodata section of the task + */ +bool sanitize_is_pointer_in_txt_slot(__user void *ptr, + e_task_id caller) +{ + const task_t *t = task_get_task(caller); + if ((physaddr_t) ptr >= t->txt_slot_start + && (physaddr_t) ptr + 4 <= t->txt_slot_end) { + return true; + } + return false; +} + +/*! + * @brief return true if the pointer target a scalar value in any task slots + * @param[in] ptr 32 bits data pointer + * @param[in] t associated user task kernel structure + * + * @return true if ptr point to an address in any (RAM, .text or .rodata) sections of the task + */ +bool sanitize_is_data_pointer_in_any_slot(__user void *ptr, + __user uint32_t size, + __user e_task_id caller, + e_task_mode mode) +{ + if ( sanitize_is_data_pointer_in_slot(ptr, size, caller, mode) + || sanitize_is_data_pointer_in_txt_slot(ptr, size, caller)) + { + return true; + } else if (mode == TASK_MODE_ISRTHREAD) { + if ( (physaddr_t) ptr >= (STACK_TOP_ISR - STACK_SIZE_ISR) + && (physaddr_t) ptr < STACK_TOP_ISR) { + return true; + } + } + return false; +} + +/*! + * @brief return true if the pointer target a structured value in task RAM slot + * @param[in] ptr the data pointer + * @param[in] size the size of the pointed content + * @param[in] t associated user task kernel structure + * + * @return true if ptr point to an address in the RAM slot of the task + */ +bool sanitize_is_data_pointer_in_slot(__user void *ptr, + __user uint32_t size, + __user e_task_id caller, + e_task_mode mode) +{ + const task_t *t = task_get_task(caller); + if ((physaddr_t) ptr >= t->ram_slot_start + && (physaddr_t) ptr + size >= (physaddr_t) ptr + && (physaddr_t) ptr + size <= t->ram_slot_end) { + return true; + } else if (mode == TASK_MODE_ISRTHREAD) { + if ( (physaddr_t) ptr >= (STACK_TOP_ISR - STACK_SIZE_ISR) + && (physaddr_t) ptr < STACK_TOP_ISR) { + return true; + } + } + return false; +} + +/*! + * @brief return true if the pointer target a structured value in task .text or .rodata slot + * @param[in] ptr 32 bits data pointer + * @param[in] size the size of the pointed content + * @param[in] t associated user task kernel structure + * + * @return true if ptr point to an address in the .text or .rodata section of the task + */ +bool sanitize_is_data_pointer_in_txt_slot(__user void *ptr, + __user uint32_t size, + __user e_task_id caller) +{ + const task_t *t = task_get_task(caller); + if ((physaddr_t) ptr >= t->txt_slot_start + && (physaddr_t) ptr + size >= (physaddr_t) ptr + && (physaddr_t) ptr + size <= t->txt_slot_end) { + return true; + } + return false; +} + +/************************************************************** + * About DMA slotting + **************************************************************/ + +/*! + * @brief Check that a pointer, associated to a size pointed, targets a DMA SHM region of the task + * @param[in] ptr a DMA buffer pointer + * @param[in] size the size of the DMA buffer + * @param[in] mode (dma RO/RW) + * @param[in] t associated user task kernel structure + * + * @return true if ptr point to a valid shared DMA buffer, allowed as a source for DMA transactions + */ +bool sanitize_is_data_pointer_in_dma_shm(__user void *ptr, + __user uint32_t size, + __user dma_shm_access_t mode, + __user e_task_id caller) +{ + const task_t *t = task_get_task(caller); + for (uint8_t i = 0; i < t->num_dma_shms; ++i) { + if (t->dma_shm[i].mode == mode && + (physaddr_t) ptr >= t->dma_shm[i].address && + (physaddr_t) ptr + size >= (physaddr_t) ptr && + (physaddr_t) ptr + size <= (t->dma_shm[i].address + t->dma_shm[i].size)) { + return true; + } + } + return false; +} + diff --git a/sanitize.h b/sanitize.h new file mode 100644 index 0000000..3fbe05d --- /dev/null +++ b/sanitize.h @@ -0,0 +1,115 @@ +/* \file sanitize.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SANITIZE_H_ +#define SANITIZE_H_ + +#include "exported/dmas.h" +#include "tasks-shared.h" +#include "tasks.h" +#include "kernel.h" + +/************************************************************** + * About task slotting + **************************************************************/ + +/*! + * @brief return true if the pointer target a scalar value in task RAM slot + * @param[in] ptr 32 bits data pointer + * @param[in] t associated user task kernel structure + * @param[in] mode task mode at syscall time + * + * @return true if ptr point to an address in the RAM slot of the task + */ +bool sanitize_is_pointer_in_slot(__user void *ptr, + __user e_task_id caller, + e_task_mode mode); + +/*! + * @brief return true if the pointer target a scalar value in task .text or .rodata slot + * @param[in] ptr 32 bits data pointer + * @param[in] t associated user task kernel structure + * + * @return true if ptr point to an address in the .text or .rodata section of the task + */ +bool sanitize_is_pointer_in_txt_slot(__user void *ptr, + __user e_task_id caller); + +/*! + * @brief return true if the pointer target a scalar value in any task slots + * @param[in] ptr 32 bits data pointer + * @param[in] t associated user task kernel structure + * @param[in] mode task mode at syscall time + * + * @return true if ptr point to an address in any (RAM, .text or .rodata) sections of the task + */ +bool sanitize_is_data_pointer_in_any_slot(__user void *ptr, + __user uint32_t size, + __user e_task_id caller, + e_task_mode mode); + +/*! + * @brief return true if the pointer target a structured value in task RAM slot + * @param[in] ptr the data pointer + * @param[in] size the size of the pointed content + * @param[in] t associated user task kernel structure + * @param[in] mode task mode at syscall time + * + * @return true if ptr point to an address in the RAM slot of the task + */ +bool sanitize_is_data_pointer_in_slot(__user void *ptr, + __user uint32_t size, + __user e_task_id caller, + e_task_mode mode); + +/*! + * @brief return true if the pointer target a structured value in task .text or .rodata slot + * @param[in] ptr 32 bits data pointer + * @param[in] size the size of the pointed content + * @param[in] t associated user task kernel structure + * + * @return true if ptr point to an address in the .text or .rodata section of the task + */ +bool sanitize_is_data_pointer_in_txt_slot(__user void *ptr, + __user uint32_t size, + __user e_task_id caller); + +/************************************************************** + * About DMA slotting + **************************************************************/ + +/*! + * @brief Check that a pointer, associated to a size pointed, targets a DMA SHM region of the task + * @param[in] ptr a DMA buffer pointer + * @param[in] size the size of the DMA buffer + * @param[in] mode (dma RO/RW) + * @param[in] t associated user task kernel structure + * + * @return true if ptr point to a valid shared DMA buffer, allowed as a source for DMA transactions + */ +bool sanitize_is_data_pointer_in_dma_shm(__user void *ptr, + __user uint32_t size, + __user dma_shm_access_t mode, + __user e_task_id caller); + +#endif diff --git a/sched.c b/sched.c new file mode 100644 index 0000000..a3c35e2 --- /dev/null +++ b/sched.c @@ -0,0 +1,615 @@ +/* \file sched.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "m4-mpu.h" +#include "m4-core.h" +#include "m4-cpu.h" +#include "tasks.h" +#include "sched.h" +#include "mpu.h" +#include "devices.h" +#include "apps_layout.h" +#include "layout.h" +#include "libc.h" +#include "debug.h" +#include "soc-scb.h" +#include "sleep.h" + +#include "generated/apps_layout.h" + +#if CONFIG_SCHED_RAND +#include "soc-rng.h" +#endif + +extern stack_frame_t *svc_handler(stack_frame_t* ); + +#define SCHED_PERIOD CONFIG_SCHED_PERIOD + +/* +** current task +*/ + +static task_t *current_task = NULL; + +#ifdef CONFIG_KERNEL_SCHED_DEBUG +typedef struct { + uint32_t ts; /* timestamp */ + uint8_t id; /* task id */ + uint8_t mode; /* task mode (ISR/MT) */ +} sched_debug_t; + +static struct { + uint32_t start; + uint32_t end; + sched_debug_t buf[CONFIG_KERNEL_SCHED_DEBUG_BUFSIZE]; +} sched_ring_buffer; + +void init_sched_ring_buffer(void) +{ + sched_ring_buffer.end = 0; + sched_ring_buffer.start = sched_ring_buffer.end; + memset((void*)sched_ring_buffer.buf, 0, CONFIG_KERNEL_SCHED_DEBUG_BUFSIZE * sizeof(sched_debug_t)); +} + +static void push_sched_info(uint32_t ts, uint8_t id, uint8_t mode) +{ + sched_ring_buffer.buf[sched_ring_buffer.end].ts = ts; + sched_ring_buffer.buf[sched_ring_buffer.end].id = id; + sched_ring_buffer.buf[sched_ring_buffer.end++].mode = mode; + sched_ring_buffer.end %= CONFIG_KERNEL_SCHED_DEBUG_BUFSIZE; + if (sched_ring_buffer.end == sched_ring_buffer.start) { + sched_ring_buffer.start++; + sched_ring_buffer.start %= CONFIG_KERNEL_SCHED_DEBUG_BUFSIZE; + } +} +#endif + + + +#if defined(CONFIG_SCHED_RR) || defined(CONFIG_SCHED_MLQ_RR) +static uint8_t current_id = 0; +#endif + +static uint32_t sched_period = 0; + +/* + * Set PENDSVSET = 1 to generate a PENDSV interrupt that will call the + * scheduler + */ +inline void request_schedule(void) +{ + set_reg_bits(r_CORTEX_M_SCB_ICSR, (1<<28)); +} + +task_t *sched_get_current(void) +{ + return current_task; +} + +/** +** Elect the task. This function host the EwoK scheduling policy. +** EwoK supports various policies by configuration but keeps the same +** general principle: +** 1) If an ISR has to be executed, execute it +** 2) If a forced main-thread exec is required by a currently finishing ISR, execute it +** This specific property is for high reactivity hardware drivers, that need to execute + their main thread just after their ISR +** 3) If softirq (handling syscalls, prepare ISR) has to be executed, execute it +** 4) Current scheduling policy on all schedulable tasks (RAND, RR or MLQ_RR) +** 5) If none of the above, execute Idle +** +*/ +static task_t *sched_task_elect(void) +{ + e_task_id id; + task_t *tasks_list = task_get_tasks_list(); + task_t *elected = 0; + + /* Execute pending user ISR first */ + for (id = ID_APP1; id <= ID_APPMAX; ++id) { + if (tasks_list[id].mode == TASK_MODE_ISRTHREAD && + tasks_list[id].state[TASK_MODE_ISRTHREAD] == TASK_STATE_RUNNABLE) + { + DEBUG(DBG_DEBUG, "task %s (id: %d, slot %d) is in ISR mode\n", + tasks_list[id].name, tasks_list[id].id, tasks_list[id].slot); +#ifdef CONFIG_KERNEL_SCHED_DEBUG + tasks_list[id].isr_count++; +#endif + elected = &tasks_list[id]; + goto end; + } + } + + /* Execute tasks in critical sections */ + for (id = ID_APP1; id <= ID_APPMAX; ++id) { + if (tasks_list[id].state[TASK_MODE_MAINTHREAD] == TASK_STATE_LOCKED) { + elected = &tasks_list[id]; + goto end; + } + } + + /* Any finished ISR is updated in order to go back to its main thread + * state + */ + for (id = ID_APP1; id <= ID_APPMAX; ++id) { + if (tasks_list[id].mode == TASK_MODE_ISRTHREAD && + tasks_list[id].state[TASK_MODE_ISRTHREAD] == TASK_STATE_ISR_DONE) + { + tasks_list[id].state[TASK_MODE_ISRTHREAD] = TASK_STATE_IDLE; + tasks_list[id].ctx[TASK_MODE_ISRTHREAD].frame = 0; + tasks_list[id].ctx[TASK_MODE_ISRTHREAD].dev_id = ID_DEV_UNUSED; + tasks_list[id].ctx[TASK_MODE_ISRTHREAD].irq = 0; + tasks_list[id].mode = TASK_MODE_MAINTHREAD; + +#ifdef CONFIG_SCHED_SUPPORT_FISR + /* if a task has just finished its ISR, elect its main thread + if not SVC_BLOCKED and the ISR requires a forced election */ + if (tasks_list[id].state[TASK_MODE_MAINTHREAD] == TASK_STATE_FORCED) { + tasks_list[id].state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + +# ifdef CONFIG_KERNEL_SCHED_DEBUG + tasks_list[id].force_count++; +# endif + elected = &tasks_list[id]; + goto end; + } +#endif + if (sleep_is_sleeping_task(id)) { + sleep_try_waking_up(id); + } else { + /* finishing ISR awake their main threads when they are in IDLE + * mode, scheduling is leaved to the scheduler policy + * TODO: implement task_awake(id, state) would be better... + */ + if (tasks_list[id].state[TASK_MODE_MAINTHREAD] == TASK_STATE_IDLE) { + tasks_list[id].state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + } + } + } + } + + /* Check if there are some pending softirqs */ + if (tasks_list[ID_SOFTIRQ].state[TASK_MODE_MAINTHREAD] == TASK_STATE_RUNNABLE) { +#ifdef CONFIG_KERNEL_SCHED_KERNEL_SCHED_DEBUG + tasks_list[ID_SOFTIRQ].count++; +#endif + elected = &tasks_list[ID_SOFTIRQ]; + goto end; + } + + /* if a task has been set as FORCED through an IPC, its priority is higher for once */ +#ifdef CONFIG_SCHED_SUPPORT_FIPC + for (id = ID_APP1; id <= ID_APPMAX; ++id) { + if (tasks_list[id].state[TASK_MODE_MAINTHREAD] == TASK_STATE_FORCED) { +# ifdef CONFIG_KERNEL_SCHED_DEBUG + tasks_list[id].force_count++; +# endif + elected = &tasks_list[id]; + goto end; + + } + } +#endif + +#if CONFIG_SCHED_RAND + uint32_t rand = 0; + uint8_t maxtests = 0; + + do { + soc_rng_getrng(&rand); + id = ID_APP1 + (rand % (ID_APPMAX - ID_APP1 + 1)); + + /* + * if current task mode is ISRTHREAD, its state can't be runnable but ISR_DONE or IDLE + * it can't be elected here (automaticaly not runnable) + */ + if (tasks_list[id].state[tasks_list[id].mode] == TASK_STATE_RUNNABLE) { +#ifdef CONFIG_KERNEL_SCHED_DEBUG + tasks_list[id].count++; +#endif + elected = &tasks_list[id]; + goto end; + } + } while (maxtests++ < 32); +#endif + +#if CONFIG_SCHED_RR + for (int i = ID_APP1; i <= ID_APPMAX; i++) { + if (current_id < ID_APPMAX) { + current_id++; + } + else { + current_id = ID_APP1; + } + + id = current_id; + if (tasks_list[id].state[tasks_list[id].mode] == TASK_STATE_RUNNABLE) { +#ifdef CONFIG_KERNEL_SCHED_DEBUG + tasks_list[id].count++; +#endif + elected = &tasks_list[id]; + goto end; + } + } +#endif + +#if CONFIG_SCHED_MLQ_RR + id = ID_APP1; + uint8_t prio = 0; + + /* 1) found the max priority runnable */ + for (int i = ID_APP1; i <= ID_APPMAX; i++) { + if (tasks_list[i].state[TASK_MODE_MAINTHREAD] == TASK_STATE_RUNNABLE && + tasks_list[i].prio > prio) + { + prio = tasks_list[i].prio; + } + } + + /* 2) now execute a RR scheduling on the tasks of the same priority only */ + for (int i = ID_APP1; i <= ID_APPMAX; i++) { + if (current_id < ID_APPMAX) { + current_id++; + } + else { + current_id = ID_APP1; + } + + id = current_id; + if (tasks_list[id].state[TASK_MODE_MAINTHREAD] == TASK_STATE_RUNNABLE && + tasks_list[id].prio == prio) { +#ifdef CONFIG_KERNEL_SCHED_DEBUG + tasks_list[id].count++; +#endif + elected = &tasks_list[id]; + goto end; + } + } + +#ifdef CONFIG_KERNEL_SCHED_DEBUG + tasks_list[id].count++; +#endif + + if (tasks_list[current_id].state[TASK_MODE_MAINTHREAD] == TASK_STATE_RUNNABLE) { + elected = &tasks_list[current_id]; + goto end; + } +#endif /* MLQ_RR */ + + /* Execute the idle task */ +#ifdef CONFIG_KERNEL_SCHED_DEBUG + tasks_list[ID_KERNEL].count++; +#endif + elected = &tasks_list[ID_KERNEL]; + +end: +#ifdef CONFIG_KERNEL_SCHED_DEBUG + push_sched_info(soc_dwt_getcycles() / MAIN_CLOCK_FREQUENCY_US, elected->id, elected->mode); +#endif + + DEBUG(DBG_DEBUG, "task %s (id %d) has been elected\n", + elected->name, elected->id); + + return elected; +} + +/* + * MPU region management during scheduling + * + * BEWARE: Mapping new regions without disabling MPU is feasable only for + * non-overlapping regions. Otherwhise, MPU MUST be disabled during the configuration + * or the region being configured at least once during the init before mpu_enable, + * even if it is replaced after. + */ +uint8_t sched_switch_mpu(task_t *next) +{ + e_region_type region_type; + uint8_t mpu_region_size; + uint8_t ret; + physaddr_t dev_addr; + uint16_t dev_size; + e_device_id dev_id; + + if (next->type == TASK_TYPE_USER) { + KERNLOG(DBG_DEBUG, "remapping MPU for user schedule !\n"); + + uint8_t num_mapped_dev = 0; + + if (next->mode == TASK_MODE_ISRTHREAD) { + dev_id = next->ctx[TASK_MODE_ISRTHREAD].dev_id; + dev_size = dev_get_device_size(dev_id); + dev_addr = dev_get_device_addr(dev_id); + + if (dev_id != ID_DEV_UNUSED && dev_size != 0) { + + /* Convert size in bytes to MPU format used in RASR registers */ + mpu_region_size = core_mpu_bytes_to_region_size(dev_size); + + if (dev_is_device_region_ro(dev_id)) { + region_type = MPU_REGION_RO_USER_DEV; + } else { + region_type = MPU_REGION_USER_DEV; + } + + ret = mpu_regions_schedule (MPU_LAST_REGION, + dev_addr, + mpu_region_size, + region_type, + dev_get_device_region_mask(dev_id)); + if (ret > 0) { + KERNLOG(DBG_ERR, + "Unable to map userspace device id %d (@0x%x) !\n", + dev_id, dev_addr); + } else { + num_mapped_dev++; + } + } + + /* Mapping the ISR stack using an empty dedicated region in the + * kernel RAM */ + ret = mpu_regions_schedule (MPU_USER_ISR_RAM_REGION, + STACK_TOP_ISR - STACK_SIZE_ISR, + MPU_REGION_SIZE_4Kb, + MPU_REGION_ISR_RAM, + 0); + if (ret > 0) { + KERNLOG(DBG_ERR, + "Unable to remap isr stack for isr handler of task %s (%d) !\n", + next->name, next->id); + } + /* + * Now all devices are mapped. + * Nevertheless, as some tasks may map 0, 1, or 2 devices, ISR map 0 or 1 devices, previously mapped + * devices may not be demapped by another mapping at scheduling time (imagine a task mapping 2 devices, + * then another task mapping 0 device. This last app would be able to access the previous task devices + * as they have never been unmapped. + * This is the goald of this little part of code: + * For each residual region used for device mapping (i.e. for which a device has not been mapped in + * this current MPU switching context), we map a specific unaccessible region to avoid any shadowing + * and potential leak or uncontroled communication channel. + * + * This loop differ from the mainthread mon one: the first free region for ISR is used to map the ISR + * stack, not a device. This region must not be disabled as it is always remapped in ISR context. + */ + for (uint8_t current_region = (uint8_t)(MPU_LAST_REGION - num_mapped_dev); + current_region > MPU_LAST_REGION - MPU_MAX_EMPTY_REGIONS + 1; + current_region--) { + ret = core_mpu_region_disable(current_region); + if (ret != 0) { + KERNLOG(DBG_ERR, + "Unable to disable region %d! leak risk!\n", + current_region); + } + } + + + } else { /* TASK_MODE_MAINTHREAD */ + + /* FIXME: remove MIN and use next->num_devs but still use + * some defensive code + * NOTE: a task cannot register more than 2 devices with MMIO + * TODO: blah blah blah... + */ + + for (uint8_t i = 0; i < next->num_devs; ++i) { + dev_id = next->dev_id[i]; + dev_size = dev_get_device_size (dev_id); + dev_addr = dev_get_device_addr (dev_id); + + // device is previously mapped if: + // - declared as DEV_MAP_AUTO + // - declared as DEV_MAP_VOLUNTARY and mapping request + // has already be done, with no unmap after + if (dev_size != 0 && dev_is_mapped(dev_id)) { + /* previously mapped DEV_MAP_VOLUNTARY devices are falgued + * as previously mapped, which keep them mapped at schedule time + * sys_cfg(CFG_DEV_(UN)MAP only manipulate this flag to + * (un)map the device at next mpu configuration time, + * which is syncrhonous for this syscall + */ + if (num_mapped_dev < MPU_MAX_EMPTY_REGIONS) { + mpu_region_size = core_mpu_bytes_to_region_size(dev_size); + + if (dev_is_device_region_ro(dev_id)) { + region_type = MPU_REGION_RO_USER_DEV; + } else { + region_type = MPU_REGION_USER_DEV; + } + + ret = mpu_regions_schedule((uint8_t)(MPU_LAST_REGION - num_mapped_dev), + dev_addr, + mpu_region_size, + region_type, + dev_get_device_region_mask(dev_id)); + if (ret > 0) { + KERNLOG(DBG_ERR, + "Unable to map userspace device %d (@0x%x) !\n", + dev_id, dev_addr); + } else { + num_mapped_dev++; + } + } else { + KERNLOG(DBG_ERR, + "Unable to map userspace device %d: (@0x%x): memory regions exhausted !\n", + dev_id, dev_addr); + } + } + } + /* + * Now all devices are mapped. + * Nevertheless, as some tasks may map 0, 1, or 2 devices, ISR map 0 or 1 devices, previously mapped + * devices may not be demapped by another mapping at scheduling time (imagine a task mapping 2 devices, + * then another task mapping 0 device. This last app would be able to access the previous task devices + * as they have never been unmapped. + * This is the goald of this little part of code: + * For each residual region used for device mapping (i.e. for which a device has not been mapped in + * this current MPU switching context), we map a specific unaccessible region to avoid any shadowing + * and potential leak or uncontroled communication channel. + */ + for (uint8_t current_region = (uint8_t)(MPU_LAST_REGION - num_mapped_dev); + current_region > MPU_LAST_REGION - MPU_MAX_EMPTY_REGIONS; + current_region--) { + ret = core_mpu_region_disable(current_region); + if (ret != 0) { + KERNLOG(DBG_ERR, + "Unable to disable region %d! leak risk!\n", + current_region); + } + } + } + + + /* Now remapping user txt and ram region with subregion deactivation + * the MPU mask depends on the number of required slots */ + uint8_t mask = 0xff; + + for (uint8_t i = 0; i < next->num_slots; ++i) { + /* Note: slot are numbered from 1 to 8 */ + mask &= mpu_region_mask[next->slot - 1 + i]; + } + + /* Mapping code */ + ret = mpu_regions_schedule (MPU_USER_TXT_REGION, + TXT_USER_REGION_BASE, + TXT_USER_REGION_SIZE, + MPU_REGION_USER_TXT, + mask); + if (ret > 0) { + KERNLOG(DBG_ERR, + "Unable to remap user txt for task %s (%d) !\n", + next->name, next->id); + } + + /* Mapping data */ + ret = mpu_regions_schedule (MPU_USER_RAM_REGION, + RAM_USER_BASE, + RAM_USER_REGION_SIZE, + MPU_REGION_USER_RAM, + mask); + + if (ret > 0) { + KERNLOG(DBG_ERR, + "Unable to remap user txt for task %s (%d) !\n", + next->name, next->id); + } + + } + + /* TODO: not TASK_TYPE_USER, specific to STM32F4!!! */ + else { + KERNLOG(DBG_DEBUG, "remapping MPU for kernel schedule !\n"); + /* Lock BOOTROM mapping for supervisor mode (in user mode, it is + * already locked by the default MPU map) */ + ret = mpu_regions_schedule (MPU_BOOT_ROM_REGION, + 0x1FFF0000, + MPU_REGION_SIZE_32Kb, + MPU_REGION_BOOTROM, + 0); + + if (ret > 0) { + KERNLOG(DBG_ERR, "Unable to remap bootrom lock !\n"); + } + return ret; + } + + return 0; +} + +/* This interrupt is activated by request_schedule() */ +stack_frame_t *Sched_PendSV_Handler(stack_frame_t * stack_frame) +{ + sched_period = 0; + // no election when ISR thread is being run. It should finish with SVC + if (current_task->mode == TASK_MODE_ISRTHREAD && + current_task->state[TASK_MODE_ISRTHREAD] == TASK_STATE_RUNNABLE) { + return stack_frame; + } + current_task->ctx[current_task->mode].frame = stack_frame; + current_task = sched_task_elect(); + full_memory_barrier(); + sched_switch_mpu(current_task); + return current_task->ctx[current_task->mode].frame; +} + +stack_frame_t *Sched_Systick_Handler(stack_frame_t * stack_frame) +{ + // reduce the dwt previous value scoping to this function only + core_systick_handler(stack_frame); + + sched_period++; + if (sched_period == SCHED_PERIOD) { + sched_period = 0; + + /* decrement sleep count of sleeping tasks */ + sleep_check_is_awoke(); + + /* Managing DWT cycle count overflow */ + soc_dwt_ovf_manage(); + + // no election when ISR thread is being run. It should finish with SVC + if (current_task->mode == TASK_MODE_ISRTHREAD && + current_task->state[TASK_MODE_ISRTHREAD] == TASK_STATE_RUNNABLE) { + return stack_frame; + } + current_task->ctx[current_task->mode].frame = stack_frame; + current_task = sched_task_elect(); + full_memory_barrier(); + sched_switch_mpu(current_task); + return current_task->ctx[current_task->mode].frame; + } else { + return stack_frame; + } +} + + +void sched_init(void) +{ + task_t *tasks_list = NULL; + +#ifdef CONFIG_KERNEL_SCHED_DEBUG + init_sched_ring_buffer(); +#endif + + tasks_list = task_get_tasks_list(); + current_task = &tasks_list[ID_KERNEL]; + + /* Set handlers involved in scheduling */ + set_interrupt_handler(SYSTICK_IRQ, Sched_Systick_Handler, 0, ID_DEV_UNUSED); + set_interrupt_handler(PENDSV_IRQ, Sched_PendSV_Handler, 0, ID_DEV_UNUSED); + set_interrupt_handler(SVC_IRQ, svc_handler, 0, ID_DEV_UNUSED); + + /* + * Initial context switches to kernel. + */ + asm volatile + ("mov r0, %[SP] \n\t" \ + "msr psp, r0 \n\t" \ + "mov r0, 2 \n\t" \ + "msr control, r0 \n\t" \ + "mov r1, %[PC] \n\t" \ + "bx r1 \n\t" \ + : + : [PC] "r" (current_task->fn), + [SP] "r" (current_task->ctx[current_task->mode].frame) + : "r0", "r1"); +} diff --git a/sched.h b/sched.h new file mode 100644 index 0000000..96272a5 --- /dev/null +++ b/sched.h @@ -0,0 +1,25 @@ +/* sched.h + * + * Copyright (C) 2018 ANSSI + * All rights reserved. + * + * This software may be modified and distributed under the terms + * of the BSD license. See the LICENSE file for details. + */ + +#ifndef SCHED_H +#define SCHED_H + +#include "kernel.h" + +void request_schedule(void); + +void schedule(void); + +void sched_init(void); + +task_t *sched_get_current(void); + +void sched_switch_thread(task_t * to); + +#endif diff --git a/shared/ipc.h b/shared/ipc.h new file mode 100644 index 0000000..080c626 --- /dev/null +++ b/shared/ipc.h @@ -0,0 +1,2 @@ + +#define ANY_APP 0xff diff --git a/sleep.c b/sleep.c new file mode 100644 index 0000000..4f4c98d --- /dev/null +++ b/sleep.c @@ -0,0 +1,113 @@ +#include "exported/sleep.h" +#include "types.h" +#include "autoconf.h" +#include "generated/apps_layout.h" +#include "tasks.h" +#include "sleep.h" +#include "debug.h" + +static struct st { + unsigned long long sleep_until; + bool interruptible; +} sleep_tab[ID_APPMAX + 1] = { 0 }; + +/* + * \brief declare a time to sleep. + * + * This function is called in a syscall context and make the task + * unschedulable for at least the given sleeptime. Only external events + * (ISR, IPC) can awake the task during this period. If no external events + * happend, the task is marked as schedulable at the end of the sleep period, + * which means that the task is schedule *after* the sleep time, not exactly + * at the sleep time end. + * The variation of the time to wait between the end of the sleep time and + * the effective time execution depends on the scheduling policy, the task + * priority and the number of tasks on the system. + * + * \param id the task id requesting to sleep + * \param sleeptime the sleep duration in unit given by unit argument + * \param unit the unit of the sleep time, which is one of sleep_unit_t + */ +uint8_t sleeping(e_task_id id, + uint32_t ms, + sleep_mode_t mode) +{ + if (id <= ID_APPMAX) { + sleep_tab[id].sleep_until = + core_systick_get_ticks() + core_ms_to_ticks (ms); + if (mode == SLEEP_MODE_INTERRUPTIBLE) { + sleep_tab[id].interruptible = true; + } else { + sleep_tab[id].interruptible = false; + } + task_set_task_state(id, TASK_MODE_MAINTHREAD, TASK_STATE_SLEEPING); + } else { + goto err_id; + } +err_id: + return 2; +} + +/* + * This function is called at each sched time of the systick handler, to + * decrement the sleeptime of each task of 1. + * If the speeptime reaches 0, the task mainthread is awoken. + * + * WARNING: there is case where the task is awoken *before* the end of + * its sleep period: + * - when an ISR arise + * - when an IPC targeting the task is pushed + * + * In theses two cases, the sleep_cancel() function must be called in order + * to cancel the current sleep round. The task is awoken by the corresponding + * kernel module instead. + */ +void sleep_check_is_awoke(void) +{ + uint64_t t = core_systick_get_ticks(); + + for (uint8_t id = 0; id <= ID_APPMAX; ++id) { + if (task_get_task_state(id, TASK_MODE_MAINTHREAD) == TASK_STATE_SLEEPING + && t > sleep_tab[id].sleep_until) + { + task_set_task_state(id, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + } + } +} + +/** + * \brief check if a task is currently sleeping + * + * \param id the task id to check + * + * return true if a task is sleeping, or false + */ +bool sleep_is_sleeping_task(e_task_id id) +{ + if (task_get_task_state(id, TASK_MODE_MAINTHREAD) == TASK_STATE_SLEEPING) { + if (sleep_tab[id].sleep_until > core_systick_get_ticks()) { + return true; + } else { + task_set_task_state(id, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + return false; + } + } else { + return false; + } +} + +/* + * As explain in sleep_round function explanations, some external events may + * awake the main thread. In that case, the sleep process must be canceled + * as the awoking process is made by another module. + * tasks that have requested locked sleep will continue to sleep + */ +void sleep_try_waking_up (e_task_id id) +{ + if (sleep_tab[id].sleep_until < core_systick_get_ticks() || + sleep_tab[id].interruptible == true) + { + task_set_task_state(id, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + } +} + diff --git a/sleep.h b/sleep.h new file mode 100644 index 0000000..75ddfd9 --- /dev/null +++ b/sleep.h @@ -0,0 +1,100 @@ +/* \file sleep.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SLEEP_H +# define SLEEP_H + +/* + * \file sleep module for EwoK + * + * This module implement the sys_sleep() syscall internals. This module + * permit to ask the kernel for sleeping for a certain amount of time, what + * sys_yield() doesn't, as it wait indefinitely for an external event. + * + * FIXME: is it interesting for the sys_sleep() syscall to specify if + * the task which to be awoken by external events *before* the end of its + * sleep period or to refuse any prematurate wakeup ? + * + * INFO: the sleep module is nearly implemented but the syscall is *not* + * by now. The call to the sleep module API in the SysTick Handler is not done + * too. + */ + +#include "exported/sleep.h" +#include "types.h" + + +/* + * \brief declare a time to sleep. + * + * This function is called in a syscall context and make the task + * unschedulable for at least the given sleeptime. Only external events + * (ISR, IPC) can awake the task during this period. If no external events + * happend, the task is marked as schedulable at the end of the sleep period, + * which means that the task is schedule *after* the sleep time, not exactly + * at the sleep time end. + * The variation of the time to wait between the end of the sleep time and + * the effective time execution depends on the scheduling policy, the task + * priority and the number of tasks on the system. + * + * \param id the task id requesting to sleep + * \param sleeptime the sleep duration in unit given by unit argument + * \param mode sleep mode (preemptible by ISR or IPC, or unpreemptible) + */ +uint8_t sleeping(e_task_id id, + uint32_t ms, + sleep_mode_t mode); + +/* + * This function is called at each sched time of the systick handler, to + * decrement the sleeptime of each task of 1. + * If the speeptime reaches 0, the task mainthread is awoken. + * + * WARNING: there is case where the task is awoken *before* the end of + * its sleep period: + * - when an ISR arise + * - when an IPC targeting the task is pushed + * + * In theses two cases, the sleep_cancel() function must be called in order + * to cancel the current sleep round. The task is awoken by the corresponding + * kernel module instead. + */ +void sleep_check_is_awoke(void); + +/*! + * As explain in sleep_round function explanations, some external events may + * awake the main thread. In that case, the sleep process must be canceled + * as the awoking process is made by another module. + * tasks that have requested locked sleep will continue to sleep + */ +void sleep_try_waking_up(e_task_id id); + +/** + * \brief check if a task is currently sleeping + * + * \param id the task id to check + * + * return true if a task is sleeping, or false + */ +bool sleep_is_sleeping_task(e_task_id id); + +#endif/*!SLEEP_H*/ diff --git a/softirq.c b/softirq.c new file mode 100644 index 0000000..74c8e24 --- /dev/null +++ b/softirq.c @@ -0,0 +1,405 @@ +/* softirq.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "m4-mpu.h" +#include "m4-cpu.h" +#include "soc-interrupts.h" + +#include "softirq.h" +#include "layout.h" +#include "types.h" +#include "debug.h" +#include "autoconf.h" +#include "libc.h" +#include "sched.h" +#include "syscalls.h" +#include "kernel.h" +#include "tasks.h" +#include "tasks-shared.h" +#include "devices.h" +#include "mpu.h" +#include "syscalls-init.h" + +#include "dma.h" +#include "soc-dma.h" +#include "sleep.h" + +/* +** max IRQ waiting +*/ +#define MAX_QUEUE_SIZE 12 + +typedef enum { + SFQ_DONE = 0, + SFQ_WAITING +} e_softirq_state; + +typedef struct { + task_t *caller; //syscall case, task requesting + e_softirq_state state; + uint8_t irqnum; //IRQ case, nIRQ requesting + physaddr_t handler; //IRQ case, user handler + physaddr_t status; //IRQ case, status register value, when needed + physaddr_t data; //IRQ case, data register value, when needed +} softirq_t; + +typedef void (*softirq_handler_t) (softirq_t *); + +typedef struct { + uint32_t start; + uint32_t end; + bool full; + bool empty; + softirq_t queue[MAX_QUEUE_SIZE]; +} softirqs_queue; + +#define BUF_MAX (MAX_QUEUE_SIZE - 1) + +/* +** All input queue are ring buffers. +** This allows multiple syscalls/IRQ queries by external execution before finishing others. +** Note: a user ISR can't execute a syscall because it has no dedicated stack +*/ +static softirqs_queue isr_queue; +static softirqs_queue syscall_queue; + +/* +** push some content in one of the softirq ring buffers +*/ +__INLINE uint8_t push_softirq(softirqs_queue *queue, e_task_id task_id, + uint8_t irqnum, physaddr_t handler, + physaddr_t *regs) +{ + task_t *caller; + + caller = task_get_task(task_id); + if (caller == NULL) { + panic("push_softirq(): faulty task_id %d", task_id); + } + + if (queue->full) { + return 1; + } + + queue->empty = false; + + queue->queue[queue->end].state = SFQ_WAITING; + queue->queue[queue->end].caller = caller; + queue->queue[queue->end].irqnum = irqnum; + queue->queue[queue->end].handler = handler; + if (regs != 0) { + queue->queue[queue->end].status = regs[0]; + queue->queue[queue->end].data = regs[1]; + } else { + queue->queue[queue->end].status = 0; + queue->queue[queue->end].data = 0; + } + + queue->end++; + queue->end %= BUF_MAX; + if (queue->end == queue->start) { + queue->full = true; + } + + return 0; +} + +/* +** pop some content from one of the softirq ring buffers +** This is a FIFO mode to respect the ISR and syscall order +** +** CAUTION: IRQ are temporary disabled to avoid race condition +** between pop and push from IRQ context. This disabling is +** really short, the time to effectively pop the cell and update +** the queue. +*/ +__INLINE softirq_t* pop_softirq(softirqs_queue *queue) +{ + softirq_t *sfq; + + disable_irq(); + if (queue->empty) { + enable_irq(); + return NULL; + } + + queue->full = false; + + sfq = &(queue->queue[queue->start]); + + queue->start++; + queue->start %= BUF_MAX; + if (queue->end == queue->start) { + queue->empty = true; + } + + enable_irq(); + return sfq; +} + +/* +** Handler managing syscalls (svc 0) waiting for execution in the softirq input queue +*/ +static void softirq_handler_syscall(softirq_t * sfq) +{ + svcnum_t svc = 0; + uint32_t *args = 0; + char *svcptr = 0; + uint32_t syscall = 0; + stack_frame_t *frame = sfq->caller->ctx[TASK_MODE_MAINTHREAD].frame; + + // let's execute the effective content of the syscall from the userspace task + // FIXME: [PTH] svc is 8bits on Thumb2, to be updated for portability + svcptr = (char *)frame->pc; + svc = (uint32_t) svcptr[-2]; + args = (uint32_t *) frame->r0; + + if (svc != 0) { + dbg_log("unsupported system call svc=%d!\n", svc); + dbg_flush(); + } + + syscall = (uint32_t) args[0]; + + /* + * TODO: Hardcoded TASK_MODE_MAINTHREAD should be replaced by the + * caller task current mode at svc handler time, passed through + * softirq_query, using the same mechanism as svc_handler_syscalls(). + */ + KERNLOG(DBG_DEBUG, "Executing syscall %d for task %s\n", syscall, + sfq->caller->name); + switch (syscall) { + case SYS_YIELD: + sys_yield(sfq->caller, TASK_MODE_MAINTHREAD); + break; + case SYS_RESET: + sys_reset(sfq->caller, TASK_MODE_MAINTHREAD); + break; + case SYS_SLEEP: + sys_sleep(sfq->caller, &args[1], TASK_MODE_MAINTHREAD); + break; + case SYS_LOCK: + sys_lock(sfq->caller, &args[1], TASK_MODE_MAINTHREAD); + break; + case SYS_INIT: + sys_init(sfq->caller, &args[1], TASK_MODE_MAINTHREAD); + break; + case SYS_IPC: + sys_ipc(sfq->caller, &args[1], TASK_MODE_MAINTHREAD); + break; + case SYS_CFG: + sys_cfg(sfq->caller, &args[1], TASK_MODE_MAINTHREAD); + break; + case SYS_GETTICK: + sys_gettick(sfq->caller, &args[1], TASK_MODE_MAINTHREAD); + break; + default: + WARN("Unknown syscall %d for task %s\n", syscall, sfq->caller->name); + break; + } + return; +} + +/* + * This function prepare execution of the user ISR handler in user mode (with + * PSP stack). When PendSV will request the scheduler, ISRTHREAD mode tasks + * will be scheduled with the highest priority (note: it can + * be preempted by any IRQ). + */ +static void softirq_handler_user_isr(softirq_t * sfq) +{ + static e_task_id previous_isr_owner = ID_UNUSED; + task_t *task = sfq->caller; + uint8_t irq = sfq->irqnum; + physaddr_t isr_params[4] = { 0, 0, 0, 0 }; + e_device_id dev_id; + + isr_params[0] = sfq->handler; + isr_params[1] = (uint8_t) (irq - 16); /* IRQ num for NVIC starts with 0 */ + isr_params[2] = sfq->status; + isr_params[3] = sfq->data; + + + // FIXME: DMA device has to be mapped in IRQ context; dma is not a device_t + + dev_id = get_device_from_interrupt(irq); + if (dev_id != ID_DEV_UNUSED) { + task->ctx[TASK_MODE_ISRTHREAD].dev_id = dev_id; + } + else { + task->ctx[TASK_MODE_ISRTHREAD].dev_id = ID_DEV_UNUSED; + } + + task->ctx[TASK_MODE_ISRTHREAD].irq = dev_get_irqinfo_from_irq(irq); + + /* Creating the fake stack for ISR handler and create the initial frame */ + if (sfq->caller->id != previous_isr_owner) { + /* Zeroing the stack only if previous ISR belongs to another task */ + memset((char *)STACK_TOP_ISR - STACK_SIZE_ISR, 0, STACK_SIZE_ISR); + previous_isr_owner = sfq->caller->id; + } + + task->ctx[TASK_MODE_ISRTHREAD].frame = (stack_frame_t *) STACK_TOP_ISR; + + /* + * The schedule will execute 'task->ctx[TASK_MODE_ISRTHREAD].fn' that + * is for every tasks 'libs/libstd/arch/cores/armv7-m/m4_syscall.c: + * do_startisr()' function. That function is a wrapper that take + * several parameters: + * isr_params[0]: user handler to execute + * isr_params[1]: irq + * isr_params[2]: status + * isr_params[3]: data + */ + task_create_stack(&task->ctx[TASK_MODE_ISRTHREAD], STACK_TOP_ISR, + (uint32_t) task->ctx[TASK_MODE_ISRTHREAD].fn, + isr_params); + + task->mode = TASK_MODE_ISRTHREAD; + task->state[TASK_MODE_ISRTHREAD] = TASK_STATE_RUNNABLE; + + full_memory_barrier(); +} + +/* +** initialize handlers +*/ +void softirq_init(void) +{ + isr_queue.empty = true; + isr_queue.full = false; + isr_queue.start = 0; + isr_queue.end = 0; + + syscall_queue.empty = true; + syscall_queue.full = false; + syscall_queue.start = 0; + syscall_queue.end = 0; + + KERNLOG(DBG_NOTICE, + "Initialized softirq subsystem. Syscalls and user IRQ/FIQ are handled out of interrupt mode.\n"); + dbg_flush(); +} + +/* +** Query for a new softirq +** executed in hander mode +*/ +void softirq_query(e_softirq_type sfq, e_task_id task_id, uint8_t irq, + physaddr_t irq_handler, physaddr_t *args) +{ + int ret; + + switch (sfq) { + case SFQ_SYSCALL: + ret = push_softirq(&syscall_queue, task_id, 0, 0, 0); + if (ret) { + panic("push_softirq() failed"); + } + break; + case SFQ_USR_ISR: + ret = push_softirq(&isr_queue, task_id, irq, irq_handler, args); + if (ret) { + panic("push_softirq() failed"); + } + break; + default: + panic("push_softirq(): unknown method!"); + break; + } + task_set_task_state (ID_SOFTIRQ, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + request_schedule(); + full_memory_barrier(); +} + +/* +** This is the softirq task. Scheduled when a syscall or a userspace interrupt handler +** need to be executed. It is executed out of processor interrupt mode, on voluntary schedule +** only. +*/ +void task_softirq(void) +{ + softirq_t *sfq = NULL; + + while (1) { + + /* + * User ISRs + */ + if (!isr_queue.empty) { + while ((sfq = pop_softirq(&isr_queue))) { + if (sfq->state == SFQ_WAITING) { + if (sfq->caller->state[TASK_MODE_MAINTHREAD] != TASK_STATE_LOCKED) + { + disable_irq(); + softirq_handler_user_isr(sfq); + sfq->state = SFQ_DONE; + full_memory_barrier(); + enable_irq(); +#ifdef CONFIG_ISR_REACTIVITY + // ISR should be executed fastly, softirq let them being + // executed now, syscalls are delayed + request_schedule(); +#endif + } else { + // while task is locked, postponing the ISR + uint32_t args[2] = { sfq->status, sfq->data }; + disable_irq(); + full_memory_barrier(); + push_softirq(&isr_queue, sfq->caller->id, sfq->irqnum, sfq->handler, args); + sfq->state = SFQ_DONE; + enable_irq(); + } + } + } + } + + full_memory_barrier(); + + /* + * Syscalls + */ + if (!syscall_queue.empty) { + while ((sfq = pop_softirq(&syscall_queue))) { + if (sfq->state == SFQ_WAITING) { + softirq_handler_syscall(sfq); + sfq->state = SFQ_DONE; + } + } + } + + disable_irq(); + full_memory_barrier(); + + if (syscall_queue.empty && isr_queue.empty) { + /* Softirq is idle when there is no more syscall of ISR to manage */ + task_set_task_state (ID_SOFTIRQ, TASK_MODE_MAINTHREAD, TASK_STATE_IDLE); + full_memory_barrier(); + request_schedule(); + } + + enable_irq(); + + } + /* end of main loop */ +} diff --git a/softirq.h b/softirq.h new file mode 100644 index 0000000..57e4202 --- /dev/null +++ b/softirq.h @@ -0,0 +1,31 @@ +/* softirq.h + * + * Copyright (C) 2018 ANSSI + * All rights reserved. + * + * This software may be modified and distributed under the terms + * of the BSD license. See the LICENSE file for details. + */ + +#ifndef SOFTIRQ_H_ +#define SOFTIRQ_H_ + +#include "tasks.h" + +typedef enum { + SFQ_USR_ISR = 0, + SFQ_SYSCALL = 1, + NUM_SOFTIRQ = 2, +} e_softirq_type; + +/* the softirq task itslef */ +void task_softirq(void); + + /**/ +void softirq_query(e_softirq_type sfq, e_task_id task_id, uint8_t irq, + physaddr_t irq_handler, physaddr_t *args); + +/* init the softirq subsystem */ +void softirq_init(void); + +#endif diff --git a/syscalls-handler.c b/syscalls-handler.c new file mode 100644 index 0000000..c7a16b7 --- /dev/null +++ b/syscalls-handler.c @@ -0,0 +1,259 @@ +/* \file syscalls-handler.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "autoconf.h" +#include "types.h" +#include "debug.h" +#include "tasks.h" +#include "sched.h" +#include "softirq.h" +#include "syscalls.h" +#include "syscalls-cfg.h" +#include "syscalls-dma.h" + +static inline bool svc_is_synchronous_syscall(task_t * caller) +{ + uint32_t *args = 0; + uint32_t syscall = 0; + uint32_t subsyscall = 0; + stack_frame_t *frame = caller->ctx[caller->mode].frame; + + // let's execute the effective content of the syscall from the userspace task + // FIXME: [PTH] svc is 8bits on Thumb2, to be updated for portability + args = (uint32_t *) frame->r0; + + syscall = (uint32_t) args[0]; + subsyscall = (uint32_t) args[1]; + + if (syscall == SYS_YIELD) { + return true; + } + if (syscall == SYS_GETTICK) { + return true; + } + if (syscall == SYS_RESET) { + return true; + } + if (syscall == SYS_SLEEP) { + return true; + } + if (syscall == SYS_LOCK) { + return true; + } + if (syscall == SYS_CFG) { + if (subsyscall == CFG_DMA_RELOAD || + subsyscall == CFG_DMA_RECONF || + subsyscall == CFG_DMA_DISABLE|| + subsyscall == CFG_DEV_MAP || + subsyscall == CFG_DEV_UNMAP) + { + return true; + } + } + return false; +} + + +/* +** Handler managing syscalls (svc 0) directly in hanlder mode (synchronous syscalls +** the syscall mode is given to the syscall directly +*/ +static inline void svc_synchronous_syscall(task_t * caller) +{ + svcnum_t svc = 0; + uint32_t *args = 0; + char *svcptr = 0; + uint32_t syscall = 0; + uint32_t subsyscall = 0; + + stack_frame_t *frame = caller->ctx[caller->mode].frame; + + // let's execute the effective content of the syscall from the userspace task + // FIXME: [PTH] svc is 8bits on Thumb2, to be updated for portability + svcptr = (char *)frame->pc; + svc = (uint32_t) svcptr[-2]; + args = (uint32_t *) frame->r0; + subsyscall = (uint32_t) args[1]; + + if (svc != 0) { + dbg_log("unsupported system call svc=%d!\n", svc); + dbg_flush(); + } + + syscall = (uint32_t) args[0]; + + KERNLOG(DBG_DEBUG, "Executing syscall %d for task %s\n", syscall, + caller->name); + switch (syscall) { + case SYS_YIELD: + sys_yield(caller, caller->mode); + break; + case SYS_GETTICK: + sys_gettick(caller, &args[1], caller->mode); + break; + case SYS_RESET: + sys_reset(caller, caller->mode); + break; + case SYS_SLEEP: + sys_sleep(caller, &args[1], caller->mode); + break; + case SYS_LOCK: + sys_lock(caller, &args[1], caller->mode); + break; + case SYS_CFG: { + switch (subsyscall) { + case CFG_DMA_RECONF: + sys_cfg_dma_reconf(caller, &args[1], caller->mode); + break; + case CFG_DMA_RELOAD: + sys_cfg_dma_reload(caller, &args[1], caller->mode); + break; + case CFG_DMA_DISABLE: + sys_cfg_dma_disable(caller, &args[1], caller->mode); + break; + case CFG_DEV_MAP: + sys_cfg_dev_map(caller, &args[1], caller->mode); + break; + case CFG_DEV_UNMAP: + sys_cfg_dev_unmap(caller, &args[1], caller->mode); + break; + } + break; + } + default: + WARN("Unknown syncrhonous syscall %d for task %s\n", syscall, caller->name); + break; + } + return; +} + +/* + * TODO: sched_get_current() and all associated types (caller...) should use task_id. + * This will ermit to avoid any pointer usage since the task module export enough + * getters and setters based on the task_id argument. + * + * Using that, it is possible to make all syscalls SPARK compatible, in Ada mode, + * deleting all references to _access variables. + * The task_t structure should only be visible to the task package itself. + */ +stack_frame_t *svc_handler(stack_frame_t * stack_frame) +{ + task_t *current_task; + char *svcptr = 0; + svcnum_t svc = 0; + +#ifdef CONFIG_KERNEL_SYSCALLS_WISE_REPARTITION // requied for syscalls in ISR + bool wise = true; +#else + bool wise = false; +#endif + + current_task = sched_get_current(); + + /* Saving context before executing complex content in handler */ + current_task->ctx[current_task->mode].frame = stack_frame; + + svcptr = (char *) stack_frame->pc; + svc = (uint32_t) svcptr[-2]; + + switch (svc) { + + /* Syscall */ + case 0: // user syscall + KERNLOG(DBG_DEBUG, "Syscall SVC from %s\n", current_task->name); + + /* + * Syscalls execution is usually delayed (managed by the SoftIRQ kernel + * task). + * Tasks in ISR mode share the same stack. For that reason, their + * syscalls can't be delayed ('synchronous' execution). + */ + + if (current_task->mode == TASK_MODE_ISRTHREAD) { + if (wise && svc_is_synchronous_syscall(current_task)) { + svc_synchronous_syscall(current_task); + } else { + syscall_r0_update(current_task, TASK_MODE_ISRTHREAD, SYS_E_DENIED); + } + } else { + /* Only some critical syscalls executed synchronously */ + if (wise && svc_is_synchronous_syscall(current_task)) { + svc_synchronous_syscall(current_task); + } else { + current_task->state[TASK_MODE_MAINTHREAD] = TASK_STATE_SVC_BLOCKED; + softirq_query(SFQ_SYSCALL, current_task->id, 0, 0, 0); + task_set_task_state(ID_SOFTIRQ, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + request_schedule(); + } + } + break; + + /* Task done */ + case 1: + dbg_log("Task %s returns from main(). Set as finished.\n", + current_task->name); + dbg_flush(); + current_task->state[TASK_MODE_MAINTHREAD] = TASK_STATE_FINISHED; + request_schedule(); + break; + + /* ISR done */ + case 2: + // If the task previously executed yield syscall, it is awoken by the execution by any + // of its ISR handlers. This change is enough for now, the task electing code will + // update the task mode to valid context just before its election in handler mode, to avoid + // any race condition. + // check if the current ISR requires to force mainthread exec + if (current_task->ctx[TASK_MODE_ISRTHREAD].irq) { + switch (current_task->ctx[TASK_MODE_ISRTHREAD].irq->mode) { +#ifdef CONFIG_SCHED_SUPPORT_FISR + case IRQ_ISR_FORCE_MAINTHREAD: + //TODO: don't do this for FAULT & FINISHED tasks + if (current_task->state[TASK_MODE_MAINTHREAD] == TASK_STATE_IDLE || + current_task->state[TASK_MODE_MAINTHREAD] == TASK_STATE_RUNNABLE) + { + current_task->state[TASK_MODE_MAINTHREAD] = TASK_STATE_FORCED; + } + break; +#endif + default: + break; + } + } + // set ISR thread as done + current_task->state[TASK_MODE_ISRTHREAD] = TASK_STATE_ISR_DONE; + request_schedule(); + break; + + default: + KERNLOG(DBG_ERR, + "Invalid SVC request %d from %s ! locking task !\n", + svc, current_task->name); + dbg_flush(); + current_task->state[TASK_MODE_MAINTHREAD] = TASK_STATE_FAULT; + request_schedule(); + break; + } + + return stack_frame; +} diff --git a/syscalls/syscalls-cfg-gpio.c b/syscalls/syscalls-cfg-gpio.c new file mode 100644 index 0000000..4a7e27d --- /dev/null +++ b/syscalls/syscalls-cfg-gpio.c @@ -0,0 +1,102 @@ +/* syscalls-cfg-gpio.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "debug.h" +#include "devices.h" +#include "devices-shared.h" +#include "gpio.h" +#include "syscalls.h" +#include "syscalls-utils.h" +#include "syscalls-cfg-gpio.h" +#include "sanitize.h" + +void sys_cfg_gpio_set(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + uint8_t user_gpio = (uint8_t) regs[1]; + uint8_t gpio_value = (uint8_t) regs[2]; + device_t *udev; + + /* Generic sanitation of inputs */ + if (caller->init_done == false) { + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; + } + + /* Validate that the GPIO is owned by the task */ + for (int i = 0; i < caller->num_devs; ++i) { + udev = dev_get_device_from_id (caller->dev_id[i]); + + for (int j = 0; j < udev->gpio_num; ++j) { + if (udev->gpios[j].kref.val == user_gpio) { + gpio_set_value(udev->gpios[j].kref, gpio_value); + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); + return; + } + } + } + + /* GPIO not found */ + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + return; +} + +void sys_cfg_gpio_get(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + uint8_t user_gpio = (uint8_t) regs[1]; + uint32_t *gpio_value = (uint32_t *) regs[2]; + device_t *udev; + + /* Generic sanitation of inputs */ + if (!sanitize_is_pointer_in_slot((void *)gpio_value, caller->id, mode)) { + goto ret_inval; + } + + /* End of generic sanitation */ + if (caller->init_done == false) { + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; + } + + /* validate that the GPIO is owned by the task */ + for (int i = 0; i < caller->num_devs; ++i) { + udev = dev_get_device_from_id (caller->dev_id[i]); + for (int j = 0; j < udev->gpio_num; ++j) { + if (udev->gpios[j].kref.val == user_gpio) { + *gpio_value = gpio_get_value(udev->gpios[j].kref); + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); + return; + } + } + } + + ret_inval: + /* GPIO not found or invalid value*/ + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + return; +} diff --git a/syscalls/syscalls-cfg-gpio.h b/syscalls/syscalls-cfg-gpio.h new file mode 100644 index 0000000..f28c4a7 --- /dev/null +++ b/syscalls/syscalls-cfg-gpio.h @@ -0,0 +1,32 @@ +/* \file syscalls-cfg-gpio.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SYSCALLS_CFG_GPIO_H_ +#define SYSCALLS_CFG_GPIO_H_ + +#include "tasks.h" + +void sys_cfg_gpio_set(task_t *caller, __user regval_t *regs, e_task_mode mode); + +void sys_cfg_gpio_get(task_t *caller, __user regval_t *regs, e_task_mode mode); + +#endif /*!SYSCALLS_CFG_GPIO_H_*/ diff --git a/syscalls/syscalls-cfg-mem.c b/syscalls/syscalls-cfg-mem.c new file mode 100644 index 0000000..2744d1a --- /dev/null +++ b/syscalls/syscalls-cfg-mem.c @@ -0,0 +1,182 @@ +/* \file syscalls-cfg-mem.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "syscalls-cfg-mem.h" +#include "devices.h" +#include "sched.h" +#include "debug.h" + +void sys_cfg_dev_map(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + uint8_t user_dev_id = (uint8_t) regs[1]; + device_t *dev = 0; + e_device_id dev_id; + + if (user_dev_id >= caller->num_devs ) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_MAP): invalid descriptor\n", caller->id); + goto ret_denied; + } + + dev_id = caller->dev_id[user_dev_id]; + + /* forbidden from ISR... */ + if (mode == TASK_MODE_ISRTHREAD) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_MAP): not allowed in SR mode\n", caller->id); + goto ret_denied; + } + + /* Should be out of initialization sequence */ + if (caller->init_done == false) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_MAP): not allowed before end of init\n", caller->id); + goto ret_denied; + return; + } + + /* check that the device is owned by the task */ + if (!(dev_get_task_from_id(dev_id) == caller->id)) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_MAP): device not owned by the task\n", caller->id); + /* no 'DENIED' to avoid detecting which devid is owned by other tasks */ + goto ret_inval; + return; + } + + dev = dev_get_device_from_id(dev_id); + if (dev->map_mode != DEV_MAP_VOLUNTARY) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_MAP): not a DEV_MAP_VOLUNTARY device\n", caller->id); + /* DEV_MAP_AUTO devices can't be (un)mapped */ + goto ret_denied; + } + + if (dev_is_mapped(dev_id)) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_MAP): device is already mapped\n", caller->id); + /* already mapped... */ + goto ret_busy; + } + + /* Okay now map the device */ + if (dev_set_device_map(true, dev_id) == FAILURE) { + /* max mapped devices already reached ! */ + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_MAP): unable to map device !\n", caller->id); + goto ret_busy; + } + // FIXME: the number of mapped device should be increased in the task_t struct (num_devs_mmaped + + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); + request_schedule(); + return; + + +ret_busy: + syscall_r0_update(caller, mode, SYS_E_BUSY); + syscall_set_target_task_runnable(caller); + return; + +ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; + +ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + return; + + +} + +void sys_cfg_dev_unmap(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + uint8_t user_dev_id = (uint8_t) regs[1]; + device_t *dev = 0; + e_device_id dev_id; + + if (user_dev_id >= caller->num_devs ) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_MAP): invalid descriptor\n", caller->id); + goto ret_denied; + } + + dev_id = caller->dev_id[user_dev_id]; + + /* forbidden from ISR... */ + if (mode == TASK_MODE_ISRTHREAD) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_UNMAP): not allowed in SR mode\n", caller->id); + goto ret_denied; + } + + /* Should be out of initialization sequence */ + if (caller->init_done == false) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_UNMAP): not allowed before end of init\n", caller->id); + goto ret_denied; + return; + } + + /* check that the device is owned by the task */ + if (!(dev_get_task_from_id(dev_id) == caller->id)) { + /* no 'DENIED' to avoid detecting which dev_id is owned by other tasks */ + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_UNMAP): device not owned by the task\n", caller->id); + goto ret_inval; + return; + } + + if (!dev_is_mapped(dev_id)) { + /* not already mapped... */ + goto ret_inval; + } + dev = dev_get_device_from_id(dev_id); + if (dev->map_mode != DEV_MAP_VOLUNTARY) { + KERNLOG(DBG_ERR, + "[task %d] sys_cfg(CFG_DEV_UNMAP): not a DEV_MAP_VOLUNTARY device\n", caller->id); + /* DEV_MAP_AUTO devices can't be (un)mapped */ + goto ret_denied; + } + + /* Okay now unmap the device. If already unmapped, nothing is done */ + dev_set_device_map(false, dev_id); + + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); + request_schedule(); + return; + +ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + return; + +ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; + +} diff --git a/syscalls/syscalls-cfg-mem.h b/syscalls/syscalls-cfg-mem.h new file mode 100644 index 0000000..7c53d4f --- /dev/null +++ b/syscalls/syscalls-cfg-mem.h @@ -0,0 +1,39 @@ +/* \file syscalls-cfg-mem.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SYSCALL_CFG_MEM_H +#define SYSCALL_CFG_MEM_H + +#include "syscalls.h" +#include "syscalls-utils.h" +#include "types.h" +#include "tasks.h" + +void sys_cfg_dev_map( task_t *caller, + __user regval_t *regs, + e_task_mode mode); + +void sys_cfg_dev_unmap( task_t *caller, + __user regval_t *regs, + e_task_mode mode); + +#endif/*!SYSCALL_CFG_MEM_H*/ diff --git a/syscalls/syscalls-cfg.c b/syscalls/syscalls-cfg.c new file mode 100644 index 0000000..aedf6de --- /dev/null +++ b/syscalls/syscalls-cfg.c @@ -0,0 +1,113 @@ +/* syscalls-cfg.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "autoconf.h" +#include "libc.h" +#include "tasks.h" +#include "sched.h" +#include "debug.h" +#include "softirq.h" +#include "soc-interrupts.h" +#include "soc-devmap.h" +#include "devices.h" +#include "devices-shared.h" +#include "mpu.h" +#include "gpio.h" +#include "apps_layout.h" +#include "syscalls-dma.h" +#include "sanitize.h" + +#ifdef CONFIG_ARCH_ARMV7M +#include "m4-core.h" +#else +#error "undefined core header for this arch!" +#endif + +#include "syscalls.h" +#include "syscalls-utils.h" +#include "syscalls-cfg.h" +#include "syscalls-cfg-gpio.h" +#include "syscalls-cfg-mem.h" + + + +#ifdef CONFIG_KERNEL_DMA_ENABLE +/**************************** +* DMA sys_cfg sycalls familly +*****************************/ + + + +#endif + + + +/* +** CFG type to define, please use register based, not buffer based to +** set type and content (r1, r2, r3, r4... r1 = target, r2 = ipctype, r3 = ipc arg1...) +*/ +void sys_cfg(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + uint32_t type = regs[0]; + // check that msg toward msg+size is in task's data section. + switch (type) { + case CFG_GPIO_SET: + KERNLOG(DBG_DEBUG, "[syscall][cfg][task %s] gpio set\n", caller->name); + sys_cfg_gpio_set(caller, regs, mode); + break; + case CFG_GPIO_GET: + KERNLOG(DBG_DEBUG, "[syscall][cfg][task %s] gpio get\n", caller->name); + sys_cfg_gpio_get(caller, regs, mode); + break; +#ifdef CONFIG_KERNEL_DMA_ENABLE + case CFG_DMA_RECONF: + KERNLOG(DBG_DEBUG, "[syscall][cfg][task %s] dma reconf\n", caller->name); + sys_cfg_dma_reconf(caller, regs, mode); + break; + case CFG_DMA_RELOAD: + KERNLOG(DBG_DEBUG, "[syscall][cfg][task %s] dma reload\n", caller->name); + sys_cfg_dma_reload(caller, regs, mode); + break; + case CFG_DMA_DISABLE: + KERNLOG(DBG_DEBUG, "[syscall][cfg][task %s] dma disable\n", caller->name); + sys_cfg_dma_disable(caller, regs, mode); + break; + +#endif + case CFG_DEV_MAP: + KERNLOG(DBG_DEBUG, "[syscall][cfg][task %s] device map\n", caller->name); + sys_cfg_dev_map(caller, regs, mode); + break; + case CFG_DEV_UNMAP: + KERNLOG(DBG_DEBUG, "[syscall][cfg][task %s] device unmap\n", caller->name); + sys_cfg_dev_unmap(caller, regs, mode); + break; + default: + KERNLOG(DBG_DEBUG, "[syscall][cfg][task %s] invalid!!\n", caller->name); + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + break; + } + return; +} + diff --git a/syscalls/syscalls-cfg.h b/syscalls/syscalls-cfg.h new file mode 100644 index 0000000..08cfc0d --- /dev/null +++ b/syscalls/syscalls-cfg.h @@ -0,0 +1,57 @@ +/* syscalls-cfg.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SYSCALLS_CFG_H_ +# define SYSCALLS_CFG_H_ + +#include "syscalls-cfg-mem.h" + +/** + * SYS_CFG syscall dispatcher familly. + * + * TODO: this dispatcher, like others, should be deleted to reduce the number + * of displatching sequence in the SVC/softirq syscalls execution + */ +void sys_cfg(task_t *caller, __user regval_t *regs, e_task_mode mode); + +/** + * \brief Set a given GPIO with a given value + * + * The value is normailzed in the function. + * + * \param[in/out] caller the task requesting the GPIO set + * \param[in] regs user params, containing the value to set + * + */ +void sys_cfg_gpio_set(task_t *caller, __user regval_t *regs, e_task_mode mode); + +/** + * \brief Get the current GPIO value + * + * \param[in/out] caller the caller requesting the GPIO + * \param[out] regs user params, containing the user pointer to set + */ +void sys_cfg_gpio_get(task_t *caller, __user regval_t *regs, e_task_mode mode); + + +#endif /*!SYSCALLS_CFG_H_*/ diff --git a/syscalls/syscalls-dma.c b/syscalls/syscalls-dma.c new file mode 100644 index 0000000..09ddfff --- /dev/null +++ b/syscalls/syscalls-dma.c @@ -0,0 +1,327 @@ +/* \file syscalls-dma.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "debug.h" +#include "devices.h" +#include "devices-shared.h" +#include "dma.h" +#include "sanitize.h" +#include "perm.h" +#include "libc.h" + +#include "syscalls.h" +#include "syscalls-utils.h" +#include "syscalls-dma.h" + +void init_do_reg_dma(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ +#ifdef CONFIG_KERNEL_DMA_ENABLE + __user dma_t *dma = (dma_t *) regs[1]; + int *descriptor = (int*) regs[2]; + e_dma_id dma_id = 0; + uint8_t ret; + + /* Generic sanitation of inputs */ + if (!sanitize_is_data_pointer_in_slot + ((void *)dma, sizeof(dma_t), caller->id, mode)) + { + goto ret_inval; + } + + if (!sanitize_is_pointer_in_slot ((void *)descriptor, caller->id, mode)) { + goto ret_inval; + } + + /* Is DMA allowed ? */ + if (!perm_ressource_is_granted(PERM_RES_DEV_DMA, caller->id)) { + goto ret_denied; + } + + /* check user content */ + ret = dma_sanitize_dma(dma, caller->id, (uint8_t)0, mode); + if (ret == 1) { + goto ret_inval; + } + + if (ret == 2) { + goto ret_denied; + } + + /* Check if Controller/Stream couple is already registered */ + if(dma_stream_is_already_registered(dma)) { + goto ret_busy; + } + + /* Does any user descriptor is available ?*/ + if (caller->num_dmas >= MAX_DMAS_PER_TASK) { + goto ret_busy; + } + + /* Initialization */ + ret = dma_init_dma(dma, caller->id, &dma_id); + if (ret != 0) { + goto ret_inval; + } + + caller->dma[caller->num_dmas] = dma_id; + *descriptor = (int) caller->num_dmas; + caller->num_dmas++; + + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); + return; + + ret_inval: + *descriptor = -1; + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + return; + + ret_busy: + *descriptor = -1; + syscall_r0_update(caller, mode, SYS_E_BUSY); + syscall_set_target_task_runnable(caller); + return; + + ret_denied: + *descriptor = -1; + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; + +#else + KERNLOG(DBG_INFO, "DMA not activated at config time\n"); + regs = regs; + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; +#endif +} + +/* +** syscall handling DMA SHM declaration between tasks +*/ +void init_do_reg_dma_shm(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ +#ifdef CONFIG_KERNEL_DMA_ENABLE + __user dma_shm_t *dma_shm = (dma_shm_t *)regs[1]; + uint8_t ret; + task_t *target_task = 0; + + /* Generic sanitation of inputs */ + if (!sanitize_is_data_pointer_in_slot((void *)dma_shm, sizeof(dma_shm_t), caller->id, mode)) { + goto ret_inval; + } + /* end of generic sanitation */ + /* check user content */ + ret = dma_shm_sanitize(dma_shm, caller->id, mode); + if (ret == 1) { + goto ret_inval; + } + + /*********************** + * Verifying permissions + ***********************/ + if (!perm_dmashm_is_granted(caller->id, dma_shm->target)) { + goto ret_denied; + } + + /* still place in the target task ? */ + target_task = task_get_task(dma_shm->target); + /* target_task is non-null because task_is_user() didn't fail */ + + if (target_task->num_dma_shms == MAX_DMA_SHM_PER_TASK) { + goto ret_busy; + } + + /* copy the SHM information into the target task */ + memcpy(&target_task->dma_shm[target_task->num_dma_shms++], dma_shm, sizeof(dma_shm_t)); + + KERNLOG(DBG_INFO, "DMA SHM has been declared by %s with %s (access mode %d)\n", caller->name, target_task->name, dma_shm->mode); + + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); + return; + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + return; + + ret_busy: + syscall_r0_update(caller, mode, SYS_E_BUSY); + syscall_set_target_task_runnable(caller); + return; + +ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; +#else + KERNLOG(DBG_INFO, "DMA not activated at config time\n"); + regs = regs; + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; +#endif +} + + +/* + * Reconfigure the DMA. A fully configure dma_t structure must be given. + */ +void sys_cfg_dma_reconf(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ +#ifdef CONFIG_KERNEL_DMA_ENABLE + uint8_t ret = 1; + dma_t *dma = (dma_t *) regs[1]; + uint8_t reconfmask = (uint8_t)regs[2]; + int desc = (int) regs[3]; + + /* Generic sanitation of inputs */ + if (!sanitize_is_data_pointer_in_slot + ((void *)dma, sizeof(dma_t), caller->id, mode)) { + goto ret_inval; + } + + /* The DMA user descriptor must be already defined in the task */ + if (desc < 0 || desc > (int) caller->num_dmas - 1) { + goto ret_inval; + } + + /* The DMA ctrl/channel/stream must be the same */ + if (!dma_same_dma_stream_channel (caller->dma[desc], dma)) { + goto ret_inval; + } + + /* check user content */ + ret = dma_sanitize_dma(dma, caller->id, (uint8_t)0, mode); // FIXME - reconfmask must be used + if (ret != 0) { + goto ret_inval; + } + + ret = dma_reconf_dma(dma, caller->dma[desc], reconfmask, caller->id); + if (ret != 0) { + goto ret_inval; + } + + syscall_r0_update(caller, mode, SYS_E_DONE); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + return; + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + + return; +#else + KERNLOG(DBG_INFO, "DMA not activated at config time\n"); + regs = regs; + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; +#endif +} + +/* +** Reload the DMA. Just set CR register CEN bit to 1 for the the given +** DMA if the task already owns it. +*/ +void sys_cfg_dma_reload(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ +#ifdef CONFIG_KERNEL_DMA_ENABLE + uint8_t ret = 1; + int desc = (int) regs[1]; + + /* The DMA user descriptor must be already defined in the task */ + if (desc < 0 || desc > (int) caller->num_dmas - 1) { + goto ret_inval; + } + + dma_enable_dma_stream(caller->dma[desc]); + ret = 0; + + syscall_r0_update(caller, mode, SYS_E_DONE); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + return; + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + return; +#else + KERNLOG(DBG_INFO, "DMA not activated at config time\n"); + regs = regs; + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; +#endif + +} + +/* +** Reset the DMA Stream. DMA is then disable. It can be reenable by +** IPC_DMA_RECONF syscall. +*/ +void sys_cfg_dma_disable(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ +#ifdef CONFIG_KERNEL_DMA_ENABLE + uint8_t ret = 1; + int desc = (int) regs[1]; + + /* The DMA user descriptor must be already defined in the task */ + if (desc < 0 || desc > (int) caller->num_dmas - 1) { + goto ret_inval; + } + + dma_disable_dma_stream(caller->dma[desc]); + ret = 0; + + syscall_r0_update(caller, mode, SYS_E_DONE); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + return; + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + return; +#else + KERNLOG(DBG_INFO, "DMA not activated at config time\n"); + regs = regs; + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; +#endif +} diff --git a/syscalls/syscalls-dma.h b/syscalls/syscalls-dma.h new file mode 100644 index 0000000..3773368 --- /dev/null +++ b/syscalls/syscalls-dma.h @@ -0,0 +1,46 @@ +/* syscalls-dma.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SYSCALLS_DMA_H_ +# define SYSCALLS_DMA_H_ + +#include "tasks.h" +#include "types.h" + +/* + * If KERNEL_DMA is disable, all these syscalls will return SYS_E_DENIED to + * the userspace, with a kernel log indicating that the kernel DMA support + * is not included. + */ + +void init_do_reg_dma(task_t *caller, __user regval_t *regs, e_task_mode mode); + +void init_do_reg_dma_shm(task_t *caller, __user regval_t *regs, e_task_mode mode); + +void sys_cfg_dma_reconf(task_t *caller, __user regval_t *regs, e_task_mode mode); + +void sys_cfg_dma_reload(task_t *caller, __user regval_t *regs, e_task_mode mode); + +void sys_cfg_dma_disable(task_t *caller, __user regval_t *regs, e_task_mode mode); + + +#endif /*!SYSCALLS_DMA_H_*/ diff --git a/syscalls/syscalls-gettick.c b/syscalls/syscalls-gettick.c new file mode 100644 index 0000000..1361521 --- /dev/null +++ b/syscalls/syscalls-gettick.c @@ -0,0 +1,84 @@ +/* syscalls-gettick.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "exported/syscalls.h" +#include "syscalls-gettick.h" +#include "syscalls-utils.h" +#include "sanitize.h" +#include "perm.h" +#include "soc-dwt.h" +#include "m4-core.h" + +void sys_gettick(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + uint64_t *val = (uint64_t *) regs[0]; + e_tick_type prec = (e_tick_type) regs[1]; + + if (!sanitize_is_pointer_in_slot((void *)val, caller->id, mode)) { + goto ret_inval; + } + + switch (prec) { + case PREC_MILLI: + if (!perm_ressource_is_granted(PERM_RES_TIM_GETMILLI, caller->id)) { + goto ret_denied; + } + *val = core_systick_get_ticks(); + break; + case PREC_MICRO: + if (!perm_ressource_is_granted(PERM_RES_TIM_GETMICRO, caller->id)) { + goto ret_denied; + } + *val = soc_dwt_getcycles_64() / MAIN_CLOCK_FREQUENCY_US; + break; + case PREC_CYCLE: + if (!perm_ressource_is_granted(PERM_RES_TIM_GETCYCLE, caller->id)) { + goto ret_denied; + } + *val = soc_dwt_getcycles_64(); + break; + default: + goto ret_inval; + } + + + syscall_r0_update(caller, mode, SYS_E_DONE); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + return; + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + return; + + ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + return; +} diff --git a/syscalls/syscalls-gettick.h b/syscalls/syscalls-gettick.h new file mode 100644 index 0000000..32965fb --- /dev/null +++ b/syscalls/syscalls-gettick.h @@ -0,0 +1,36 @@ +/* \file syscalls-gettick.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SYSCALL_GETTICK +# define SYSCALL_GETTICK + +#include "syscalls-utils.h" +#include "tasks.h" +#include "types.h" + +/* +** Return the current timer tick. +*/ +void sys_gettick(task_t *caller, __user regval_t *regs, e_task_mode mode); + +#endif/*!SYSCALL_GETTICK*/ diff --git a/syscalls/syscalls-init.c b/syscalls/syscalls-init.c new file mode 100644 index 0000000..ebdd91d --- /dev/null +++ b/syscalls/syscalls-init.c @@ -0,0 +1,289 @@ +/* \file syscalls-init.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "syscalls-init.h" +#include "exported/syscalls.h" +#include "syscalls-utils.h" +#include "sanitize.h" +#include "perm.h" +#include "libc.h" +#include "sched.h" +#include "debug.h" +#include "softirq.h" +#include "soc-interrupts.h" +#include "soc-devmap.h" +#include "devices.h" +#include "devices-shared.h" +#include "mpu.h" +#include "gpio.h" +#include "apps_layout.h" +#include "syscalls-dma.h" +#include "dma.h" +#include "sanitize.h" + + +void init_do_get_taskid(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + const char *task_name = (const char *)regs[1]; + uint32_t *id = (uint32_t *) regs[2]; + task_t *tasks_list = NULL; + + /* Generic sanitation of inputs */ + // TODO: there is a security risk here: as there is no string size, we can't check + // that the string is fully in the task's slot. This means that this is possible to + // get back the value of the first bytes of the data of the next task, up to the + // max task name's size (fixed max size is 16 bytes). Here I only check that there is + // at least 4 bytes of string in the slot (3 chars length string). + + //if (!sanitize_is_pointer_in_slot((void*)task_name, t->id)) { + // goto ret_inval; + //} + + if (!sanitize_is_pointer_in_slot((void *)id, caller->id, mode)) { + goto ret_inval; + } + + /* End of generic sanitation */ + if (caller->init_done == true) { + syscall_r0_update(caller, TASK_MODE_MAINTHREAD, SYS_E_DENIED); + caller->state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + return; + } + + tasks_list = task_get_tasks_list(); + + for (e_task_id peer = ID_APP1; peer <= ID_APP7; ++peer) { + if (strcasecmp(task_name, tasks_list[peer].name) == 0) { +#ifdef CONFIG_KERNEL_DOMAIN + /* Checking domain */ + if (!perm_same_ipc_domain(caller->id, peer)) { + goto done; + } +#endif + *id = peer; + goto done; + } + } + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + + done: + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); +} + + +void init_do_reg_devaccess(e_task_id caller_id, __user regval_t *regs, e_task_mode mode) +{ + /* + * User defined device struct 'udev' has two roles: + * - it is used by a user task to register and to configure a new device + * in the kernel + * - the kernel uses it to return some informations to the user task + */ + __user device_t *udev = (device_t *) regs[1]; + __user int *descriptor = (int*) regs[2]; + + e_device_id device_id; + uint8_t ret; + task_t *caller; + + caller = task_get_task(caller_id); + if (caller == NULL) { + panic("init_do_reg_devaccess(): invalid task id %d\n", caller_id); + } + + if (task_is_user(caller_id)) { + /* Generic sanitation of inputs */ + if (!sanitize_is_data_pointer_in_slot((void *)udev, sizeof(device_t), caller->id, mode)) { + KERNLOG(DBG_ERR, "invalid pointer given in argument\n"); + goto ret_inval; + } + + if (!sanitize_is_pointer_in_slot ((void *)descriptor, caller->id, mode)) + { + goto ret_inval; + } + + + /* Check user content */ + ret = dev_sanitize_user_device(udev, caller->id); + if (ret != SUCCESS) { + KERNLOG(DBG_ERR, "invalid device datas or permission is denied\n"); + goto ret_denied; + } + } + + /* Enough place */ + if (udev->size != 0 && + udev->map_mode == DEV_MAP_AUTO && + caller->num_devs_mmapped >= MPU_MAX_EMPTY_REGIONS) + { + KERNLOG(DBG_ERR, "No more free space in task for device\n"); + goto ret_busy; + } + + /* + * Register a user device + */ + + device_id = dev_get_free_device_slot(caller_id, udev); + if (device_id == ID_DEV_UNUSED) { + KERNLOG(DBG_ERR, "No more free space in kernel for device\n"); + dbg_flush(); + goto ret_busy; + } + + caller->dev_id[caller->num_devs] = device_id; // FIXME - overflow + + if (udev->size != 0 && udev->map_mode == DEV_MAP_AUTO) { + caller->num_devs_mmapped++; + } + + /* Identifier to transmit to userspace */ + *descriptor = caller->num_devs; + + caller->num_devs++; // FIXME - overflow + + ret = dev_register_gpios(device_id, caller_id); + if (ret == 1) { + KERNLOG(DBG_ERR, "[%s] init_do_reg_devaccess() failed\n", caller->name); + dev_release_device_slot (device_id); + caller->num_devs--; + caller->dev_id[caller->num_devs] = ID_DEV_UNUSED; + goto ret_inval; + } + if (ret == 2) { + KERNLOG(DBG_ERR, "[%s] init_do_reg_devaccess() failed\n", caller->name); + dev_release_device_slot (device_id); + caller->num_devs--; + caller->dev_id[caller->num_devs] = ID_DEV_UNUSED; + goto ret_busy; + } + + ret = dev_register_handlers(device_id, caller_id); + if (ret != 0) { + dev_release_device_slot (device_id); + caller->num_devs--; + caller->dev_id[caller->num_devs] = ID_DEV_UNUSED; + goto ret_inval; + } + + /* + * Finalize device registration and return some device informations to the + * user task via 'udev' struct + */ + ret = dev_register_device(device_id, udev); + if (ret != 0) { + dev_release_device_slot (device_id); + caller->num_devs--; + caller->dev_id[caller->num_devs] = ID_DEV_UNUSED; + goto ret_busy; + } + + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); + return; + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + return; + + ret_busy: + syscall_r0_update(caller, mode, SYS_E_BUSY); + syscall_set_target_task_runnable(caller); + return; + + ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; +} + + +static void init_do_done(task_t *caller, e_task_mode mode) +{ + // activate all devices + for (uint8_t i = 0; i < caller->num_devs; ++i) { + dev_enable_device(caller->dev_id[i]); + } + +#if CONFIG_KERNEL_DMA_ENABLE + for (uint8_t i = 0; i < caller->num_dmas; ++i) { + dma_enable_dma_irq(caller->dma[i]); + } +#endif + + caller->init_done = true; + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); + /* init_done always request a scheduling to make devices mapped + * at next execution time of the task + */ + request_schedule(); +} + +/* +** Initialize the userspace task device and handler access. Also lock initialize sequence. +*/ +void sys_init(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + regval_t type = regs[0]; + + // sanitation + // check that msg toward msg+size is in task's data section. + if (caller->init_done == true) { + syscall_r0_update(caller, mode, SYS_E_DENIED); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; + } + + switch (type) { + case INIT_DEVACCESS: + init_do_reg_devaccess(caller->id, regs, mode); + break; +#ifdef CONFIG_KERNEL_DMA_ENABLE + case INIT_DMA: + init_do_reg_dma(caller, regs, mode); + break; + case INIT_DMA_SHM: + init_do_reg_dma_shm(caller, regs, mode); + break; +#endif + case INIT_GETTASKID: + init_do_get_taskid(caller, regs, mode); + break; + case INIT_DONE: + init_do_done(caller, mode); + break; + default: + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + break; + } + return; +} + diff --git a/syscalls/syscalls-init.h b/syscalls/syscalls-init.h new file mode 100644 index 0000000..e87271c --- /dev/null +++ b/syscalls/syscalls-init.h @@ -0,0 +1,49 @@ +/* syscalls-init.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SYSCALLS_INIT +#define SYSCALLS_INIT + +#include "kernel.h" +#include "tasks.h" + + +void init_do_get_taskid(task_t *caller, __user regval_t *regs, e_task_mode mode); + +/* +** Userspace task device and handler registration initialization +** and locking +*/ +void sys_init(task_t * t, regval_t * regs, e_task_mode mode); + +/* +** Also used by kernel to declare its own devices in devices.c. In this case, +** the kernel use DEV_KERNEL as a third argument. +*/ +void init_do_reg_devaccess(e_task_id caller_id, __user regval_t *regs, e_task_mode mode); + + +static void init_do_done(task_t *caller, e_task_mode mode); + + +#endif /* SYSCALLS_GET_TASKID_ */ diff --git a/syscalls/syscalls-ipc.c b/syscalls/syscalls-ipc.c new file mode 100644 index 0000000..a45d221 --- /dev/null +++ b/syscalls/syscalls-ipc.c @@ -0,0 +1,553 @@ +/* \file syscalls-ipc.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "libc.h" +#include "syscalls.h" +#include "tasks.h" +#include "softirq.h" +#include "ipc.h" +#include "sched.h" +#include "perm.h" +#include "sanitize.h" +#include "debug.h" +#include "sleep.h" + + +void ipc_do_recv(task_t *caller, __user regval_t *regs, bool blocking, e_task_mode mode) { + ipc_endpoint_t *ep = NULL; + task_t *sender = NULL; + + /* Sender id. That field is mandatory to know who is the sender. + * The 'id_sender' is thus also used to inform the receiver about who sent + * a message in the case where the receiver was listening to any task. */ + e_task_id *id_sender = (e_task_id *) regs[1]; + + /* Pointer to buffer size. Also used to return the number of bytes written + * by the sender. */ + logsize_t *size = (logsize_t *) regs[2]; + + /* Buffer address */ + char *buf = (char *)regs[3]; + + /* Debug */ + KERNLOG(DBG_DEBUG, + "DEBUG: ipc_do_recv() task %d <- task %d\n", caller->id, *id_sender); + + /*********************** + * Verifying parameters + ***********************/ + + if (mode == TASK_MODE_ISRTHREAD) { + KERNLOG(DBG_ERR, "[task %d] ipc_do_recv(): making IPCs while in ISR mode is not allowed!\n", caller->id); + goto ret_denied; + } + + /* Test if task initialization is complete */ + if (caller->init_done == false) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_recv(): initialization not completed\n", caller->id); + goto ret_denied; + } + + /* Verifying &size is in caller address space */ + if (!sanitize_is_pointer_in_slot((void *)size, caller->id, mode)) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_recv(): size (%x) is not in caller space\n", caller->id, size); + goto ret_inval; + } + + /* Verifying &id_sender is in caller address space */ + if (!sanitize_is_pointer_in_slot((void *)id_sender, caller->id, mode)) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_recv(): id_sender (%x) is not in caller space\n", caller->id, id_sender); + goto ret_inval; + } + + /* Verifying that the id corresponds to a user task */ + if (!task_is_user(*id_sender) && *id_sender != ANY_APP) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_recv(): invalid id_sender (%d)\n", caller->id, *id_sender); + goto ret_inval; + } + + if (*id_sender != ANY_APP) { + sender = task_get_task(*id_sender); + if (sender == NULL || + sender->state[TASK_MODE_MAINTHREAD] == TASK_STATE_EMPTY) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_recv(): invalid sender (%d) - empty task\n", caller->id, *id_sender); + goto ret_inval; + } + } + + /* A task can't send a message to itself */ + if (caller->id == *id_sender) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_recv(): invalid id_sender (%d) - same as caller->id\n", caller->id, *id_sender); + goto ret_inval; + } + + /* + * Verifying permissions + */ + + if (*id_sender != ANY_APP) { + +#ifdef CONFIG_KERNEL_DOMAIN + if (!perm_same_ipc_domain(*id_sender, caller->id)) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_recv(): sender %d domain not granted\n", caller->id, *id_sender); + goto ret_denied; + } +#endif + + if (!perm_ipc_is_granted(*id_sender, caller->id)) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_recv(): not granted to listen sender %d\n", caller->id, *id_sender); + goto ret_denied; + } + } + + /* Verifying that &buf is in caller address space. + * Important note: the sender can transmit a void message to send a + * notification. In that case, that sanatization step is not required. */ + if (*size) { + if (!sanitize_is_data_pointer_in_slot((void *)buf, *size, caller->id, mode)) { + KERNLOG(DBG_ERR, + "ipc_do_recv(): buffer (%x - %x) not in caller (%d) space\n", buf, buf + *size, caller->id); + goto ret_inval; + } + } + + /*************************** + * Defining an IPC EndPoint + ***************************/ + + ep = NULL; + + /* Listening to ANY_APP is a special case. + * The receiver may have already received any message. Thus, + * we have to look for the IPC endpoints with a pending message. */ + if (*id_sender == ANY_APP) { + for (int i=ID_APP1; i<=ID_APP7; i++) { + if (caller->ipc_endpoint[i] != NULL && + caller->ipc_endpoint[i]->state == WAIT_FOR_RECEIVER && + caller->ipc_endpoint[i]->to == caller->id) { + ep = caller->ipc_endpoint[i]; + break; /* read data on the endpoint */ + } + } + } + /* Listening to an identified user task (ID_APP*) */ + else { + if (caller->ipc_endpoint[*id_sender] != NULL && + caller->ipc_endpoint[*id_sender]->state == WAIT_FOR_RECEIVER && + caller->ipc_endpoint[*id_sender]->to == caller->id) { + ep = caller->ipc_endpoint[*id_sender]; + } + } + + /********************** + * Reading the message + **********************/ + + /* If there is no pending message to read, we terminate here */ + if (ep == NULL) { + /* Waking up idle senders */ + if (*id_sender != ANY_APP && + sender->state[TASK_MODE_MAINTHREAD] == TASK_STATE_IDLE) + { + sender->state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + } + + /* Receiver is blocking until it receives a message or it returns + * E_SYS_BUSY */ + if (blocking) { + caller->state[TASK_MODE_MAINTHREAD] = TASK_STATE_IPC_RECV_BLOCKED; + return; + } else { + goto ret_busy; + } + } + + /* + * A message was sent. First, we verify that the caller is granted + * to read a message sent by the sender in the specific case of a recv(ANY) + */ + + if (*id_sender == ANY_APP) { + + /* The caller is not allowed to read a message from the sender */ + if (!perm_ipc_is_granted(ep->from, caller->id)) { + + KERNLOG(DBG_ERR, + "[task %d] ipc_do_recv(): sender %d not granted\n", + caller->id, ep->from); + + /* Free sender from it's blocking state */ + syscall_r0_update(sender, TASK_MODE_MAINTHREAD, SYS_E_DENIED); + sender->state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + + /* Receiver is blocking until it receives a message or it returns + * E_SYS_BUSY */ + if (blocking) { + caller->state[TASK_MODE_MAINTHREAD] = TASK_STATE_IPC_RECV_BLOCKED; + return; + } else { + goto ret_busy; + } + } + } + + /* The syscall returns the sender ID */ + *id_sender = ep->from; + + sender = task_get_task(ep->from); + if (sender == NULL || + sender->state[TASK_MODE_MAINTHREAD] == TASK_STATE_EMPTY) + { + panic("[task %d] invalid sender (%d) - empty task\n", caller->id, *id_sender); + } + + /* Copying the message in the receiver's buffer */ + if (ep->size > *size) { + KERNLOG(DBG_ERR, + "ipc_do_recv(): IPC message overflows: receiver's (%x) buffer is too small (%d > %d)\n", caller->id, ep->size, *size); + *size = ep->size; + goto ret_inval; + } + + memcpy(buf, ep->data, ep->size); + + /* Returning the data size */ + *size = ep->size; + + /* The EndPoint is ready for another use */ + ep->state = READY; + ep->size = 0; + + /* Free sender from it's blocking state */ + switch (sender->state[TASK_MODE_MAINTHREAD]) { + case TASK_STATE_IPC_WAIT_ACK: + syscall_r0_update(sender, TASK_MODE_MAINTHREAD, SYS_E_DONE); + sender->state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + break; + + case TASK_STATE_IPC_SEND_BLOCKED: + sender->state[TASK_MODE_MAINTHREAD] = TASK_STATE_SVC_BLOCKED; + softirq_query(SFQ_SYSCALL, sender->id, 0, 0, 0); + task_set_task_state(ID_SOFTIRQ, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + break; + + default: + break; + } + + syscall_r0_update(caller, mode, SYS_E_DONE); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; + + ret_busy: + syscall_r0_update(caller, mode, SYS_E_BUSY); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; + + ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; +} + + +void ipc_do_send(task_t *caller, __user regval_t *regs, bool blocking, e_task_mode mode) +{ + ipc_endpoint_t *ep = NULL; + task_t *receiver = NULL; + + /* Receiver id. Mandatory to know who is the receiver */ + e_task_id id_receiver = (e_task_id) regs[1]; + + /* Buffer size */ + logsize_t size = (logsize_t)regs[2]; + + /* Buffer address */ + char *buf = (char *)regs[3]; + + /* Debug */ + KERNLOG(DBG_DEBUG, + "DEBUG: ipc_do_send() task %d -> task %d\n", caller->id, id_receiver); + + /*********************** + * Verifying parameters + ***********************/ + + if (mode == TASK_MODE_ISRTHREAD) { + KERNLOG(DBG_ERR, "[task %d] ipc_do_send(): making IPCs while in ISR mode is not allowed!\n", caller->id); + goto ret_denied; + } + + /* Test if task initialization is complete */ + if (caller->init_done == false) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_send(): initialization not completed\n", + caller->id); + goto ret_denied; + } + + /* Verifying that &buf is in caller address space. + * Important note: the sender can transmit a void message to send a + * notification. In that case, that sanatization step is not required. */ + if (size) { + if (!sanitize_is_data_pointer_in_any_slot((void *)buf, size, caller->id, mode)) { + KERNLOG(DBG_ERR, + "ipc_do_send(): buffer (%x - %x) not in caller (%d) space\n", + buf, buf + size, caller->id); + goto ret_inval; + } + } + + /* Verifying that the receiver id corresponds to a user task */ + if (!task_is_user(id_receiver)) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_send(): invalid id_receiver (%d)\n", + caller->id, id_receiver); + goto ret_inval; + } + + receiver = task_get_task(id_receiver); + + /* Verifying that the receiver is valid */ + if (receiver == NULL || + receiver->state[TASK_MODE_MAINTHREAD] == TASK_STATE_EMPTY) + { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_send(): invalid receiver (%d) - empty task\n", caller->id, id_receiver); + goto ret_inval; + } + + /* A task can't send a message to itself */ + if (caller->id == id_receiver) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_send(): invalid id_receiver (%d) - same as caller->id\n", caller->id, id_receiver); + goto ret_inval; + } + + /* Is size valid ? */ + if (size > MAX_IPC_MSG) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_send(): invalid size (%d > %d)\n", + caller->id, size, MAX_IPC_MSG); + goto ret_inval; + } + + /* + * Verifying permissions + */ + +#ifdef CONFIG_KERNEL_DOMAIN + if (!perm_same_ipc_domain(caller->id, id_receiver)) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_send(): receiver domain %d not granted\n", caller->id, id_receiver); + goto ret_denied; + } +#endif + + if (!perm_ipc_is_granted(caller->id, id_receiver)) { + KERNLOG(DBG_ERR, + "[task %d] ipc_do_send(): receiver %d not granted\n", caller->id, id_receiver); + goto ret_denied; + } + + + /*************************** + * Defining an IPC EndPoint + ***************************/ + + ep = NULL; + + /* Creating a new IPC endpoint between the sender and the receiver */ + if (caller->ipc_endpoint[id_receiver] == NULL) { + if (receiver->ipc_endpoint[caller->id] != NULL) { + panic("ipc_do_send(): IPC endpoint already defined by the receiver"); + } + ep = ipc_get_endpoint(); + if (ep == NULL) { + panic("ipc_do_send(): impossible to create a new IPC endpoint"); + } + caller->ipc_endpoint[id_receiver] = ep; + receiver->ipc_endpoint[caller->id] = ep; + } + /* Reusing an already existing EndPoint */ + else { + ep = caller->ipc_endpoint[id_receiver]; + } + + /******************** + * Sending a message + ********************/ + + /* Wake up idle receivers */ + if (sleep_is_sleeping_task(receiver->id)) { + sleep_try_waking_up(receiver->id); + } else { + if (receiver->state[TASK_MODE_MAINTHREAD] == TASK_STATE_IDLE) { + receiver->state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + } + } + + /* The receiver has already a pending message and the endpoint is + * already in use. */ + if (ep->state == WAIT_FOR_RECEIVER && ep->to == id_receiver) { + if (blocking) { + caller->state[TASK_MODE_MAINTHREAD] = TASK_STATE_IPC_SEND_BLOCKED; +#ifdef CONFIG_SCHED_SUPPORT_FIPC + syscall_set_target_task_forced(receiver); +#endif + return; + } else { + goto ret_busy; + } + } + + if (ep->state != READY) { + panic("ipc_do_send(): invalid IPC endpoint state"); + } + + ep->from = caller->id; + ep->to = id_receiver; + + /* We copy the message in the IPC buffer */ + memcpy(ep->data, buf, size); + ep->size = size; + + /* Adjusting the EndPoint state */ + ep->state = WAIT_FOR_RECEIVER; + + /* If the receiver was blocking, it can be 'freed' from its blocking + * state. We reinject it so that it can fulfill its syscall */ + if (receiver->state[TASK_MODE_MAINTHREAD] == TASK_STATE_IPC_RECV_BLOCKED) { + receiver->state[TASK_MODE_MAINTHREAD] = TASK_STATE_SVC_BLOCKED; + softirq_query(SFQ_SYSCALL, receiver->id, 0, 0, 0); + task_set_task_state(ID_SOFTIRQ, TASK_MODE_MAINTHREAD, TASK_STATE_RUNNABLE); + } + + if (blocking) { + caller->state[TASK_MODE_MAINTHREAD] = TASK_STATE_IPC_WAIT_ACK; +#ifdef CONFIG_SCHED_SUPPORT_FIPC + syscall_set_target_task_forced(receiver); +#endif + return; + } + else { + syscall_r0_update(caller, mode, SYS_E_DONE); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; + } + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; + + ret_busy: + syscall_r0_update(caller, mode, SYS_E_BUSY); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; + + ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; +} + +static inline void ipc_do_log(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + uint32_t size = regs[2]; + uint32_t msg = regs[3]; + + /* Generic sanitation of inputs */ + if (!sanitize_is_data_pointer_in_slot((void*)msg, size, caller->id, mode)) { + goto ret_inval; + } + + /* end of generic sanitation */ + if (size >= 512) { + goto ret_inval; + } + + dbg_log("[%s] ", caller->name); + dbg_log((char*)msg); + dbg_flush(); + syscall_r0_update(caller, mode, SYS_E_DONE); + syscall_set_target_task_runnable(caller); + return; + + ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + return; +} + +/* +** IPC type to define, please use register based, not buffer based to +** set type and content (r1, r2, r3, r4... r1 = target, r2 = ipctype, r3 = ipc arg1...) +*/ +void sys_ipc(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + uint32_t type = regs[0]; + // check that msg toward msg+size is in task's data section. + switch (type) { + case IPC_LOG: + KERNLOG(DBG_DEBUG, "[syscall][ipc][task %s] ipc log\n", caller->name); + ipc_do_log(caller, regs, mode); + break; + case IPC_RECV_SYNC: + KERNLOG(DBG_DEBUG, "[syscall][ipc][task %s] recv sync\n", caller->name); + ipc_do_recv(caller, regs, true, mode); /* blocking */ + break; + case IPC_SEND_SYNC: + KERNLOG(DBG_DEBUG, "[syscall][ipc][task %s] send sync\n", caller->name); + ipc_do_send(caller, regs, true, mode); /* blocking */ + break; + case IPC_RECV_ASYNC: + KERNLOG(DBG_DEBUG, "[syscall][ipc][task %s] recv async\n", caller->name); + ipc_do_recv(caller, regs, false, mode); /* not blocking */ + break; + case IPC_SEND_ASYNC: + KERNLOG(DBG_DEBUG, "[syscall][ipc][task %s] send async\n", caller->name); + ipc_do_send(caller, regs, false, mode); /* not blocking */ + break; + default: + KERNLOG(DBG_DEBUG, "[syscall][ipc][task %s] invalid!!\n", caller->name); + syscall_r0_update(caller, mode, SYS_E_INVAL); + syscall_set_target_task_runnable(caller); + break; + } + return; +} + diff --git a/syscalls/syscalls-ipc.h b/syscalls/syscalls-ipc.h new file mode 100644 index 0000000..5d5be8e --- /dev/null +++ b/syscalls/syscalls-ipc.h @@ -0,0 +1,30 @@ +/* syscalls-ipc.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SYSCALLS_IPC_ +# define SYSCALLS_IPC_ + +void ipc_do_recv(task_t *, __user regval_t *, bool, e_task_mode); +void ipc_do_send(task_t *, __user regval_t *, bool, e_task_mode); + +#endif /* !SYSCALLS_IPC_*/ diff --git a/syscalls/syscalls-lock.c b/syscalls/syscalls-lock.c new file mode 100644 index 0000000..c1023d6 --- /dev/null +++ b/syscalls/syscalls-lock.c @@ -0,0 +1,74 @@ +/* syscalls-lock.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "exported/syscalls.h" +#include "syscalls-utils.h" +#include "syscalls-yield.h" +#include "tasks.h" +#include "sched.h" + +/* + * The task requires to lock its ISR execution for a moment, for e.g. while + * manipulating a specific shared variable for a short time during which a + * race condition is possible. + * ISR are not deleted but only postponed, which require the lock to be keeped + * only for a very short time. + * This syscall is a complement to the userspace semaphore implementation. + */ +void sys_lock(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + e_lock_type lockmode = regs[0]; + + if (mode == TASK_MODE_ISRTHREAD) { + goto ret_denied; + } + + + switch (lockmode) { + case LOCK_ENTER: + syscall_r0_update(caller, mode, SYS_E_DONE); + caller->state[mode] = TASK_STATE_LOCKED; + break; + case LOCK_EXIT: + syscall_r0_update(caller, mode, SYS_E_DONE); + caller->state[mode] = TASK_STATE_RUNNABLE; + break; + default: + goto ret_inval; + break; + } + + syscall_r0_update(caller, mode, SYS_E_DONE); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; + +ret_denied: + /* ISR mode, state do not need to be updated */ + syscall_r0_update(caller, mode, SYS_E_DENIED); + return; + +ret_inval: + syscall_r0_update(caller, mode, SYS_E_INVAL); + caller->state[mode] = TASK_STATE_RUNNABLE; + return; +} diff --git a/syscalls/syscalls-lock.h b/syscalls/syscalls-lock.h new file mode 100644 index 0000000..fd7d6f3 --- /dev/null +++ b/syscalls/syscalls-lock.h @@ -0,0 +1,33 @@ +/* \file syscalls-gettick.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SYSCALL_LOCK +# define SYSCALL_LOCK + +#include "syscalls-utils.h" +#include "tasks.h" +#include "types.h" + +void sys_lock(task_t *caller, __user regval_t *regs, e_task_mode mode); + +#endif /*!SYSCALL_LOCK*/ diff --git a/syscalls/syscalls-reset.c b/syscalls/syscalls-reset.c new file mode 100644 index 0000000..02e8187 --- /dev/null +++ b/syscalls/syscalls-reset.c @@ -0,0 +1,41 @@ +/* syscalls-reset.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "exported/syscalls.h" +#include "syscalls-utils.h" +#include "syscalls-reset.h" +#include "perm.h" +#include "tasks.h" +#include "soc-nvic.h" + +void sys_reset(task_t *caller, e_task_mode mode) +{ + if (!perm_ressource_is_granted(PERM_RES_TSK_RESET, caller->id)) { + goto ret_denied; + } + NVIC_SystemReset(); +ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + syscall_set_target_task_runnable(caller); + return; +} diff --git a/syscalls/syscalls-reset.h b/syscalls/syscalls-reset.h new file mode 100644 index 0000000..f9d1262 --- /dev/null +++ b/syscalls/syscalls-reset.h @@ -0,0 +1,40 @@ +/* syscalls-reset.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SYSCALLS_RESET +# define SYSCALLS_RESET + +#include "tasks.h" +#include "types.h" + + + +/* + * The task requires to reset the board. + * This happends when detecting invalid/dangerous behaviors requiring + * fast reaction from the device. This syscall is associated to a specific + * permission. + */ +void sys_reset(task_t *caller, e_task_mode mode); + +#endif/*!SYSCALLS_RESET*/ diff --git a/syscalls/syscalls-sleep.c b/syscalls/syscalls-sleep.c new file mode 100644 index 0000000..6b5996a --- /dev/null +++ b/syscalls/syscalls-sleep.c @@ -0,0 +1,57 @@ +/* syscalls-sleep.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "exported/syscalls.h" +#include "syscalls-utils.h" +#include "syscalls-sleep.h" +#include "perm.h" +#include "tasks.h" +#include "sleep.h" +#include "sanitize.h" +#include "sched.h" + +void sys_sleep(task_t *caller, __user regval_t *regs, e_task_mode mode) +{ + /* ISRs can't sleep */ + if (mode == TASK_MODE_ISRTHREAD) { + goto ret_denied; + } + uint32_t sleeptime = (uint32_t) regs[0]; + sleep_mode_t sleepmode = (sleep_mode_t) regs[1]; + + sleeping(caller->id, sleeptime, sleepmode); + + /* Set caller as SLEEPING */ + syscall_r0_update(caller, mode, SYS_E_DONE); + task_set_task_state(caller->id, mode, TASK_STATE_SLEEPING); + /* request schedule, as current task is no more executable */ + request_schedule(); + return; + +ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + if (mode != TASK_MODE_ISRTHREAD) { + syscall_set_target_task_runnable(caller); + } + return; +} diff --git a/syscalls/syscalls-sleep.h b/syscalls/syscalls-sleep.h new file mode 100644 index 0000000..c83b1a4 --- /dev/null +++ b/syscalls/syscalls-sleep.h @@ -0,0 +1,31 @@ +/* \file syscalls-sleep.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef SYSCALLS_SLEEP_H_ +# define SYSCALLS_SLEEP_H_ + +#include "tasks.h" +#include "types.h" + +void sys_sleep(task_t *caller, __user regval_t *regs, e_task_mode mode); + +#endif/*!SYSCALLS_SLEEP_H_*/ diff --git a/syscalls/syscalls-utils.h b/syscalls/syscalls-utils.h new file mode 100644 index 0000000..bf6a39d --- /dev/null +++ b/syscalls/syscalls-utils.h @@ -0,0 +1,77 @@ +/* \file syscalls-utils.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SYSCALLS_UTILS_H +# define SYSCALLS_UTILS_H + +#include "exported/syscalls.h" +#include "tasks.h" + +/** + * Syscall mode (syscall (svc 0) or fastcall (svc 3)) + */ +typedef enum { + SYS_CALL_MODE, + FAST_CALL_MODE +} t_call_mode; + +/* + * This function update the target task's state. + * + * CAUTION ! + * - Target task might currently be in ISR mode (state == + * TASK_STATE_RUNNABLE or state == TASK_STATE_ISR_DONE). In theory, it's state should + * not be updated. But as it will be automatically set as runnable by the + * scheduler when returning in THREAD mode, it causes no problem. + */ +static inline void syscall_set_target_task_runnable (task_t *target) +{ + if (target->state[TASK_MODE_MAINTHREAD] == TASK_STATE_SVC_BLOCKED || + target->state[TASK_MODE_MAINTHREAD] == TASK_STATE_IDLE) { + target->state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + } +} + +#ifdef CONFIG_SCHED_SUPPORT_FIPC +static inline void syscall_set_target_task_forced (task_t * t) +{ + if (t->state[TASK_MODE_MAINTHREAD] == TASK_STATE_RUNNABLE || + t->state[TASK_MODE_MAINTHREAD] == TASK_STATE_IDLE) { + t->state[TASK_MODE_MAINTHREAD] = TASK_STATE_FORCED; + } + +} +#endif + +/* +** Update the user r0 register for syscall return value +*/ +static inline void syscall_r0_update(task_t * t, e_task_mode mode, e_syscall_ret val) +{ + /* This task (or any of its handlers) should not be executed while + ** updating the return value. It is, as softirq_syscall_handler deactivate + ** irq by now. */ + t->ctx[mode].frame->r0 = val; +} + +#endif diff --git a/syscalls/syscalls-yield.c b/syscalls/syscalls-yield.c new file mode 100644 index 0000000..c1909d9 --- /dev/null +++ b/syscalls/syscalls-yield.c @@ -0,0 +1,55 @@ +/* syscalls-yield.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "exported/syscalls.h" +#include "syscalls-utils.h" +#include "syscalls-yield.h" +#include "tasks.h" +#include "sched.h" + +/* + * The task requires to terminate its current execution. The task is set + * freezed while no IPC targetting it or interrupt already registered by it or is + * received by the kernel. + * If such IPC/interrupt arise, the task is set schedulable again and the it is executed + */ +void sys_yield(task_t *caller, e_task_mode mode) +{ + /* an ISR must not yield. There is no logic to that ! */ + if (mode == TASK_MODE_ISRTHREAD) { + goto ret_denied; + } + /* + * The main() function of the task is now finished. Instead of destroying improperly + * the task and its stack, this function help it by releasing the processor and giving + * it back to the kernel + */ + syscall_r0_update(caller, mode, SYS_E_DONE); + caller->state[mode] = TASK_STATE_IDLE; + request_schedule(); + return; +ret_denied: + syscall_r0_update(caller, mode, SYS_E_DENIED); + return; +} + diff --git a/syscalls/syscalls-yield.h b/syscalls/syscalls-yield.h new file mode 100644 index 0000000..96eb1b7 --- /dev/null +++ b/syscalls/syscalls-yield.h @@ -0,0 +1,39 @@ +/* syscalls-yield.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SYSCALLS_YIELD +# define SYSCALLS_YIELD + +#include "tasks.h" +#include "types.h" + +/* + * The task requires to terminate its current execution. The task is set + * freezed while no IPC targetting it or interrupt already registered by + * it or is received by the kernel. + * If such IPC/interrupt arise, the task is set schedulable again and then + * it is executed + */ +void sys_yield(task_t *caller, e_task_mode mode); + +#endif/*!SYSCALLS_YIELD*/ diff --git a/syscalls/syscalls.h b/syscalls/syscalls.h new file mode 100644 index 0000000..d008bee --- /dev/null +++ b/syscalls/syscalls.h @@ -0,0 +1,50 @@ +/* \file syscalls.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SYSCALLS_H_ +#define SYSCALLS_H_ + +#include "types.h" +#include "syscalls-utils.h" +#include "exported/syscalls.h" +#include "autoconf.h" +#include "tasks.h" +#include "devices.h" + +/* including all syscalls header */ +#include "syscalls-yield.h" +#include "syscalls-sleep.h" +#include "syscalls-reset.h" +#include "syscalls-gettick.h" +#include "syscalls-lock.h" +#include "syscalls-init.h" + +/* +** IPC type to define, please use register based, not buffer based to +** set type and content (r1, r2, r3, r4... r1 = target, r2 = ipctype, r3 = ipc arg1...) +*/ +void sys_ipc(task_t * t, regval_t * regs, e_task_mode mode); + +void sys_cfg(task_t *caller, __user regval_t *regs, e_task_mode mode); + +#endif diff --git a/tasks-shared.h b/tasks-shared.h new file mode 100644 index 0000000..ebd19c8 --- /dev/null +++ b/tasks-shared.h @@ -0,0 +1,31 @@ +/* tasks-shared.h + * + * Copyright (C) 2018 ANSSI + * All rights reserved. + * + * This software may be modified and distributed under the terms + * of the BSD license. See the LICENSE file for details. + */ + +#ifndef TASK_SHARED_H_ +#define TASK_SHARED_H_ + + +/* + * \brief Task table accessor naming enumerate + */ +typedef enum { + ID_UNUSED, + ID_APP1, /* User app of slot 1 */ + ID_APP2, /* User app of slot 2 */ + ID_APP3, /* User app of slot 3 */ + ID_APP4, /* User app of slot 4 */ + ID_APP5, /* User app of slot 5 */ + ID_APP6, /* User app of slot 6 */ + ID_APP7, /* User app of slot 7 */ + ID_SOFTIRQ, /* Softirq thread */ + ID_KERNEL, /* Kernel idle task */ + ID_MAX +} e_task_id; + +#endif /*!TASK_SHARED_H_ */ diff --git a/tasks.c b/tasks.c new file mode 100644 index 0000000..bf47af6 --- /dev/null +++ b/tasks.c @@ -0,0 +1,406 @@ +/* \file tasks.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "tasks.h" +#include "m4-cpu.h" +#include "layout.h" +#include "soc-layout.h" +#include "apps_layout.h" +#include "debug.h" +#include "sched.h" +#include "kernel.h" +#include "softirq.h" +#include "autoconf.h" +#include "sections.h" + +#define EXC_THREAD_MODE 0xFFFFFFFD +#define EXC_KERN_MODE 0xFFFFFFF9 +#define EXC_HANDLER_MODE 0xFFFFFFF1 + +/* number of task registered in the slots */ +static uint8_t num_tasks = 0; + +/* size of .text content of tasks (i.e. size of slots in memory mapping) */ +static uint32_t task_txt_size = 0; +static uint32_t task_ram_size = 0; + +/* calculate the user base @, depending on FW1, FW2, DFU1, DFU2 ctx. */ +static uint32_t user_base = 0; + +/* +** global task contexts tab (max 8 tasks) +** please avoid = 0 in globals, they are set in .data instead of .bss, which +** generates huge amount of memory in flash for nothing. +*/ +static task_t tasks_list[ID_MAX]; + +/************************************************************************ + * Threads + * This part hosts kernel-land threads others than softirq (which has + * its dedicated package) + ***********************************************************************/ + +/* +** This is the idle task. As we are in collaborative mode, this is simply a kernel task +** when no userspace task is schedulable. This task simply waits for an interrupt. +** All userspace tasks are interrupt based (HW timers, device's IRQ...) +** In this case, this idle tasks looks like a simple "main loop". +*/ +static void task_idle(void) +{ + KERNLOG(DBG_NOTICE, "[II] EwoK ukernel IDLE thread starting\n"); + dbg_flush(); + enable_irq(); + while (1) { + wait_for_interrupt(); + } +} + + +/************************************************************************ + * Utility functions for task execution + ***********************************************************************/ + +/* + * This function is used as LR value of the initial frame created + * at task initialization time. Nevertheless, this is not a real + * need as the _main function is called by do_starttask() which + * istelf finishes with a while(1); waiting for the task state to + * be set at finished. This function, as a consequence, should never + * be called. + */ +static void task_finish(void) +{ + /* the task will never exit from here and will never be schedule again */ + while (1) ; +} + +/************************************************************************ + * Utility functions for task creation + * These functions create task context, task stack, etc. + ***********************************************************************/ + +/* + * This function create the first frame of the user task, before its first + * execution + * This construct permits to geenrate a clean stack frame in a dedicated + * user stack area + * + * args specify the 4 first registers value, if needed, to + */ +void task_create_stack(task_context_t * ctx, physaddr_t sp, physaddr_t pc, + physaddr_t * args) +{ + ctx->frame = (stack_frame_t *) ((uint32_t) sp - sizeof(stack_frame_t)); + + if (args) { + ctx->frame->r0 = args[0]; + ctx->frame->r1 = args[1]; + ctx->frame->r2 = args[2]; + ctx->frame->r3 = args[3]; + } else { + ctx->frame->r0 = 0x0; + ctx->frame->r1 = 0x0; + ctx->frame->r2 = 0x0; + ctx->frame->r3 = 0x0; + } + + ctx->frame->r4 = 0x0; + ctx->frame->r5 = 0x0; + ctx->frame->r6 = 0x0; + ctx->frame->r7 = 0x0; + ctx->frame->r8 = 0x0; + ctx->frame->r9 = 0x0; + ctx->frame->r10 = 0x0; + ctx->frame->r11 = 0x0; + ctx->frame->r12 = 0x0; + ctx->frame->lr = (uint32_t) EXC_THREAD_MODE; + ctx->frame->prev_lr = (uint32_t) task_finish; + ctx->frame->pc = pc; + ctx->frame->xpsr = 0x1000000; /* Thumb bit on */ +} + +/* + * Create the softirq task context + */ +uint8_t task_init_softirq(void) +{ + task_t *tsk = &tasks_list[ID_SOFTIRQ]; // kernel task is tasks_list[9] + tsk->name = "softirq"; + tsk->mode = TASK_MODE_MAINTHREAD; + tsk->fn = + ((physaddr_t) task_softirq % 2 == + 1) ? (physaddr_t) task_softirq : (physaddr_t) task_softirq + 1; + tsk->type = TASK_TYPE_KERNEL; + tsk->id = ID_SOFTIRQ; + tsk->slot = 0; /* unused */ + + memset((void*)(STACK_TOP_SOFTIRQ - STACK_SIZE_SOFTIRQ), 0, STACK_SIZE_SOFTIRQ); + task_create_stack(&(tsk->ctx[TASK_MODE_MAINTHREAD]), STACK_TOP_SOFTIRQ, + tsk->fn, 0); + + tsk->stack_size = STACK_SIZE_SOFTIRQ; + + tsk->state[TASK_MODE_MAINTHREAD] = TASK_STATE_IDLE; + tsk->state[TASK_MODE_ISRTHREAD] = TASK_STATE_IDLE; /* always */ + + for (int i=0;iipc_endpoint[i] = NULL; + } + + KERNLOG(DBG_INFO, + "created context for softirq task '%s' (@%x) sp: @%x\n", + tsk->name, tsk->fn, tsk->ctx[TASK_MODE_MAINTHREAD].frame); + return 0; +} + +/* + * Create the idle task context + */ +uint8_t task_init_idle(void) +{ + task_t *tsk = &tasks_list[ID_KERNEL]; + tsk->name = "idle"; + tsk->fn = + ((physaddr_t) task_idle % 2 == + 1) ? (physaddr_t) task_idle : (physaddr_t) task_idle + 1; + tsk->type = TASK_TYPE_KERNEL; + tsk->id = ID_KERNEL; + tsk->slot = 0; /* unused */ + tsk->prio = 0; /* unused */ + + task_create_stack(&(tsk->ctx[TASK_MODE_MAINTHREAD]), STACK_TOP_IDLE, tsk->fn, 0); + tsk->stack_size = STACK_SIZE_IDLE; + + tsk->mode = TASK_MODE_MAINTHREAD; + tsk->state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + tsk->state[TASK_MODE_ISRTHREAD] = TASK_STATE_IDLE; /* always */ + + for (int i=0;iipc_endpoint[i] = NULL; + } + + KERNLOG(DBG_INFO, + "created context for kernel task '%s' (@%x), sp: @%x\n", + tsk->name, tsk->fn, tsk->ctx[TASK_MODE_MAINTHREAD].frame); + return 0; +} + +/* + * Initialize all userspace tasks. + */ +uint8_t task_init_apps(void) +{ + int i; + + /* + * How many tasks ? + * Tasks are defined in 'app_tab' array (include/generated/apps_layout.h) + */ + num_tasks = sizeof(app_tab) / sizeof(struct app); + + if (num_tasks > 7) { + KERNLOG(DBG_ERR, + "[EE] too many apps ! only 7 apps can be included ! see include/generated/apps_layout.h\n"); + panic("stopping initialization\n"); + } + +#ifdef CONFIG_FIRMWARE_DUALBANK + /* Detect if we are in firmware 1 or 2 */ + if ((uint32_t) task_init_apps < FW1_USER_BASE) { + user_base = FW1_USER_BASE; + } else { + user_base = FW2_USER_BASE; + } +#else + user_base = FW1_USER_BASE; +#endif + + /* Slot size is fixed. An application may requires more than one slot */ + task_txt_size = FW_MAX_USER_SIZE; + task_ram_size = RAM_USER_SIZE; + + for (i = 0; i < num_tasks; ++i) { + physaddr_t args[4] = { 0, 0, 0, 0 }; + + task_t *tsk = &tasks_list[ID_APP1 + i]; + memset(tsk, 0, sizeof(tsk)); + + tsk->id = ID_APP1 + i; /* id range from ID_APP1 to ID_APP7 */ + tsk->slot = app_tab[i].slot; + tsk->num_slots = app_tab[i].num_slots; +#if CONFIG_KERNEL_DOMAIN + tsk->domain = app_tab[i].domain; +#endif + tsk->fn = + (physaddr_t) user_base + + (uint32_t) ((uint8_t) (tsk->slot - 1) * (uint32_t) task_txt_size); + + tsk->fn = tsk->fn % 2 == 1 ? tsk->fn : tsk->fn + 1; + tsk->name = app_tab[i].name; + tsk->type = TASK_TYPE_USER; + tsk->ctx[TASK_MODE_ISRTHREAD].fn = app_tab[i].startisr; + tsk->prio = app_tab[i].prio; +#ifdef CONFIG_KERNEL_SCHED_DEBUG + tsk->count = 0; + tsk->force_count = 0; + tsk->isr_count = 0; +#endif + tsk->num_devs = 0; + tsk->num_devs_mmapped = 0; + + /* RAM size depends on the number of required slots + * less big */ + tsk->ram_slot_start = RAM_USER_BASE + + ((uint32_t)tsk->slot - 1) * task_ram_size; + + tsk->ram_slot_end = RAM_USER_BASE + + ((uint32_t)tsk->slot + tsk->num_slots - 1) * task_ram_size; + + /* FLASH size depends on the number of required slots */ + tsk->txt_slot_start = user_base + + ((uint32_t)tsk->slot - 1) * task_txt_size; + + tsk->txt_slot_end = user_base + + ((uint32_t)tsk->slot + tsk->num_slots - 1) * task_txt_size; + + /* Top of the stack is at the end of the task's address space */ + args[0] = tsk->id; + task_create_stack(&(tsk->ctx[TASK_MODE_MAINTHREAD]), tsk->ram_slot_end, tsk->fn, args); + + tsk->stack_size = app_tab[i].stacksize; + tsk->mode = TASK_MODE_MAINTHREAD; + tsk->state[TASK_MODE_MAINTHREAD] = TASK_STATE_RUNNABLE; + tsk->state[TASK_MODE_ISRTHREAD] = TASK_STATE_IDLE; + tsk->init_done = false; + + for (int i=0;iipc_endpoint[i] = NULL; + } + + KERNLOG(DBG_INFO, + "created context for task '%s' (@%x), sp: %x\n", + tsk->name, tsk->fn, tsk->ctx[TASK_MODE_MAINTHREAD].frame); + KERNLOG(DBG_DEBUG, "context for task '%s'\n", tsk->name); + KERNLOG(DBG_DEBUG, " - _start '%x'\n", tsk->fn); + KERNLOG(DBG_DEBUG, " - SP '%x'\n", tsk->ctx[TASK_MODE_MAINTHREAD].frame); + } + dbg_flush(); + + return 0; +} + +/************************************************************************ + * Task package getters and setters + ***********************************************************************/ + +/* + * Get the list of tasks + */ +task_t* task_get_tasks_list(void) +{ + return tasks_list; +} + +/* + * get the task structure using its identifier + */ +task_t* task_get_task(e_task_id id) +{ + return &tasks_list[id]; +} + + +/* + * Set the given task thread to a given state + */ +void task_set_task_state(e_task_id id, e_task_mode thread, e_task_state state) +{ + tasks_list[id].state[thread] = state; +} + +e_task_state task_get_task_state(e_task_id id, e_task_mode mode) +{ + return tasks_list[id].state[mode]; +} + +/* + * Get the task name using its identifier + */ +const char* task_get_name(e_task_id id) +{ + return tasks_list[id].name; +} + + +/* +** return true if the task is an existing userspace task +*/ +uint8_t task_is_user(e_task_id id) +{ + if (id > ID_MAX) { + /* Not a valid id (generates a table overflow), may be a ANY_APP id */ + return 0; + } + /* id higher thant MAXTASKS */ + if (id >= ID_APP1 && id <= ID_APP1 + CONFIG_MAXTASKS - 1) { + return 1; + } + return 0; +} + +/************************************************************************ + * Global task package initializer + ***********************************************************************/ +/* +** \fn task module initialization function +*/ +void task_init(void) +{ + e_task_id id; + + for (id = 0; id <= ID_MAX; id++) { + tasks_list[id].state[TASK_MODE_MAINTHREAD] = TASK_STATE_EMPTY; + } + + if (task_init_idle()) { + ERROR("idle task context initialization fails!\n"); + dbg_flush(); + panic("Unable to prepare for creating idle task.\n"); + } + if (task_init_softirq()) { + ERROR("softirq task context initialization fails!\n"); + dbg_flush(); + panic("Unable to prepare for creating softirq task.\n"); + } + if (task_init_apps()) { + ERROR("Userspace tasks contexts initialization fails!\n"); + dbg_flush(); + panic("Unable to prepare for creating user tasks.\n"); + } + task_map_data(); + KERNLOG(DBG_NOTICE, + "data sections of userspace tasks mapped in user RAM slots\n"); + KERNLOG(DBG_NOTICE, "bss sections of userspace tasks zero'ified\n"); + dbg_flush(); +} diff --git a/tasks.h b/tasks.h new file mode 100644 index 0000000..fbf92a7 --- /dev/null +++ b/tasks.h @@ -0,0 +1,270 @@ +/* \file tasks.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef TASK_H_ +#define TASK_H_ + +#include "autoconf.h" +#include "types.h" +#include "mpu.h" +#include "exported/devices.h" +#include "exported/dmas.h" +#include "dma-shared.h" +#include "kernel.h" + +#define __KERNEL + +#include "tasks-shared.h" +#include "ipc.h" +#include "devices-shared.h" + +/* should be configured */ +#define MAX_IRQS_PER_TASK 8 +#define MAX_TIMERS_PER_TASK 6 +#define MAX_DMAS_PER_TASK 8 +#define MAX_DMA_SHM_PER_TASK 4 +#define MAX_DEVS_PER_TASK 4 + + +/* +** \brief task state +*/ +typedef enum { + /* No task in this slot */ + TASK_STATE_EMPTY, + + /* Task can be elected by the scheduler with its standard priority */ + TASK_STATE_RUNNABLE, + + /* Force the scheduler to choose that task */ + TASK_STATE_FORCED, + + /* Pending syscall. Task can't be scheduled. */ + TASK_STATE_SVC_BLOCKED, + + TASK_STATE_ISR_DONE, + + /* Task currently has nothing to do, not schedulable */ + TASK_STATE_IDLE, + + /* Task is sleeping */ + TASK_STATE_SLEEPING, + + /* Task has generated an exception (memory fault, etc.), not + * schedulable anymore */ + TASK_STATE_FAULT, + + /* Task has return from its main() function. Yet its ISR handlers can + * still be executed if needed */ + TASK_STATE_FINISHED, + + /* Task has emitted a blocking send(target) and is waiting + * for that the EndPoint shared with the receiver gets ready */ + TASK_STATE_IPC_SEND_BLOCKED, + + /* Task has emitted a blocking recv(target) and is waiting + * for a send() */ + TASK_STATE_IPC_RECV_BLOCKED, + + /* Task has emitted a blocking send(target) and is waiting + * recv() acknowledgement from the target task */ + TASK_STATE_IPC_WAIT_ACK, + + TASK_STATE_LOCKED +} e_task_state; + +/* +** \brief task type: kernel, user or idle +*/ +typedef enum { + /* Kernel task, executing restricted ASM instruction (typically + * softirq) */ + TASK_TYPE_KERNEL, + + /* User task, being executed in user mode, with restricted access */ + TASK_TYPE_USER +} e_task_type; + +/* +** \brief Specify the current task context state +*/ +typedef enum { + /* The task is using it's main context, executing its main thread */ + TASK_MODE_MAINTHREAD = 0, + + /* The task is using its ISR context, when executing one of its ISR + * handler in user mode */ + TASK_MODE_ISRTHREAD = 1, + TASK_MODE_MAX = 2, +} e_task_mode; + +/** + * \brief the task context struct, hosting the task context when scheduled + * + * \param fn: for handler mode (isr_ctx) only, to set which handler needs to be executed + * \param dev: for handler mode (isr_ctx) only, specify the lonely device to map + * \param frame: point to saved registers + * \param ret: link register value + * \param fp_regs: FPU registers values + * \param fp_flags: FPU flags (cary, etc.) + */ +typedef struct { + physaddr_t fn; + e_device_id dev_id; + dev_irq_info_t *irq; + stack_frame_t *frame; +#ifdef CONFIG_FPU +#ifndef CONFIG_FPU_ENABLE_PRIVILEGIED + regval_t fp_regs[8]; + regval_t fp_flag; +#endif +#endif +} task_context_t; + +/* + * \brief This is the main task struct + * This structure contains the overall task informations, including: + * - memory layout properties + * - task type (user, kernel) + * - task priority + * - task registered ressources (devices, DMA, etc.) + * - task current status (init or nominal mode + * - task threads contexts + * + * This structure doesn't contain the permissions, as permissions + * are read-only data set at build time. Link beetween permissions and + * tasks is done using the task identifier. + */ +typedef struct task_t { + char const *name; /* task name, for pretty printing */ + + physaddr_t fn; /* task entry point */ + e_task_type type; /* task type (user, kernel, ... */ + e_task_mode mode; /* current task mode (thread or isr) */ + e_task_id id; /* id */ + + uint8_t slot; /* user slot (memory sub-region) used. 0 = unused */ + uint8_t num_slots; /* number of slots used by the application */ + + uint8_t prio; /* priority (not used by now) */ + +#ifdef CONFIG_KERNEL_DOMAIN + uint8_t domain; /* task execution domain */ +#endif + + uint8_t num_devs; /* Number of devices for this task */ + uint8_t num_devs_mmapped; /* Number of devices for this task */ + +#ifdef CONFIG_KERNEL_SCHED_DEBUG + uint32_t count; + uint32_t force_count; + uint32_t isr_count; +#endif + +#ifdef CONFIG_KERNEL_DMA_ENABLE + uint32_t num_dma_shms; + dma_shm_t dma_shm[MAX_DMA_SHM_PER_TASK]; + uint32_t num_dmas; /* number of task's registered dma */ + e_dma_id dma[MAX_DMAS_PER_TASK]; /* list of task's devices */ +#endif + + bool init_done; /* set to true when sys_init(INIT_DONE) has been executed */ + + e_device_id dev_id[MAX_DEVS_PER_TASK]; /* list of task's devices */ + + physaddr_t ram_slot_start; /* RAM slot start address */ + physaddr_t ram_slot_end; /* RAM slot end address */ + physaddr_t txt_slot_start; /* .text slot start address */ + physaddr_t txt_slot_end; /* .text slot end address */ + + uint16_t stack_size; /* stack size (in bytes) */ + + e_task_state state[TASK_MODE_MAX]; /* current schedulable state */ + ipc_endpoint_t* ipc_endpoint[ID_MAX]; /* input IPC context (if any) */ + task_context_t ctx[TASK_MODE_MAX]; /* main thread context */ +} task_t; + + +/************************************************************************ + * Task package getters and setters + ***********************************************************************/ +/* + * Get the list of tasks + */ +task_t* task_get_tasks_list(void); + +/* + * get the task structure using its identifier + */ +task_t* task_get_task(e_task_id id); + +/* + * Set the given task thread to a given state + */ +void task_set_task_state(e_task_id id, + e_task_mode thread, + e_task_state state); + +e_task_state task_get_task_state(e_task_id id, e_task_mode mode); + +/* + * Get the task name using its identifier + */ +const char* task_get_name(e_task_id id); + + +/* +** \fn specify if a task is a user task or not +** +** \param id: the slot (or task id) identifier +*/ +uint8_t task_is_user(e_task_id id); + +/************************************************************************ + * Utility functions for task creation (public part) + * These functions create task context, task stack, etc. + ***********************************************************************/ + +/* +** \fn Generate a custom stack frame for a given task context +** +** \param t: the task_context (sp @ has to be set in it already) +** \param sp: a given stack pointer +** \param fn: a handler or function to use for LR stacked value +** \param args: table of 4 registers values, for r0,r1,r2,r3, or 0 if no args +*/ +void task_create_stack(task_context_t* t, + physaddr_t sp, + physaddr_t fn, + physaddr_t* args); + +/************************************************************************ + * Global task package initializer + ***********************************************************************/ + +/* +** \fn task module initialization function +*/ +void task_init(void); + +#endif /*!TASK_H_ */ diff --git a/types.h b/types.h new file mode 100644 index 0000000..e45fd84 --- /dev/null +++ b/types.h @@ -0,0 +1,34 @@ +/* \file types.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef TYPES_H_ +#define TYPES_H_ + +#include "autoconf.h" + +#ifdef CONFIG_ARCH_ARMV7M +# include "arch/cores/armv7-m/types.h" +#else +# error "architecture not yet supported" +#endif + +#endif/*!TYPES_H_*/ diff --git a/usart.c b/usart.c new file mode 100644 index 0000000..29cd965 --- /dev/null +++ b/usart.c @@ -0,0 +1,92 @@ +/* \file usart.c + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "types.h" +#include "devices.h" +#include "gpio.h" +#include "libc.h" +#include "soc-usart.h" +#include "syscalls.h" + +device_t kusart_dev = { 0 }; + +void usart_init(void) +{ + uint32_t args[4] = { 0 }; + char *name; + + /* + * First registering device and gpio (this will only register + * a kernel device and lock the associated IP as the kernel + * as no INIT_DONE principle. IRQ handlers are executed + * in handler mode. + */ + + kusart_dev.irq_num = 1; + kusart_dev.size = 0x400; + kusart_dev.irqs[0].irq = soc_usarts[CONFIG_KERNEL_USART].irq; + + switch (CONFIG_KERNEL_USART) { + case 1: + name = "kusart1"; + kusart_dev.address = 0x40011000; + kusart_dev.irqs[0].handler = (void*)USART1_IRQ_Handler; + break; + case 6: + name = "kusart6"; + kusart_dev.address = 0x40011400; + kusart_dev.irqs[0].handler = (void*)USART6_IRQ_Handler; + break; + default: + break; + } + + memcpy(kusart_dev.name, name, strlen(name)); + kusart_dev.gpio_num = 2; + kusart_dev.gpios[0].mask = GPIO_MASK_SET_ALL; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + /* No possible typecasting from uint8_t to :4 */ + kusart_dev.gpios[0].kref.port = soc_usarts[CONFIG_KERNEL_USART].port; + kusart_dev.gpios[0].kref.pin = soc_usarts[CONFIG_KERNEL_USART].tx_pin; +#pragma GCC diagnostic pop + kusart_dev.gpios[0].afr = soc_usarts[CONFIG_KERNEL_USART].af; + kusart_dev.gpios[0].mode = GPIO_PIN_ALTERNATE_MODE; + kusart_dev.gpios[0].speed = GPIO_PIN_VERY_HIGH_SPEED; + kusart_dev.gpios[0].lck = 0; + + kusart_dev.gpios[1].mask = GPIO_MASK_SET_ALL; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + /* No possible typecasting from uint8_t to :4 */ + kusart_dev.gpios[1].kref.port = soc_usarts[CONFIG_KERNEL_USART].port; + kusart_dev.gpios[1].kref.pin = soc_usarts[CONFIG_KERNEL_USART].rx_pin; +#pragma GCC diagnostic pop + kusart_dev.gpios[1].afr = soc_usarts[CONFIG_KERNEL_USART].af; + kusart_dev.gpios[1].mode = GPIO_PIN_ALTERNATE_MODE; + kusart_dev.gpios[1].speed = GPIO_PIN_VERY_HIGH_SPEED; + kusart_dev.gpios[1].lck = 0; + + /* Kernel task is hosting the kernel devices list */ + args[1] = (uint32_t)&kusart_dev; + init_do_reg_devaccess(ID_KERNEL, args, TASK_MODE_MAINTHREAD); +} diff --git a/usart.h b/usart.h new file mode 100644 index 0000000..c1d5457 --- /dev/null +++ b/usart.h @@ -0,0 +1,29 @@ +/* \file usart.h + * + * Copyright 2018 The wookey project team + * - Ryad Benadjila + * - Arnauld Michelizza + * - Mathieu Renard + * - Philippe Thierry + * - Philippe Trebuchet + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef USART_H_ +# define USART_H_ + +void usart_init(void); + +#endif/*!USART_H_*/