Add support for arm{,64} cuttlefish phone platforms

Only 'aosp_cf_arm_phone-userdebug' can boot up successfully because
swiftshader does not support arm64.

Bug: 118442619
Test: lunch aosp_cf_arm_phone-userdebug && make -j128 dist
Test: lunch aosp_cf_arm64_phone-userdebug && make -j128 dist
Change-Id: I68f39bbe2bd7d6f0dac4ab8bce888dc9ca4babad
diff --git a/Android.bp b/Android.bp
index a901fe1..d9cbf16 100644
--- a/Android.bp
+++ b/Android.bp
@@ -59,19 +59,6 @@
     vendor: true,
 }
 
-// ARM code should not touch the VSoC window on an x86 CPU.
-cc_defaults {
-    name: "cuttlefish_native_isa",
-    target: {
-        android_arm: {
-            enabled: false,
-        },
-        android_arm64: {
-            enabled: false,
-        },
-    },
-}
-
 cc_defaults {
     name: "cuttlefish_guest_only",
     defaults: ["cuttlefish_base"],
@@ -137,7 +124,7 @@
             ],
         },
     },
-    defaults: ["cuttlefish_host_and_guest", "cuttlefish_native_isa"],
+    defaults: ["cuttlefish_host_and_guest"],
 }
 
 cc_test_host {
diff --git a/Android.mk b/Android.mk
index c38d99b..fa659d7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -11,7 +11,7 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-ifneq ($(filter vsoc_x86 vsoc_x86_64, $(TARGET_DEVICE)),)
+ifneq ($(filter vsoc_arm vsoc_arm64 vsoc_x86 vsoc_x86_64, $(TARGET_DEVICE)),)
 LOCAL_PATH:= $(call my-dir)
 include $(call first-makefiles-under,$(LOCAL_PATH))
 endif
diff --git a/common/frontend/socket_forward_proxy/Android.bp b/common/frontend/socket_forward_proxy/Android.bp
index 81ba9c4..74ef53a 100644
--- a/common/frontend/socket_forward_proxy/Android.bp
+++ b/common/frontend/socket_forward_proxy/Android.bp
@@ -41,5 +41,5 @@
             ],
         },
     },
-    defaults: ["cuttlefish_host_and_guest", "cuttlefish_native_isa"]
+    defaults: ["cuttlefish_host_and_guest"]
 }
diff --git a/common/frontend/socket_vsock_proxy/Android.bp b/common/frontend/socket_vsock_proxy/Android.bp
index 2cebe17..a0bc46f 100644
--- a/common/frontend/socket_vsock_proxy/Android.bp
+++ b/common/frontend/socket_vsock_proxy/Android.bp
@@ -39,5 +39,5 @@
             ],
         },
     },
-    defaults: ["cuttlefish_host_and_guest", "cuttlefish_native_isa"]
+    defaults: ["cuttlefish_host_and_guest"]
 }
diff --git a/common/vsoc/shm/lock.h b/common/vsoc/shm/lock.h
index cc86add..2049ba8 100644
--- a/common/vsoc/shm/lock.h
+++ b/common/vsoc/shm/lock.h
@@ -23,7 +23,13 @@
 // types that can be referenced below.
 
 // For _mm_pause()
+#if defined(__SSE2__)
 #include <x86intrin.h>
+#define _pause() _mm_pause()
+#elif defined(__arm__) || defined(__aarch64__)
+#include <arm_acle.h>
+#define _pause() __yield()
+#endif
 
 #include <atomic>
 #include <cstdint>
@@ -62,7 +68,7 @@
       if (lock_.compare_exchange_strong(expected, Sides::OurSide)) {
         return;
       }
-      _mm_pause();
+      _pause();
     }
   }
 
diff --git a/host/libs/vm_manager/cf_qemu.sh b/host/libs/vm_manager/cf_qemu.sh
index f3e2384..8cfff78 100755
--- a/host/libs/vm_manager/cf_qemu.sh
+++ b/host/libs/vm_manager/cf_qemu.sh
@@ -16,6 +16,33 @@
 # limitations under the License.
 #
 
