Step 1 Get the required tools

sudo apt-get update
sudo apt-get install -y \
  bc \
  bison \
  build-essential \
  ccache \
  clang \
  cpio \
  dwarves \
  flex \
  gawk \
  gcc \
  git \
  gzip \
  libcap-dev \
  libelf-dev \
  liblz4-dev \
  libncurses-dev \
  libssl-dev \
  libudev-dev \
  libzstd-dev \
  lz4 \
  python3 \
  python3-dev \
  python3-distutils-extra \
  python3-setuptools \
  xz-utils \
  zstd \
	crossbuild-essential-arm64 \
	qemu-system-arm

Step 2 Download kernel

You can choose the version of kernel you like at this website: cdn.kernel.org

and unzip it

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.30.tar.xz
tar xvf linux-6.6.30.tar.xz && cd linux-6.6.30

Step 3 Build it

Set the environment,

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

And make it

make defconfig
make menuconfig
# here you could ajust the options you like

Build

make -j$(nproc) Image

And it would generate the Image at arch/arm64/boot/Image, valide the Image file:

file arch/arm64/boot/Image
# should show Image: Linux kernel ARM64 boot executable Image, little-endian, 4K pages

Now you get a kernel!

Step 4 Build BusyBox

Download the BusxBox and unzip it.

wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xvf busybox-1.36.1.tar.bz2 && cd busybox-1.36.1

Config static compile:

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make menuconfig

if it compliant:

	*** Unable to find the ncurses libraries or the
	*** required header files.
	*** 'make menuconfig' requires the ncurses libraries.
	*** 
	*** Install ncurses (ncurses-devel) and try again.
	*** 

you could edit the file scripts/kconfig/lxdialog/Makefile at BusxBox directory, and comment this line:

always                := $(hostprogs-y) dochecklxdialog

Now you should make menuconfig successful.

And ajusting the build option:

Settings -> Build Options -> [*] Build static binary (no shared libs)

Network Utilities → [ ] tc # unselect it

And Exit and Save.

Now you can compile and install it

make -j$(nproc) && make install

After it the _install directory is the root Filesystem of arm64

Step 5 build initramfs

cd _install
mkdir -p proc sys dev etc/init.d

# create the init scrpit
cat > init <<EOF
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
echo "ARM64 System Ready!"
exec /bin/sh
EOF
chmod +x init

# pack it
find . | cpio -H newc -ov -R root:root | gzip > ../initramfs.cpio.gz

Step 6 QEMU launch

qemu-system-aarch64 \
    -M virt \         
    -cpu cortex-a72 \     
    -smp 4 \  
    -m 2G \                        
    -kernel /path/to/linux-6.6.30/arch/arm64/boot/Image \
    -initrd /path/to/busybox-1.36.1/initramfs.cpio.gz \
    -append "console=ttyAMA0 init=/init" \
    -nographic \
    -serial mon:stdio