ソースは
https://github.com/shohei/xapp1078_2014.4_zybo
を使う
1. xapp1078のビットストリームをVivadoで合成する。
design/work/project_2/project_2.xprを起動する。
IPは自動アップグレードする。
Generate bitstreamでビットストリームを生成する。
Export Hardwareでbitstreamを含んだHardwareをエクスポートする。
Launch SDKでSDKを起動する
2. BSPおよびapp_cpu1プロジェクトの作成
GitHubレポジトリのdesign/work/project_2/project_2.sdk/以下にあるコードは
どこかに退避させるかすべて削除する。(これらはあとで使うので削除した場合は再度クローンしてくる)
app_cpu1アプリケーションプロジェクトに、退避させた以下のコードを入れてRefreshすることでプロジェクトに反映する。
- app_cpu1.c
- app_cpu1.h
- my_utils.c
- my_utils.h
- scu_sleep.c
- scu_sleep.h
- lscript.ld
アプリケーションプロジェクトは特に変更の必要はない。
ここで重要なのはリンカースクリプトlscript.ld。
ベアメタルがアクセスできるDDR3のベースアドレスが変更されている。
次にBSPを修正する。
Board support package settingsから、drivers->ps7_cortexa1でコンパイラの設定を行う。
extra_compiler_flagsに、-g -DUSE_AMP=1を追加する。
(※standalne->stdin/stdoutをnoneにすると、後述のsoftUart.elfが実行できなくなるのでいじらない)
ブート時のメモリ読み込みに関する設定?をする。
(※1. これをしないとCPU0がCPU1を呼び出したときにハングする)
(※2. libsrcの下にあるファイルはBSPの設定を変更すると上書きされる?BSPを設定し直す度に修正する必要があるのかも )
app_cpu1_bsp/ps7_cortexa9_1/libsrc/standalone_v6_4/src/boot.S
〜(中略)〜 #ifdef SHAREABLE_DDR /* Mark the entire DDR memory as shareable */ ldr r3, =0x3ff /* 1024 entries to cover 1G DDR */ ldr r0, =TblBase /* MMU Table address in memory */ ldr r2, =0x15de6 /* S=b1 TEX=b101 AP=b11, Domain=b1111, C=b0, B=b1 */ shareable_loop: str r2, [r0] /* write the entry to MMU table */ add r0, r0, #0x4 /* next entry in the table */ add r2, r2, #0x100000 /* next section */ subs r3, r3, #1 bge shareable_loop /* loop till 1G is covered */ #endif ########### ここから ################## /* In case of AMP, mark address 0x00000000 - 0x17ffffff DDR as unassigned/reserved */ /* and address 0x30000000 - 0x3fffffff DDR as inner cached only */ #if USE_AMP==1 ldr r3, =0x17f /* 384 entries to cover 384MB DDR updated by Hu Xiaolei */ ldr r0, =TblBase /* MMU Table address in memory */ ldr r2, =0x0000 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */ mmu_loop: str r2, [r0] /* write the entry to MMU table */ add r0, r0, #0x4 /* next entry in the table */ add r2, r2, #0x100000 /* next section */ subs r3, r3, #1 bge mmu_loop /* loop till 384MB is covered */ ldr r3, =0x07f /* 128 entries to cover 128MB DDR */ movw r2, #0x4de6 /* S=b0 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b1 */ movt r2, #0x1800 /* S=b0, Section start for address 0x30000000 */ mmu_loop1: str r2, [r0] /* write the entry to MMU table */ add r0, r0, #0x4 /* next entry in the table */ add r2, r2, #0x100000 /* next section */ subs r3, r3, #1 bge mmu_loop1 /* loop till 128MB is covered */ #endif ########### ここまでを追加する ################## mrs r0, cpsr /* get the current PSR */ mvn r1, #0x1f /* set up the irq stack pointer */ and r2, r1, r0 orr r2, r2, #0x12 /* IRQ mode */ msr cpsr, r2 ldr r13,=IRQ_stack /* IRQ stack pointer */
これでapp_cpu1.elfの準備ができた。
LinuxアプリケーションsoftUartの準備もしておく。
New ApplicationからOSにLinuxを選び、Empty Applicationを作成する。
以下のファイルをアプリケーションにImportしてビルドし、softUart.elfを作成する。
/design/src/apps/softUart/softUart.c
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <byteswap.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> #include <errno.h> #include <sys/mman.h> #define PAGE_SIZE ((size_t)getpagesize()) #define PAGE_MASK ((uint64_t)(long)~(PAGE_SIZE - 1)) #define COMM_BASE 0xFFFF9000 #define COMM_TX_FLAG_OFFSET 0x00 #define COMM_TX_DATA_OFFSET 0x04 #define COMM_RX_FLAG_OFFSET 0x08 #define COMM_RX_DATA_OFFSET 0x0C #define MAX_STR 256 int main() { int fd; uint32_t value=0; uint32_t flag=0; volatile uint8_t *mm; uint8_t str[MAX_STR]; int rcnt; fd = open("/dev/mem", O_RDWR|O_SYNC); if (fd < 0) { fprintf(stderr, "open(/dev/mem) failed (%d)\n", errno); return 1; } mm = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, COMM_BASE); if (mm == MAP_FAILED) { fprintf(stderr, "mmap64(0x%x@0x%x) failed (%d)\n", PAGE_SIZE, (uint32_t)(COMM_BASE), errno); return 1; } rcnt = 0; while(1) { //read if( (flag = *(volatile uint32_t *)(mm + COMM_TX_FLAG_OFFSET)) ) { value = *(volatile uint32_t *)(mm + COMM_TX_DATA_OFFSET); //process non-string type data if(flag > 1) { printf("CPU1: 0x%08x = 0x%08x\n", (uint32_t)(mm + COMM_TX_DATA_OFFSET), value); //process string type data } else { if(rcnt < MAX_STR) { str[rcnt++] = value; } if(value == '\n') { if(rcnt != 0) { str[rcnt-1] = '\0'; } else { str[0] = '\0'; } printf("CPU1: %s\n", str); rcnt = 0; } } *(volatile uint32_t *)(mm + COMM_TX_FLAG_OFFSET) = 0; } } munmap((void *)mm, PAGE_SIZE); close(fd); return 0; }
3. petalinuxでLinuxシステムを作成する
Vivadoでエクスポートしたsystem_wrapper.hdfを使ってhw-descriptionを設定する。
$ petalinux-create -t project -n plnx-project --template zynq $ petalinux-config --get-hw-description=<path to system_wrapper.hdf directory> -> Image Packing configuration -> Root file system type -> SD card -> /dev/mmcblk0p12 (Device node of SD device) $ petalinux-config -c u-boot -> Boot images -> Support flattened image treeのチェックを外す(image.ubではなくuImageを見に行くようにする) -> Boot media -> Support for booting from SD/EMMCにチェックを入れる $ petalinux-config -c kernel -> 特に設定は必要ない $ petalinux-config -c rootfs -> peek-poke appを有効にする $ petalinux-build
次にBIFファイルを以下のように用意する
bootimage.bif
the_ROM_image: { [bootloader] zynq_fsbl.elf system_wrapper.bit u-boot.elf app_cpu1.elf }
次のコマンドでBOOT.BINを生成する。なお、app_cpu1.elfはカレントディレクトリ(plnx-project/images/linux)に移しておく
$ bootgen -image bootimage.bif -o i BOOT.BIN -w on
次にデバイスツリーを修正する
system.dtbからsystem.dtsを作成する
dtc -O dts -I dtb -o system.dts system.dtb
system.dtsを開いて以下を修正する
- bootargsにmem=384M maxcpus=1を追加
- memoryのregをreg = <0x0 0x18000000>に修正
〜(中略)〜 chosen { bootargs = "console=ttyPS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait mem=384M maxcpus=1"; stdout-path = "serial0:115200n8"; }; aliases { ethernet0 = "/amba/ethernet@e000b000"; serial0 = "/amba/serial@e0001000"; spi0 = "/amba/spi@e000d000"; }; memory { device_type = "memory"; reg = <0x0 0x18000000>; }; 〜(中略)〜
修正したsystem.dtsからsystem.dtbを再度作成する。
$ dtc -I dts -O dtb -o system.dtb system.dts
u-bootの設定ファイルは以下のように用意する。
https://gist.github.com/shohei/93cf5d59b561ab2d65388133f9c5a5e1
uEnv.txt
kernel_image=uImage devicetree_image=system.dtb netstart=0x10000000 dtbnetstart=0x11800000 bootargs=console=ttyPS0,115200 rw rootwait earlyprintk root=/dev/mmcblk0p2 rootfstype=ext4 maxcpus=1 mem=384M uenvcmd=mmcinfo && echo bootargs ${bootargs} && fatload mmc 0 ${netstart} ${kernel_image} && fatload mmc 0 ${dtbnetstart} ${devicetree_image} && bootm ${netstart} - ${dtbnetstart}
カーネルイメージuImageを作成する
$ petalinux-package --image -c kernel --format uImage
4. 作成したファイル群をSDカードに書き込む
$ sudo mkdir /mnt/boot $ sudo mount /dev/sdc1 /mnt/boot $ sudo cp BOOT.BIN /mnt/boot $ sudo cp uImage /mnt/boot $ sudo cp uEnv.txt /mnt/boot $ sudo cp system.dtb /mnt/boot $ sudo umount /mnt/boot
$ sudo mkdir /mnt/rootfs $ sudo mount /dev/sdc2 /mnt/rootfs $ sudo tar -xf rootfs.tar.gz -C /mnt/rootfs $ sudo umount /mnt/rootfs
5. ZyboをSDカードから起動する
gtktermでzyboに接続する
$ sudo gtkterm &
アカウントroot/rootでPetalinuxに入る
# mount /dev/mmcblk0p1 /mnt # cd /mnt # ls BOOT.BIN softUart.elf system.dtb uEnv.txt uImage # softUart.elf & [1] 1078 //ソフトシリアルを起動する # peek 0xffff8000 0x00000000 # peek 0xfffffff0 0x18000000 //CPU1を起動する→サンプルでは ./rwmem 0xfffffff0 0x30000000となっていた # peek 0xffff8000 0x00000001 //1秒毎にカウントアップされる # poke 0x78600000 1 CPU1: IRQ clr0 //IPコア irq_genが叩かれ、CPU1のPPIに割込みをかける