+print_command() {
+  binary=$1; shift
+  binary_args=("$@")
+  printf %s "${binary}"
+  for i in "${binary_args[@]}"; do
+    case "$i" in
+      -*) printf "\\%s  %s " $'\n' "$i" ;;
+      *) printf "%s " "$i" ;;
+    esac
+  done
+  echo
+}
+
+exec_run() {
+  binary=$1; shift
+  binary_args=("$@")
+  print_command "${binary}" "${binary_args[@]}"
+  exec "${binary}" "${binary_args[@]}"
+}
+
+run() {
+  binary=$1; shift
+  binary_args=("$@")
+  print_command "${binary}" "${binary_args[@]}"
+  "${binary}" "${binary_args[@]}"
+}
+
 default_instance_number() {
     if [[ "${USER::5}" == "vsoc-" ]]; then
         echo "${USER: -2}"
@@ -30,15 +57,33 @@
 default_mobile_tap_name="cvd-mtap-${CUTTLEFISH_INSTANCE}"
 default_wifi_tap_name="cvd-wtap-${CUTTLEFISH_INSTANCE}"
 
+qemu_binary=${qemu_binary=/usr/bin/qemu-system-x86_64}
+dtc_binary=${dtc_binary:-dtc}
+
 if [[ -z "${ivshmem_vector_count}" ]]; then
     echo "The required ivshmem_vector_count environment variable is not set" >&2
     exit 1
 fi
 
+if [[ "${qemu_binary##*/}" = "qemu-system-aarch64" ]]; then
+  # On ARM, the early console can be PCI, and ISA is not supported
+  kernel_console_serial="pci-serial,addr=0xb"
+  machine="virt,gic_version=2"
+  cpu=cortex-a53
+else
+  # On x86, the early console must be ISA, not PCI, so we start to get kernel
+  # messages as soon as possible. ISA devices do not have 'addr' assignments.
+  kernel_console_serial="isa-serial"
+  machine="pc-i440fx-2.8,accel=kvm"
+  cpu=host
+fi
+
+# Put anything here that might affect the machine configuration generated by
+# QEMU. Anything which connects statefully to another service (like a socket)
+# should be added in another section below.
 args=(
-    -enable-kvm
     -name "guest=${instance_name:-${default_instance_name}},debug-threads=on"
-    -machine "pc-i440fx-2.8,accel=kvm,usb=off,dump-guest-core=off"
+    -machine "${machine},usb=off,dump-guest-core=off"
     -m "${memory_mb:-2048}"
     -realtime mlock=off
     -smp "${cpus:-2},sockets=${cpus:-2},cores=1,threads=1"
@@ -46,8 +91,6 @@
     -display none
     -no-user-config
     -nodefaults
-    -chardev "socket,id=charmonitor,path=${monitor_path:-${default_dir}/qemu_monitor.sock},nowait"
-    -mon "chardev=charmonitor,id=monitor,mode=control"
     -rtc "base=utc"
     -no-shutdown
     -boot "strict=on"
@@ -68,19 +111,83 @@
     -device "virtio-net-pci,netdev=hostnet0,id=net0,addr=0x2"
     -netdev "tap,id=hostnet1,ifname=${mobile_tap_name:-${default_mobile_tap_name}},script=no,downscript=no"
     -device "virtio-net-pci,netdev=hostnet1,id=net1,addr=0x3"
+    -device "virtio-balloon-pci,id=balloon0,addr=0x9"
+    -object "rng-random,id=objrng0,filename=/dev/urandom"
+    -device "virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=1024,period=2000,addr=0xa"
+    -cpu "${cpu}"
+    -msg "timestamp=on"
+)
+
+if [[ -n "${dtb_path}" ]]; then
+  if [[ "${qemu_binary##*/}" = "qemu-system-aarch64" ]]; then
+    # Decompile the dt fragment to include in our machine FDT
+    dtsi_path="${default_dir}/android.dtsi"
+    dtc_args=(
+      -I dtb
+      "${dtb_path}"
+      -O dts
+      -o "${dtsi_path}"
+    )
+    run "${dtc_binary}" "${dtc_args[@]}"
+
+    # Remove duplicate version definition from the dtsi
+    sed_binary=sed
+    sed_args=(
+      -i "/^\/dts-v1\/;$/d"
+      ${dtsi_path}
+    )
+    run "${sed_binary}" "${sed_args[@]}"
+
+    # Dump the machine FDT blob
+    dts_path="${default_dir}/cuttlefish.dts"
+    dtb_path="${default_dir}/cuttlefish.dtb"
+    dtb_args=(-machine "dumpdtb=${dtb_path}")
+    run "${qemu_binary}" "${args[@]}" "${dtb_args[@]}"
+
+    # Decompile the FDT blob
+    dtc_args=(
+      -I dtb
+      ${dtb_path}
+      -O dts
+      -o ${dts_path}
+    )
+    run "${dtc_binary}" "${dtc_args[@]}"
+
+    # Concatenate the dts and dtsi sources
+    echo "cat ${dtsi_path} >>${dts_path}"
+    echo
+    cat ${dtsi_path} >>${dts_path}
+
+    # Compile the patched machine FDT
+    dtc_args=(
+      -i "${dts_path%/*}"
+      -I dts
+      "${dts_path}"
+      -O dtb
+      -o "${dtb_path}"
+    )
+    run "${dtc_binary}" "${dtc_args[@]}"
+  fi
+
+  args+=(-dtb "${dtb_path}")
+fi
+
+# The services providing these sockets don't expect multiple connections,
+# so we must not have them in 'args' when we dump the machine FDT. It's
+# OK to add them now, after the dumping and patching has completed.
+# The (maybe patched) DTB can also be provided now.
+
+args+=(
+    -chardev "socket,id=charmonitor,path=${monitor_path:-${default_dir}/qemu_monitor.sock},nowait"
+    -mon "chardev=charmonitor,id=monitor,mode=control"
     -chardev "socket,id=charserial0,path=${kernel_log_socket_name:-${default_dir}/kernel-log}"
-    -device "isa-serial,chardev=charserial0,id=serial0"
+    -device "${kernel_console_serial},chardev=charserial0,id=serial0"
     -chardev "socket,id=charserial1,path=${console_path:-${default_dir}/console},server,nowait"
     -device "pci-serial,chardev=charserial1,id=serial1,addr=0xc"
     -chardev "file,id=charchannel0,path=${logcat_path:-${default_dir}/logcat},append=on"
     -device "virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=cf-logcat"
-    -device "virtio-balloon-pci,id=balloon0,addr=0x9"
-    -object "rng-random,id=objrng0,filename=/dev/urandom"
-    -device "virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=1024,period=2000,addr=0xa"
     -chardev "socket,path=${ivshmem_qemu_socket_path:-${default_dir}/ivshmem_socket_qemu},id=ivsocket"
     -device "ivshmem-doorbell,chardev=ivsocket,vectors=${ivshmem_vector_count},addr=0xd"
-    -cpu host
-    -msg "timestamp=on"
 )
 
 if [[ -n "${gdb_flag}" ]]; then
@@ -102,14 +209,4 @@
   args+=(-device "vhost-vsock-pci,guest-cid=${vsock_guest_cid}")
 fi
 
-printf %s "exec ${qemu_binary=/usr/bin/qemu-system-x86_64}"
-for i in "${args[@]}"; do
-  case "$i" in
-    -*) printf "\\%s  %s " $'\n' "$i" ;;
-    *) printf "%s " "$i" ;;
-  esac
-done
-echo
-
-exec "${qemu_binary=/usr/bin/qemu-system-x86_64}" \
-  "${args[@]}"
+exec_run "${qemu_binary}" "${args[@]}"