The essential lines from your boot crash image:
[ 4.035680] EXT4-fs (sda): ext4_check_descriptors: Block bitmap for group 0 overlaps superblock
[ 4.036225] EXT4-fs (sda): group descriptors corrupted!
[ 4.551311] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000100
[ 4.551519] CPU: 1 PID: 1 Comm: switch_root Not tainted 6.1.96 #1
So, an attempt to mount /dev/sda did happen, but may have failed because the filesystem was corrupted.
The process #1 was trying to execute the switch_root command when it died.
Both of these facts suggest that the system was in fact executing your initrd /init script and was almost successful in completing it.
The crash point would be the last line of your /init script:
exec switch_root /root /init
I don't see your script creating a symlink to busybox with the name switch_root anywhere.
Something like this in your creation script might help:
...
# sbin + dev
ln -s /bin/busybox /tmp/initrd/sbin/switch_root # added
cp /sbin/{modprobe,mkfs.ext4} /tmp/initrd/sbin/
cp -a /dev/{console,null,tty1,tty2,ttyS0} /tmp/initrd/dev/ # serial console port added
...
The ln -s /bin/busybox /tmp/initrd/sbin/switch_root might seem a bit counter-intuitive.
That command will create a special symbolic link file at what is /tmp/initrd/sbin/switch_root at the time of link creation and store the pathname /bin/busybox within it. The resulting symbolic link will point to path /bin/busybox at the time it'll be used. So, when this initrd is in use, there will be a link at /sbin/switch_root, pointing to /bin/busybox and it should work as expected.
The fact that there also happens to be a /bin/busybox in the host OS is not relevant for this command at all: a symbolic link is just a pathname, with no "target tracking" of any kind.
I also noticed that you are creating /dev/tty1 and /dev/tty2 within the initrd. Those are useless to you as your boot options include console=ttyS0. But you aren't creating a device node for your console device /dev/ttyS0 - that might explain why you don't see the results of the echo commands in the /init script.
The "run sh and manually switch root" looks better, but... your switch_root command is trying to run /init after switching to the new root filesystem that comes from the kernel-hd image file.
You are creating the essential directories:
mkdir -p /root/{bin,sbin,lib,dev,proc,sys,run}
and populating /root/bin (which will be /bin after the switch)
with busybox and its links:
cp /bin/busybox /root/bin
/root/bin/busybox --install -s /root/bin
But there is nothing at /root/init, which would be what
exec switch_root /root /init
attempts to execute after making /root into a real root filesystem.
Either you should have your initrd place a second script there (not the same script as the initrd uses, or you'll have an infinite recursion), or perhaps you should have switch_root start the init of busybox instead? You would have to supply it with an appropriate inittab file (at /root/etc/inittab before the switch). Then:
exec switch_root /root /bin/init
would start busybox's init.
Oh, and copying the contents of initrd's /dev into /root/dev/ before switching would be a good idea too.