├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── custom_bsp_for_nano_dev_kit ├── cmdline.txt ├── desktop │ └── terminal.desktop ├── extlinux.conf ├── kernel_tegra210-p3448-0000-p3449-0000-b00-enable-spi1.dtb ├── onboard │ ├── onboard-autostart.desktop │ └── onboard-defaults.conf ├── step3b_customize_bsp.sh ├── u-boot.bin └── xfce │ ├── xfce4-desktop.xml │ └── xfce4-panel.xml ├── do_all.sh ├── find_mirrors.sh ├── step0_env.sh ├── step1_make_rootfs.sh ├── step2_customize_rootfs.sh ├── step2a_install.sh ├── step2b_cleanup.sh ├── step2c_fix_broken_install.sh ├── step3_apply_bsp.sh ├── step4_flash.sh ├── step5_create_image.sh └── step6_flash_SD.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.tgz 2 | *.tbz* 3 | *.tar* 4 | *.img 5 | custom/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 vuquangtrong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jetson-custom-image 2 | Create a custom image for Jetson boards 3 | 4 | 5 | ## How to 6 | 7 | 1. Firstly, edit the variables in `step0_env.sh` 8 | 9 | In here, you can change release version of Ubuntu and Jetson BSP. 10 | You have to set directories for RootFs and Build image 11 | You can choose a Desktop Environment. 12 | 13 | 2. Run `step1_make_rootfs.sh` 14 | 15 | This step creates a base RootFs in `ROOT_DIR`. 16 | The base version of Ubuntu will be downloaded and unpacked. 17 | 18 | 3. Run `step2_customize_rootfs.sh` 19 | 20 | This step installs necessary packages for Jetson libs, and X11 GUI server. 21 | It will download a Desktop environment if you do select one. 22 | It does some configurations to the RootFs. 23 | 24 | 4. Run `step3_apply_bsp.sh` 25 | 26 | This step downloads Jetson BSP including bootloader, Linux kernel, Linux headers, drivers and libraries. 27 | It also create an user for you too. 28 | 29 | 5. Run `step4_flash.sh` 30 | 31 | Put your board into Recovery Mode, and this step will flash your board with new system image. 32 | 33 | 6. Run `step5_create_image.sh` 34 | 35 | If you want to create and image file for flashing to a micro-SD Card, run this step before doing the next step. 36 | 37 | 7. Run `step6_flash_SD.sh` 38 | 39 | This step will write the system image to your micro-SD card. 40 | It also expands the application partition to use all of space of your card. 41 | 42 | ## License 43 | 44 | MIT 45 | -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/cmdline.txt: -------------------------------------------------------------------------------- 1 | tegraid=21.1.2.0.0 ddr_die=4096M@2048M section=512M memtype=0 vpr_resize usb_port_owner_info=0 lane_owner_info=0 emc_max_dvfs=0 touch_id=0@63 video=tegrafb no_console_suspend=1 debug_uartport=lsport,4 earlyprintk=uart8250-32bit,0x70006000 maxcpus=4 usbcore.old_scheme_first=1 lp0_vec=0x1000@0xff780000 core_edp_mv=1075 core_edp_ma=4000 gpt tegra_fbmem=0x800000@0x92ca9000 is_hdmi_initialised=1 earlycon=uart8250,mmio32,0x70006000 root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=tty0 fbcon=map:0 net.ifnames=0 quiet 2 | -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/desktop/terminal.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Terminal 4 | Exec=/usr/bin/gnome-terminal 5 | Terminal=false 6 | Icon=gnome-terminal 7 | -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/extlinux.conf: -------------------------------------------------------------------------------- 1 | TIMEOUT 1 2 | DEFAULT JetsonIO 3 | 4 | MENU TITLE L4T boot options 5 | 6 | LABEL JetsonIO 7 | MENU LABEL Tegra 210 - no console on ttyS0, enable spi1 8 | LINUX /boot/Image 9 | FDT /boot/kernel_tegra210-p3448-0000-p3449-0000-b00-enable-spi1.dtb 10 | INITRD /boot/initrd 11 | # flash.sh will add ROOT_DEV and CMDLINE_ADD from the conf file to APPEND variable 12 | APPEND tegraid=21.1.2.0.0 ddr_die=4096M@2048M section=512M memtype=0 vpr_resize usb_port_owner_info=0 lane_owner_info=0 emc_max_dvfs=0 touch_id=0@63 video=tegrafb no_console_suspend=1 debug_uartport=lsport,4 earlyprintk=uart8250-32bit,0x70006000 maxcpus=4 usbcore.old_scheme_first=1 lp0_vec=0x1000@0xff780000 core_edp_mv=1075 core_edp_ma=4000 gpt tegra_fbmem=0x800000@0x92ca9000 is_hdmi_initialised=1 earlycon=uart8250,mmio32,0x70006000 quiet 13 | -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/kernel_tegra210-p3448-0000-p3449-0000-b00-enable-spi1.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuquangtrong/jetson-custom-image/a63fb5ad3bc814ec3c31281142fd904fd4ef99cf/custom_bsp_for_nano_dev_kit/kernel_tegra210-p3448-0000-p3449-0000-b00-enable-spi1.dtb -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/onboard/onboard-autostart.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | X-XFCE-Autostart-Override=true 3 | -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/onboard/onboard-defaults.conf: -------------------------------------------------------------------------------- 1 | [main] 2 | start-minimized=True 3 | -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/step3b_customize_bsp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 3: apply JETSON_BSP 7 | 8 | ########## 9 | echo "Check root permission" 10 | 11 | if [ "x$(whoami)" != "xroot" ]; then 12 | echo "This script requires root privilege!!!" 13 | exit 1 14 | fi 15 | 16 | ########## 17 | echo "Get environment" 18 | 19 | source ../step0_env.sh 20 | 21 | WORK_ROOT_DIR=${WORK_DIR}/Linux_for_Tegra/rootfs 22 | 23 | ########## 24 | echo "Set script options" 25 | 26 | set -e # exit on error 27 | set -o pipefail # exit on pipeline error 28 | set -u # treat unset variable as error 29 | 30 | ########## 31 | echo "Replace U-boot" 32 | install -Dm644 u-boot.bin ${WORK_DIR}/Linux_for_Tegra/bootloader/t210ref/p3450-0000/u-boot.bin 33 | 34 | echo "Replace Linux boot menu" 35 | # note that flash.sh or make_image.sh will change add some extra boot commands based on the target boot device (SDcard/eMMC/etc.) 36 | install -Dm644 extlinux.conf ${WORK_ROOT_DIR}/boot/extlinux/extlinux.conf 37 | 38 | echo "Add overlay Device tree" 39 | # this file is generated using sudo python /opt/nvidia/jetson-io/jetson-io.py on-board 40 | install -Dm644 kernel_tegra210-p3448-0000-p3449-0000-b00-enable-spi1.dtb ${WORK_ROOT_DIR}/boot/kernel_tegra210-p3448-0000-p3449-0000-b00-enable-spi1.dtb 41 | 42 | echo "Insert SPI driver" 43 | # Jetpack 4.6 does not add driver automatically 44 | cat << EOF >> ${WORK_ROOT_DIR}/etc/modules 45 | spidev 46 | EOF 47 | 48 | echo "Disable console to take control ttyS0" 49 | sed -i 's/console=ttyS0,115200n8//g' ${WORK_DIR}/Linux_for_Tegra/p3448-0000.conf.common 50 | 51 | echo "Enable autologin" 52 | cat << EOF > ${WORK_ROOT_DIR}/etc/lightdm/lightdm.conf.d/autologin.conf 53 | [Seat:*] 54 | autologin-guest=false 55 | autologin-session=xubuntu 56 | autologin-user=${JETSON_USR} 57 | autologin-user-timeout=0 58 | EOF 59 | 60 | WIFI_SSID="HomeSweetHome" 61 | WIFI_PASS="Kh0ngch0d@u" 62 | cat << EOF > ${WORK_ROOT_DIR}/etc/netplan/01-netconf.yaml 63 | network: 64 | version: 2 65 | renderer: NetworkManager 66 | ethernets: 67 | eth0: 68 | optional: true 69 | dhcp4: true 70 | # add wifi setup information here ... 71 | wifis: 72 | wlan0: 73 | access-points: 74 | "${WIFI_SSID}": 75 | password: "${WIFI_PASS}" 76 | dhcp4: true 77 | dhcp4-overrides: 78 | route-metric: 50 79 | EOF 80 | 81 | echo "Enable color prompt for ${JETSON_USR} console" 82 | sed -i 's/^#force_color_prompt=yes/force_color_prompt=yes/g' ${WORK_ROOT_DIR}/home/${JETSON_USR}/.bashrc 83 | 84 | echo "Install qemu-aarch64-static" 85 | # for next steps 86 | install -Dm755 $(which qemu-aarch64-static) ${WORK_ROOT_DIR}/usr/bin/qemu-aarch64-static 87 | 88 | if [[ ${JETSON_DESKTOP} == 'xubuntu' ]]; then 89 | echo "Add default XFCE settings" 90 | install -Dm644 xfce/xfce4-panel.xml ${WORK_ROOT_DIR}/home/${JETSON_USR}/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml 91 | install -Dm644 xfce/xfce4-desktop.xml ${WORK_ROOT_DIR}/home/${JETSON_USR}/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml 92 | fi 93 | 94 | echo "Add default desktop icons" 95 | rm -rf ${WORK_ROOT_DIR}/home/${JETSON_USR}/Desktop/* 96 | install -Dm755 desktop/terminal.desktop ${WORK_ROOT_DIR}/home/${JETSON_USR}/Desktop/terminal.desktop 97 | 98 | chroot ${WORK_ROOT_DIR} bash -c "chmod +x /home/${JETSON_USR}/Desktop/*.desktop" 99 | chroot ${WORK_ROOT_DIR} bash -c "chown ${JETSON_USR}:${JETSON_USR} /home/${JETSON_USR}/Desktop/*.desktop" 100 | 101 | echo "Start onboard" 102 | install -Dm644 onboard/onboard-defaults.conf ${WORK_ROOT_DIR}/usr/share/onboard/onboard-defaults.conf 103 | install -Dm644 onboard/onboard-autostart.desktop ${WORK_ROOT_DIR}/home/${JETSON_USR}/.config/autostart/onboard-autostart.desktop 104 | 105 | echo "Set owner ${JETSON_USR} for .config" 106 | chroot ${WORK_ROOT_DIR} bash -c "chown -R ${JETSON_USR}:${JETSON_USR} /home/${JETSON_USR}/.config" 107 | 108 | # echo "Install extra packages" 109 | # chroot ${WORK_ROOT_DIR} apt install -y --no-install-recommends \ 110 | # xfce4-whiskermenu-plugin 111 | 112 | echo "Disable nvgetty to take control ttyTHS1" 113 | chroot ${WORK_ROOT_DIR} systemctl disable nvgetty 114 | 115 | echo "Add user to groups" 116 | chroot ${WORK_ROOT_DIR} usermod -a -G tty,dialout,gpio ${JETSON_USR} 117 | 118 | echo "Clean up" 119 | chroot ${WORK_ROOT_DIR} apt autoremove -y 120 | chroot ${WORK_ROOT_DIR} apt clean 121 | 122 | echo "Remove qemu-aarch64-static" 123 | rm -f ${WORK_ROOT_DIR}/usr/bin/qemu-aarch64-static 124 | -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/u-boot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuquangtrong/jetson-custom-image/a63fb5ad3bc814ec3c31281142fd904fd4ef99cf/custom_bsp_for_nano_dev_kit/u-boot.bin -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/xfce/xfce4-desktop.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /custom_bsp_for_nano_dev_kit/xfce/xfce4-panel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /do_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # do all defined steps 7 | 8 | ########## 9 | echo "Check root permission" 10 | 11 | if [ "x$(whoami)" != "xroot" ]; then 12 | echo "This script requires root privilege!!!" 13 | exit 1 14 | fi 15 | 16 | ########## 17 | 18 | source ./step0_env.sh 19 | ./step1_make_rootfs.sh 20 | ./step2_customize_rootfs.sh 21 | ./step3_apply_bsp.sh 22 | pushd custom_bsp_for_nano_dev_kit 23 | ./step3b_customize_bsp.sh 24 | popd 25 | ./step5_create_image.sh 26 | 27 | echo "Done!" 28 | -------------------------------------------------------------------------------- /find_mirrors.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # thanks for Malte Skoruppa 4 | # https://askubuntu.com/questions/428698/are-there-alternative-repositories-to-ports-ubuntu-com-for-arm 5 | 6 | # URL of the Launchpad mirror list 7 | MIRROR_LIST=https://launchpad.net/ubuntu/+archivemirrors 8 | 9 | # Set to the architecture you're looking for (e.g., amd64, i386, arm64, armhf, armel, powerpc, ...). 10 | # See https://wiki.ubuntu.com/UbuntuDevelopment/PackageArchive#Architectures 11 | ARCH=$1 12 | 13 | # Set to the Ubuntu distribution you need (e.g., precise, saucy, trusty, ...) 14 | # See https://wiki.ubuntu.com/DevelopmentCodeNames 15 | DIST=$2 16 | 17 | # Set to the repository you're looking for (main, restricted, universe, multiverse) 18 | # See https://help.ubuntu.com/community/Repositories/Ubuntu 19 | REPO=$3 20 | 21 | # Set flags to check speed of repo 22 | SPDCHK=$4 23 | 24 | # First, we retrieve the Launchpad mirror list, and obtain a newline-separated list of HTTP mirrors 25 | mirrorList=() 26 | for url in $(curl -s $MIRROR_LIST | grep -Po 'http://.*(?=/">http)'); do 27 | # if [[ $url == *".vn"* ]]; then 28 | # echo $url 29 | mirrorList+=( "$url" ) 30 | # fi 31 | done 32 | 33 | 34 | # Second, we try to connect to the site at `$url/dists/$DIST/$REPO/binary-$ARCH/` 35 | for url in "${mirrorList[@]}"; do 36 | ( 37 | rurl=$url/dists/$DIST/$REPO/binary-$ARCH/ 38 | # If you like some output while the script is running (feel free to comment out the following line) 39 | # echo "Processing $rurl" 40 | # retrieve the header; check if status code is 200 41 | if curl --connect-timeout 5 -s --head $rurl | head -n 1 | grep -q 'HTTP/[12].*200'; 42 | then 43 | if [ $SPDCHK = "speed" ] 44 | then 45 | echo $(curl -s -w '%{time_total}\n' -o /dev/null $rurl) "$url" 46 | else 47 | echo "$url" 48 | fi 49 | fi 50 | ) & 51 | done 52 | 53 | wait 54 | 55 | echo "Search done!" 56 | -------------------------------------------------------------------------------- /step0_env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 0: set up environment 7 | 8 | ########## 9 | echo "Set target architecture" 10 | 11 | ARCH=arm64 12 | 13 | echo "Set target distro" 14 | 15 | # Ubuntu release version, e.g. Ubuntu 18.04.6 16 | RELEASE=bionic 17 | 18 | # Use below script to get the fastest repo, after that skip script to run faster 19 | # if [ -z "${REPO}" ] 20 | # then 21 | # REPO=$(./find_mirrors.sh ${ARCH} ${RELEASE} main speed | sort -k 1 | head -n 1 | awk '{print $2}') 22 | # fi 23 | 24 | REPO=http://repo.jing.rocks/ubuntu-ports 25 | # If REPO is empty, http://ports.ubuntu.com/ubuntu-ports will be used, or set a REPO below 26 | 27 | echo "Set target platform" 28 | 29 | JETSON_BOARD=jetson-nano-devkit 30 | JETSON_STORAGE=mmcblk0p1 31 | JETSON_BOARD_IMG=jetson-nano 32 | JETSON_BOARD_REV=300 33 | JETSON_PLAT=t210 34 | JETSON_REL=r32.7.5 35 | JETSON_BSP=jetson-210_linux_r32.7.5_aarch64.tbz2 36 | JETSON_BSP_URL=https://developer.nvidia.com/downloads/embedded/l4t/r32_release_v7.5/t210/jetson-210_linux_r32.7.5_aarch64.tbz2 37 | 38 | echo "Set target directories" 39 | 40 | ROOT_DIR=/tmp/jetson-custom/rootfs 41 | WORK_DIR=/tmp/jetson-custom/build 42 | 43 | echo "Set system users" 44 | 45 | ROOT_PWD=root 46 | JETSON_NAME=nvidia 47 | JETSON_USR=jetson 48 | JETSON_PWD=cccccc 49 | 50 | echo "Set desktop manager" 51 | 52 | # leave it empty to not install any DE 53 | # JETSON_DESKTOP= 54 | 55 | # just a minimal desktop 56 | # JETSON_DESKTOP=openbox 57 | 58 | # some panels from lxde 59 | # JETSON_DESKTOP=lxde 60 | 61 | # look better and lightweight 62 | JETSON_DESKTOP=xubuntu 63 | 64 | # more similar to ubuntu 65 | # JETSON_DESKTOP=ubuntu-mate 66 | 67 | echo "Set network settings" 68 | 69 | WIFI_SSID= 70 | WIFI_PASS= 71 | 72 | ########## 73 | echo "Prepare environment" 74 | 75 | mkdir -p ${ROOT_DIR} 76 | mkdir -p ${WORK_DIR} 77 | 78 | echo "ARCH = ${ARCH}" 79 | echo "RELEASE = ${RELEASE}" 80 | echo "REPO = ${REPO}" 81 | 82 | echo "JETSON_PLAT = ${JETSON_PLAT}" 83 | echo "JETSON_REL = ${JETSON_REL}" 84 | echo "JETSON_BSP = ${JETSON_BSP}" 85 | echo "JETSON_BSP_URL = ${JETSON_BSP_URL}" 86 | 87 | echo "ROOT_DIR = ${ROOT_DIR}" 88 | echo "WORK_DIR = ${WORK_DIR}" 89 | 90 | echo "ROOT_PWD =${ROOT_PWD}" 91 | echo "JETSON_NAME = ${JETSON_NAME}" 92 | echo "JETSON_USR = ${JETSON_USR}" 93 | echo "JETSON_PWD = ${JETSON_PWD}" 94 | echo "JETSON_DESKTOP = ${JETSON_DESKTOP}" 95 | 96 | echo "WIFI_SSID = ${WIFI_SSID}" 97 | echo "WIFI_PASS = ${WIFI_PASS}" 98 | -------------------------------------------------------------------------------- /step1_make_rootfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 1: make rootfs 7 | 8 | ########## 9 | echo "Check root permission" 10 | 11 | if [ "x$(whoami)" != "xroot" ]; then 12 | echo "This script requires root privilege!!!" 13 | exit 1 14 | fi 15 | 16 | ########## 17 | echo "Get environment" 18 | 19 | source ./step0_env.sh 20 | 21 | ########## 22 | echo "Set script options" 23 | 24 | set -e # exit on error 25 | set -o pipefail # exit on pipeline error 26 | set -u # treat unset variable as error 27 | 28 | ########## 29 | echo "Install tools" 30 | 31 | apt install -y --no-install-recommends \ 32 | qemu-user-static \ 33 | debootstrap \ 34 | binfmt-support \ 35 | libxml2-utils 36 | 37 | ########## 38 | echo "Debootstrap a base" 39 | 40 | # create a zip file for laster use 41 | # delete the zip file to get new version of packages 42 | # however, app packages will be updated later 43 | if [ ! -f ${ARCH}-${RELEASE}.tgz ] 44 | then 45 | echo "Download packages to ${ARCH}-${RELEASE}.tgz" 46 | debootstrap \ 47 | --verbose \ 48 | --foreign \ 49 | --arch=${ARCH} \ 50 | ${RELEASE} \ 51 | ${ROOT_DIR} \ 52 | ${REPO} 53 | tar -cvzf ${ARCH}-${RELEASE}.tgz -C ${ROOT_DIR} . 54 | fi 55 | 56 | echo "Install packages from ${ARCH}-${RELEASE}.tgz" 57 | rm -rf ${ROOT_DIR} 58 | mkdir -p ${ROOT_DIR} 59 | tar -xvzf ${ARCH}-${RELEASE}.tgz -C ${ROOT_DIR} 60 | 61 | ########## 62 | echo "Install virtual machine" 63 | 64 | # qemu-aarch64-static will be called by chroot 65 | install -Dm755 $(which qemu-aarch64-static) ${ROOT_DIR}/usr/bin/qemu-aarch64-static 66 | 67 | # ubuntu-keyring package can be installed, but this way is a bit faster ? 68 | install -Dm644 /usr/share/keyrings/ubuntu-archive-keyring.gpg ${ROOT_DIR}/usr/share/keyrings/ubuntu-archive-keyring.gpg 69 | 70 | ########## 71 | echo "Unpack ${ROOT_DIR}" 72 | 73 | chroot ${ROOT_DIR} /debootstrap/debootstrap --second-stage 74 | -------------------------------------------------------------------------------- /step2_customize_rootfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 2: customize rootfs 7 | 8 | ./step2a_install.sh # run installation 9 | ret=$? # return 0 if no error 10 | if [ $ret -ne 0 ]; then 11 | ./step2b_cleanup.sh # clean up if something is wrong 12 | fi 13 | -------------------------------------------------------------------------------- /step2a_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 2: customize rootfs 7 | 8 | ########## 9 | echo "Check root permission" 10 | 11 | if [ "x$(whoami)" != "xroot" ]; then 12 | echo "This script requires root privilege!!!" 13 | exit 1 14 | fi 15 | 16 | ########## 17 | echo "Get environment" 18 | 19 | source ./step0_env.sh 20 | 21 | ########## 22 | echo "Set script options" 23 | 24 | set -e # exit on error 25 | set -o pipefail # exit on pipeline error 26 | set -u # treat unset variable as error 27 | 28 | ########## 29 | echo "Mount dependency points" 30 | 31 | # these mount points are needed for chroot? 32 | # if script halts before unmounting these point, you have to unmount manually 33 | # that is the reason, this script is called in a wrapper, see step2_customize_rootfs.sh 34 | for mnt in sys proc dev dev/pts tmp; do 35 | mount -o bind "/$mnt" "${ROOT_DIR}/$mnt" 36 | done 37 | 38 | ########## 39 | echo "Setup locale" 40 | 41 | chroot ${ROOT_DIR} locale-gen en_US 42 | chroot ${ROOT_DIR} locale-gen en_US.UTF-8 43 | chroot ${ROOT_DIR} update-locale LC_ALL=en_US.UTF-8 44 | 45 | ########## 46 | echo "Add nameserver" 47 | 48 | cat << EOF > ${ROOT_DIR}/etc/resolv.conf 49 | nameserver 8.8.8.8 50 | nameserver 8.8.4.4 51 | EOF 52 | 53 | ########## 54 | echo "Add repos for ${ARCH}" 55 | 56 | cat << EOF > ${ROOT_DIR}/etc/apt/apt.conf.d/99verify-peer.conf 57 | Acquire::https::Verify-Peer "false"; 58 | Acquire::https::Verify-Host "false"; 59 | EOF 60 | 61 | cat << EOF > ${ROOT_DIR}/etc/apt/sources.list 62 | deb [arch=${ARCH}] ${REPO} ${RELEASE} main restricted universe multiverse 63 | deb [arch=${ARCH}] ${REPO} ${RELEASE}-updates main restricted universe multiverse 64 | deb [arch=${ARCH}] ${REPO} ${RELEASE}-security main restricted universe multiverse 65 | EOF 66 | 67 | ########## 68 | echo "Update repo source list" 69 | 70 | chroot ${ROOT_DIR} apt update 71 | chroot ${ROOT_DIR} apt upgrade -y 72 | 73 | ########## 74 | echo "Install required packages" 75 | 76 | # below packages are needed for installing Jetson packages in step #3 77 | chroot ${ROOT_DIR} apt install -y --no-install-recommends \ 78 | libasound2 \ 79 | libcairo2 \ 80 | libdatrie1 \ 81 | libegl1 \ 82 | libegl1-mesa \ 83 | libevdev2 \ 84 | libfontconfig1 \ 85 | libgles2 \ 86 | libgstreamer1.0-0 \ 87 | libgstreamer-plugins-base1.0-0 \ 88 | libgstreamer-plugins-bad1.0-0 \ 89 | libgtk-3-0 \ 90 | libharfbuzz0b \ 91 | libinput10 \ 92 | libjpeg-turbo8 \ 93 | libpango-1.0-0 \ 94 | libpangocairo-1.0-0 \ 95 | libpangoft2-1.0-0 \ 96 | libpixman-1-0 \ 97 | libpng16-16 \ 98 | libunwind8 \ 99 | libwayland-client0 \ 100 | libwayland-cursor0 \ 101 | libwayland-egl1-mesa \ 102 | libx11-6 \ 103 | libxext6 \ 104 | libxkbcommon0 \ 105 | libxrender1 \ 106 | python \ 107 | python3 \ 108 | 109 | ########## 110 | echo "Install systen packages" 111 | 112 | # below packages are needed for systen 113 | chroot ${ROOT_DIR} apt install -y --no-install-recommends \ 114 | wget \ 115 | curl \ 116 | linux-firmware \ 117 | device-tree-compiler \ 118 | network-manager \ 119 | net-tools \ 120 | wireless-tools \ 121 | ssh \ 122 | 123 | ########## 124 | echo "Install X GUI" 125 | 126 | chroot ${ROOT_DIR} apt install -y --no-install-recommends \ 127 | xorg 128 | 129 | if [ ! -z ${JETSON_DESKTOP} ]; then 130 | 131 | if [ ${JETSON_DESKTOP} == 'openbox' ]; then 132 | echo "Install Openbox" 133 | 134 | # minimal desktop, only greeter, no taskbar and background 135 | chroot ${ROOT_DIR} apt install -y --no-install-recommends \ 136 | lightdm-gtk-greeter \ 137 | lightdm \ 138 | openbox \ 139 | 140 | fi 141 | 142 | if [ ${JETSON_DESKTOP} == 'lxde' ]; then 143 | echo "Install LXDE core" 144 | 145 | # lxde with some components 146 | chroot ${ROOT_DIR} apt install -y --no-install-recommends \ 147 | lightdm-gtk-greeter \ 148 | lightdm \ 149 | lxde-icon-theme \ 150 | lxde-core \ 151 | lxde-common \ 152 | policykit-1 lxpolkit \ 153 | lxsession-logout \ 154 | gvfs-backends \ 155 | 156 | fi 157 | 158 | if [ ${JETSON_DESKTOP} == 'xubuntu' ]; then 159 | echo "Install Xubuntu core" 160 | 161 | # Xubuntu, better than lxde 162 | chroot ${ROOT_DIR} apt install -y --no-install-recommends \ 163 | xubuntu-core \ 164 | 165 | fi 166 | 167 | if [ ${JETSON_DESKTOP} == 'ubuntu-mate' ]; then 168 | echo "Install Ubuntu Mate" 169 | 170 | # Ubuntu-Mate, similar to Ubuntu 171 | chroot ${ROOT_DIR} apt install -y --no-install-recommends \ 172 | ubuntu-mate-core \ 173 | 174 | fi 175 | 176 | # below packages are needed for desktop 177 | chroot ${ROOT_DIR} apt install -y --no-install-recommends \ 178 | onboard \ 179 | 180 | fi 181 | 182 | ########## 183 | echo "Install extra packages" 184 | 185 | # below packages are needed for desktop 186 | chroot ${ROOT_DIR} apt install -y --no-install-recommends \ 187 | htop \ 188 | nano \ 189 | 190 | ########## 191 | echo "Clean up" 192 | 193 | chroot ${ROOT_DIR} apt autoremove -y 194 | chroot ${ROOT_DIR} apt clean 195 | 196 | ########## 197 | echo "Set up networks" 198 | 199 | # Since Ubuntu 18.04, netplan does not use /etc/network/interfaces anymore 200 | if [ ! -z ${WIFI_SSID} ]; then 201 | cat << EOF > ${ROOT_DIR}/etc/netplan/01-netconf.yaml 202 | network: 203 | version: 2 204 | renderer: NetworkManager 205 | ethernets: 206 | eth0: 207 | optional: true 208 | dhcp4: true 209 | # add wifi setup information here ... 210 | wifis: 211 | wlan0: 212 | access-points: 213 | "${WIFI_SSID}": 214 | password: "${WIFI_PASS}" 215 | dhcp4: true 216 | dhcp4-overrides: 217 | route-metric: 50 218 | EOF 219 | fi 220 | 221 | cat << EOF > ${ROOT_DIR}/etc/hostname 222 | ${JETSON_NAME} 223 | EOF 224 | 225 | ########## 226 | echo "Unmount dependency points" 227 | 228 | for mnt in tmp dev/pts dev proc sys; do 229 | umount "${ROOT_DIR}/$mnt" 230 | done 231 | -------------------------------------------------------------------------------- /step2b_cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 2: customize rootfs 7 | 8 | ########## 9 | echo "Get environment" 10 | 11 | . ./step0_env.sh 12 | 13 | ########## 14 | echo "Set script options" 15 | 16 | set -e # exit on error 17 | set -o pipefail # exit on pipeline error 18 | set -u # treat unset variable as error 19 | 20 | ########## 21 | echo "Unmount dependency points" 22 | 23 | for mnt in dev/pts dev proc sys; do 24 | umount "${ROOT_DIR}/$mnt" 25 | done 26 | -------------------------------------------------------------------------------- /step2c_fix_broken_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 2: customize rootfs 7 | 8 | ########## 9 | echo "Check root permission" 10 | 11 | if [ "x$(whoami)" != "xroot" ]; then 12 | echo "This script requires root privilege!!!" 13 | exit 1 14 | fi 15 | 16 | ########## 17 | echo "Get environment" 18 | 19 | source ../jetson-custom-image/step0_env.sh 20 | 21 | ########## 22 | echo "Set script options" 23 | 24 | set -e # exit on error 25 | set -o pipefail # exit on pipeline error 26 | set -u # treat unset variable as error 27 | 28 | ########## 29 | echo "Mount dependency points" 30 | 31 | # these mount points are needed for chroot? 32 | # if script halts before unmounting these point, you have to unmount manually 33 | # that is the reason, this script is called in a wrapper, see step2_customize_rootfs.sh 34 | for mnt in sys proc dev dev/pts tmp; do 35 | mount -o bind "/$mnt" "${ROOT_DIR}/$mnt" 36 | done 37 | 38 | ########## 39 | echo "Add repos for ${ARCH}" 40 | 41 | cat << EOF > ${ROOT_DIR}/etc/apt/apt.conf.d/99verify-peer.conf 42 | Acquire::https::Verify-Peer "false"; 43 | Acquire::https::Verify-Host "false"; 44 | EOF 45 | 46 | cat << EOF > ${ROOT_DIR}/etc/apt/sources.list 47 | deb [arch=${ARCH}] ${REPO} ${RELEASE} main restricted universe multiverse 48 | deb [arch=${ARCH}] ${REPO} ${RELEASE}-updates main restricted universe multiverse 49 | deb [arch=${ARCH}] ${REPO} ${RELEASE}-security main restricted universe multiverse 50 | EOF 51 | 52 | ########## 53 | echo "Update repo source list" 54 | 55 | chroot ${ROOT_DIR} apt install --fix-broken 56 | 57 | ########## 58 | echo "Unmount dependency points" 59 | 60 | for mnt in tmp dev/pts dev proc sys; do 61 | umount "${ROOT_DIR}/$mnt" 62 | done 63 | -------------------------------------------------------------------------------- /step3_apply_bsp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 3: apply JETSON_BSP 7 | 8 | ########## 9 | echo "Check root permission" 10 | 11 | if [ "x$(whoami)" != "xroot" ]; then 12 | echo "This script requires root privilege!!!" 13 | exit 1 14 | fi 15 | 16 | ########## 17 | echo "Get environment" 18 | 19 | source ./step0_env.sh 20 | 21 | ########## 22 | echo "Set script options" 23 | 24 | set -e # exit on error 25 | set -o pipefail # exit on pipeline error 26 | set -u # treat unset variable as error 27 | 28 | ########## 29 | 30 | if [ ! -f ${JETSON_BSP} ]; then 31 | echo "Download JETSON_BSP" 32 | wget ${JETSON_BSP_URL} 33 | fi 34 | 35 | ########## 36 | 37 | if [ ! -d ${WORK_DIR}/Linux_for_Tegra ]; then 38 | echo "Extract JETSON_BSP" 39 | tar jxpf ${JETSON_BSP} -C ${WORK_DIR} 40 | fi 41 | 42 | ########## 43 | echo "Copy rootfs" 44 | 45 | rm -rf ${WORK_DIR}/Linux_for_Tegra/rootfs 46 | cp -rf ${ROOT_DIR} ${WORK_DIR}/Linux_for_Tegra/ 47 | 48 | # below device files conflict with L4T package install 49 | declare -a remove_files=( 50 | "dev/random" 51 | "dev/urandom" 52 | ) 53 | 54 | for file in "${remove_files[@]}"; do 55 | uri=${WORK_DIR}/Linux_for_Tegra/rootfs/$file 56 | if [ -e "$uri" ] 57 | then 58 | rm -f $uri 59 | fi 60 | done 61 | 62 | ########## 63 | echo "Set up permission" 64 | 65 | # copy from rootfs to L4T does not keep the sudo flag 66 | # so, do set the flag here 67 | chroot ${WORK_DIR}/Linux_for_Tegra/rootfs bash -c "echo root:$ROOT_PWD | chpasswd" 68 | chroot ${WORK_DIR}/Linux_for_Tegra/rootfs bash -c "chown root:root /usr/bin/sudo" 69 | chroot ${WORK_DIR}/Linux_for_Tegra/rootfs bash -c "chmod u+s /usr/bin/sudo" 70 | 71 | # this to fix error when install package 72 | chroot ${WORK_DIR}/Linux_for_Tegra/rootfs bash -c "chown -R man:man /var/cache/man" 73 | chroot ${WORK_DIR}/Linux_for_Tegra/rootfs bash -c "chmod -R 775 /var/cache/man" 74 | 75 | ########## 76 | echo "Apply jetson binaries" 77 | 78 | pushd ${WORK_DIR}/Linux_for_Tegra/ 79 | ./apply_binaries.sh 80 | popd 81 | 82 | ########## 83 | echo "Add user: ${JETSON_USR}" 84 | 85 | pushd ${WORK_DIR}/Linux_for_Tegra/tools 86 | # ./l4t_create_default_user.sh -u ${JETSON_USR} -p ${JETSON_PWD} -n ${JETSON_NAME} --accept-license 87 | ./l4t_create_default_user.sh -u ${JETSON_USR} -p ${JETSON_PWD} -n ${JETSON_NAME} --autologin --accept-license 88 | popd 89 | 90 | cat << EOF > ${WORK_DIR}/Linux_for_Tegra/rootfs/etc/sudoers.d/${JETSON_USR} 91 | ${JETSON_USR} ALL=(ALL) NOPASSWD: ALL 92 | EOF 93 | 94 | 95 | ########## 96 | # if you want to modify BSP, please do that here 97 | # e.g. 98 | # ./custom_bsp_for_nano_dev_kit/step3b_customize_bsp.sh -------------------------------------------------------------------------------- /step4_flash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 4: flash image 7 | 8 | ########## 9 | echo "Check root permission" 10 | 11 | if [ "x$(whoami)" != "xroot" ]; then 12 | echo "This script requires root privilege!!!" 13 | exit 1 14 | fi 15 | 16 | ########## 17 | echo "Get environment" 18 | 19 | source ./step0_env.sh 20 | 21 | ########## 22 | echo "Set script options" 23 | 24 | set -e # exit on error 25 | set -o pipefail # exit on pipeline error 26 | set -u # treat unset variable as error 27 | 28 | ########## 29 | echo "Flash image" 30 | 31 | pushd ${WORK_DIR}/Linux_for_Tegra 32 | 33 | ./flash.sh ${JETSON_BOARD} ${JETSON_STORAGE} 34 | -------------------------------------------------------------------------------- /step5_create_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 5: create image 7 | 8 | ########## 9 | echo "Check root permission" 10 | 11 | if [ "x$(whoami)" != "xroot" ]; then 12 | echo "This script requires root privilege!!!" 13 | exit 1 14 | fi 15 | 16 | ########## 17 | echo "Get environment" 18 | 19 | source ./step0_env.sh 20 | 21 | ########## 22 | echo "Set script options" 23 | 24 | set -e # exit on error 25 | set -o pipefail # exit on pipeline error 26 | set -u # treat unset variable as error 27 | 28 | ########## 29 | IMAGE=${JETSON_BOARD}_${RELEASE}_${JETSON_PLAT}_${JETSON_REL}_${JETSON_DESKTOP}.img 30 | echo "Create image ${IMAGE}" 31 | 32 | pushd ${WORK_DIR}/Linux_for_Tegra/tools 33 | 34 | ./jetson-disk-image-creator.sh -o ${IMAGE} -b ${JETSON_BOARD_IMG} -r ${JETSON_BOARD_REV} 35 | 36 | if [ -f ${IMAGE} ]; then 37 | echo "Please copy the image at ${IMAGE}" 38 | fi 39 | -------------------------------------------------------------------------------- /step6_flash_SD.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a base custom image for jetson nano 4 | # vuquangtrong@gmail.com 5 | # 6 | # step 6: flash SD card 7 | 8 | ########## 9 | echo "Check root permission" 10 | 11 | if [ "x$(whoami)" != "xroot" ]; then 12 | echo "This script requires root privilege!!!" 13 | exit 1 14 | fi 15 | 16 | ########## 17 | echo "Get environment" 18 | 19 | source ./step0_env.sh 20 | 21 | ########## 22 | echo "Set script options" 23 | 24 | set -e # exit on error 25 | set -o pipefail # exit on pipeline error 26 | set -u # treat unset variable as error 27 | 28 | ########## 29 | echo "Check that $1 is a block device" 30 | 31 | if [ ! -b $1 ] || [ "$(lsblk | grep -w $(basename $1) | awk '{print $6}')" != "disk" ]; then 32 | echo "$1 is not a block device!!!" 33 | exit 1 34 | fi 35 | 36 | ########## 37 | IMAGE=${WORK_DIR}/Linux_for_Tegra/tools/${JETSON_BOARD}_${RELEASE}_${JETSON_PLAT}_${JETSON_REL}_${JETSON_DESKTOP}.img 38 | echo "Using ${IMAGE}" 39 | 40 | 41 | ########## 42 | if [ "$(mount | grep $1)" ]; then 43 | echo "Unmount $1" 44 | for mount_point in $(mount | grep $1 | awk '{ print $1}'); do 45 | sudo umount $mount_point 46 | done 47 | fi 48 | 49 | ########## 50 | echo "Flash $1" 51 | dd if=${IMAGE} of=$1 bs=4M conv=fsync status=progress 52 | 53 | ########## 54 | echo "Extend the partition" 55 | 56 | partprobe $1 57 | sgdisk -e $1 58 | 59 | end_sector=$(sgdisk -p $1 | grep -i "Total free space is" | awk '{ print $5 }') 60 | start_sector=$(sgdisk -i 1 $1 | grep "First sector" | awk '{print $3}') 61 | 62 | echo "start_sector = ${start_sector}" 63 | echo "end_sector = ${end_sector}" 64 | 65 | sgdisk -d 1 $1 66 | sgdisk -n 1:${start_sector}:${end_sector} $1 67 | sgdisk -c 1:APP $1 68 | 69 | ########## 70 | echo "Extend the filesystem" 71 | 72 | if [[ $(basename $1) =~ mmc ]]; then 73 | e2fsck -fp $1"p1" 74 | resize2fs $1"p1" 75 | fi 76 | 77 | if [[ $(basename $1) =~ sd ]]; then 78 | e2fsck -fp $1"1" 79 | resize2fs $1"1" 80 | fi 81 | 82 | sync 83 | 84 | echo "DONE!" 85 | --------------------------------------------------------------------------------