diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4734958688757b98e9ff95a1dfa12a41e6787375
--- /dev/null
+++ b/.github/workflows/bors.yml
@@ -0,0 +1,306 @@
+name: CI (bors)
+
+on:
+  push:
+    branches:
+      - auto-libc
+      - try
+
+jobs:
+  docker_linux_tier1:
+    name: Docker Linux Tier1
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: true
+      matrix:
+        target: [
+          i686-unknown-linux-gnu,
+          x86_64-unknown-linux-gnu,
+        ]
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: TARGET=${{ matrix.target }} sh ./ci/install-rust.sh
+      - name: Execute run-docker.sh
+        run: LIBC_CI=1 sh ./ci/run-docker.sh ${{ matrix.target }}
+
+  macos:
+    name: macOS
+    runs-on: macos-10.15
+    strategy:
+      fail-fast: true
+      matrix:
+        target: [
+          x86_64-apple-darwin,
+        ]
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: TARGET=${{ matrix.target }} sh ./ci/install-rust.sh
+      - name: Execute run.sh
+        run: LIBC_CI=1 sh ./ci/run.sh ${{ matrix.target }}
+
+  windows:
+    name: Windows
+    runs-on: windows-2019
+    env:
+      OS: windows
+    strategy:
+      fail-fast: true
+      matrix:
+        include:
+          - target: x86_64-pc-windows-gnu
+            env:
+              ARCH_BITS: 64
+              ARCH: x86_64
+          - target: x86_64-pc-windows-msvc
+          # Disabled because broken:
+          #  https://github.com/rust-lang/libc/issues/1592
+          #- target: i686-pc-windows-gnu
+          #  env:
+          #    ARCH_BITS: 32
+          #    ARCH: i686
+          - target: i686-pc-windows-msvc
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: TARGET=${{ matrix.target }} sh ./ci/install-rust.sh
+        shell: bash
+      - name: Execute run.sh
+        run: LIBC_CI=1 sh ./ci/run.sh ${{ matrix.target }}
+        shell: bash
+
+  style_and_docs:
+    name: Style and docs
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: true
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: sh ./ci/install-rust.sh
+      - name: Check style
+        run: sh ci/style.sh
+      - name: Generate documentation
+        run: LIBC_CI=1 sh ci/dox.sh
+
+  docker_linux_tier2:
+    name: Docker Linux Tier2
+    needs: [docker_linux_tier1, style_and_docs]
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: true
+      max-parallel: 10
+      matrix:
+        target: [
+          aarch64-linux-android,
+          aarch64-unknown-linux-gnu,
+          aarch64-unknown-linux-musl,
+          arm-linux-androideabi,
+          arm-unknown-linux-gnueabihf,
+          arm-unknown-linux-musleabihf,
+          # FIXME: Disabled because currently broken, see:
+          # https://github.com/rust-lang/libc/issues/1591
+          # asmjs-unknown-emscripten,
+          # FIXME: Disabled due to https://github.com/rust-lang/libc/issues/1765
+          # i686-linux-android,
+          i686-unknown-linux-musl,
+          mips-unknown-linux-gnu,
+          mips-unknown-linux-musl,
+          mips64-unknown-linux-gnuabi64,
+          mips64el-unknown-linux-gnuabi64,
+          mipsel-unknown-linux-musl,
+          # FIXME: Figure out why this is disabled.
+          #powerpc-unknown-linux-gnu,
+          powerpc64-unknown-linux-gnu,
+          powerpc64le-unknown-linux-gnu,
+          s390x-unknown-linux-gnu,
+          riscv64gc-unknown-linux-gnu,
+          # FIXME: Figure out why this is disabled.
+          #wasm32-wasi,
+          sparc64-unknown-linux-gnu,
+          wasm32-unknown-emscripten,
+          x86_64-linux-android,
+          x86_64-unknown-linux-gnux32,
+          x86_64-unknown-linux-musl,
+        ]
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: TARGET=${{ matrix.target }} sh ./ci/install-rust.sh
+      - name: Execute run-docker.sh
+        run: LIBC_CI=1 sh ./ci/run-docker.sh ${{ matrix.target }}
+
+  # devkitpro's pacman needs to be connected from Docker.
+  docker_switch:
+    name: Docker Switch
+    needs: [docker_linux_tier1, style_and_docs]
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: true
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: sh ./ci/install-rust.sh
+      - name: Execute run-docker.sh
+        run: LIBC_CI=1 sh ./ci/run-docker.sh switch
+
+  build_channels_linux:
+    name: Build Channels Linux
+    needs: docker_linux_tier2
+    runs-on: ubuntu-18.04
+    env:
+      OS: linux
+    strategy:
+      fail-fast: true
+      max-parallel: 4
+      matrix:
+        toolchain: [
+          stable,
+          beta,
+          nightly,
+          1.13.0,
+          1.19.0,
+          1.24.0,
+          1.25.0,
+          1.30.0,
+        ]
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: TOOLCHAIN=${{ matrix.toolchain }} sh ./ci/install-rust.sh
+      - name: Execute build.sh
+        run: LIBC_CI=1 TOOLCHAIN=${{ matrix.toolchain }} sh ./ci/build.sh
+
+  build_channels_macos:
+    name: Build Channels macOS
+    needs: macos
+    runs-on: macos-10.15
+    env:
+      OS: macos
+    strategy:
+      fail-fast: true
+      max-parallel: 3
+      matrix:
+        toolchain: [
+          stable,
+          beta,
+          nightly,
+          1.13.0,
+          1.19.0,
+          1.24.0,
+          1.25.0,
+          1.30.0,
+        ]
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: TOOLCHAIN=${{ matrix.toolchain }} sh ./ci/install-rust.sh
+      - name: Execute build.sh
+        run: LIBC_CI=1 TOOLCHAIN=${{ matrix.toolchain }} sh ./ci/build.sh
+
+  semver_linux:
+    name: Semver Linux
+    needs: build_channels_linux
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: true
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        # FIXME: Pin nightly version to make semverver compilable.
+        run: TOOLCHAIN=nightly-2020-06-18 sh ./ci/install-rust.sh
+      - name: Check breaking changes
+        run: sh ci/semver.sh linux
+
+  semver_macos:
+    name: Semver macOS
+    needs: build_channels_macos
+    runs-on: macos-10.15
+    strategy:
+      fail-fast: true
+    steps:
+      - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.GITHUB_TOKEN }}"
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        # FIXME: Pin nightly version to make semverver compilable.
+        run: TOOLCHAIN=nightly-2020-06-18 sh ./ci/install-rust.sh
+      - name: Check breaking changes
+        run: sh ci/semver.sh macos
+
+  # These jobs doesn't actually test anything, but they're only used to tell
+  # bors the build completed, as there is no practical way to detect when a
+  # workflow is successful listening to webhooks only.
+  #
+  # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+
+  end_success:
+    name: bors build finished
+    if: github.event.pusher.name == 'bors' && success()
+    runs-on: ubuntu-18.04
+    needs: [
+      docker_linux_tier1,
+      docker_linux_tier2,
+      macos,
+      windows,
+      style_and_docs,
+      docker_switch,
+      build_channels_linux,
+      build_channels_macos,
+      semver_linux,
+      semver_macos
+    ]
+
+    steps:
+      - name: Mark the job as successful
+        run: exit 0
+
+  end_failure:
+    name: bors build finished
+    if: github.event.pusher.name == 'bors' && (failure() || cancelled())
+    runs-on: ubuntu-18.04
+    needs: [
+      docker_linux_tier1,
+      docker_linux_tier2,
+      macos,
+      windows,
+      style_and_docs,
+      docker_switch,
+      build_channels_linux,
+      build_channels_macos,
+      semver_linux,
+      semver_macos
+    ]
+
+    steps:
+      - name: Mark the job as a failure
+        run: exit 1
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a67a9efa5d4a5816e9ec8d83247818af14442713
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,86 @@
+name: CI
+
+on:
+  pull_request:
+    types: [opened, synchronize, reopened]
+  push:
+    branches:
+      - master
+
+jobs:
+  docker_linux_tier1:
+    name: Docker Linux Tier1
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: true
+      matrix:
+        target: [
+          i686-unknown-linux-gnu,
+          x86_64-unknown-linux-gnu,
+        ]
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: TARGET=${{ matrix.target }} sh ./ci/install-rust.sh
+      - name: Execute run-docker.sh
+        run: LIBC_CI=1 sh ./ci/run-docker.sh ${{ matrix.target }}
+
+  macos:
+    name: macOS
+    runs-on: macos-10.15
+    strategy:
+      fail-fast: true
+      matrix:
+        target: [
+          x86_64-apple-darwin,
+        ]
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: TARGET=${{ matrix.target }} sh ./ci/install-rust.sh
+      - name: Execute run.sh
+        run: LIBC_CI=1 sh ./ci/run.sh ${{ matrix.target }}
+
+  windows:
+    name: Windows
+    runs-on: windows-2019
+    env:
+      OS: windows
+    strategy:
+      fail-fast: true
+      matrix:
+        include:
+          - target: x86_64-pc-windows-gnu
+            env:
+              ARCH_BITS: 64
+              ARCH: x86_64
+          - target: x86_64-pc-windows-msvc
+          # Disabled because broken:
+          #  https://github.com/rust-lang/libc/issues/1592
+          #- target: i686-pc-windows-gnu
+          #  env:
+          #    ARCH_BITS: 32
+          #    ARCH: i686
+          - target: i686-pc-windows-msvc
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: TARGET=${{ matrix.target }} sh ./ci/install-rust.sh
+        shell: bash
+      - name: Execute run.sh
+        run: LIBC_CI=1 sh ./ci/run.sh ${{ matrix.target }}
+        shell: bash
+
+  style_and_docs:
+    name: Style and docs
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: true
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust toolchain
+        run: sh ./ci/install-rust.sh
+      - name: Check style
+        run: sh ci/style.sh
+      - name: Generate documentation
+        run: LIBC_CI=1 sh ci/dox.sh
diff --git a/ci/android-install-ndk.sh b/ci/android-install-ndk.sh
index 07d370395924f84ef0541dfbbcf3196d23203ce6..e37a5542c38a4306b6618662aa451c33aff8ff93 100644
--- a/ci/android-install-ndk.sh
+++ b/ci/android-install-ndk.sh
@@ -3,7 +3,7 @@
 set -ex
 
 NDK=android-ndk-r21d
-curl --retry 20 -O https://dl.google.com/android/repository/${NDK}-linux-x86_64.zip
+wget --tries=20 https://dl.google.com/android/repository/${NDK}-linux-x86_64.zip
 unzip -q ${NDK}-linux-x86_64.zip
 
 case "$1" in
diff --git a/ci/android-install-sdk.sh b/ci/android-install-sdk.sh
index 8c10c297fba7462aed07b1797add0fa1576bbaf4..8858de16d75831d8f10aa5767e2acbe5939319cd 100644
--- a/ci/android-install-sdk.sh
+++ b/ci/android-install-sdk.sh
@@ -11,7 +11,7 @@ set -ex
 
 SDK=4333796
 mkdir sdk
-curl --retry 20 https://dl.google.com/android/repository/sdk-tools-linux-${SDK}.zip -O
+wget --tries=20 https://dl.google.com/android/repository/sdk-tools-linux-${SDK}.zip
 unzip -q -d sdk sdk-tools-linux-${SDK}.zip
 
 case "$1" in
diff --git a/ci/android-sysimage.sh b/ci/android-sysimage.sh
index b0b5e903f2456709d63898c87c0db97eabf95d7a..d6eb32ed68a49ca44a8d42efc2ed0c7685d478c1 100644
--- a/ci/android-sysimage.sh
+++ b/ci/android-sysimage.sh
@@ -14,7 +14,7 @@ main() {
     apt-get install --no-install-recommends e2tools
 
     pushd "${td}"
-    curl --retry 5 -O "${URL}/${name}"
+    wget --tries=5 "${URL}/${name}"
     unzip -q "${name}"
 
     local system
diff --git a/ci/azure-install-rust.yml b/ci/azure-install-rust.yml
deleted file mode 100644
index ea5b6619740938ea59ba3a24b69c70195c8c81d8..0000000000000000000000000000000000000000
--- a/ci/azure-install-rust.yml
+++ /dev/null
@@ -1,89 +0,0 @@
-steps:
-  - bash: |
-      set -ex
-      toolchain=$TOOLCHAIN
-      if [ "$toolchain" = "" ]; then
-        toolchain=nightly
-      fi
-      if command -v rustup; then
-        rustup set profile minimal
-        rustup update --force $toolchain
-        rustup default $toolchain
-      else
-        curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain --profile=minimal
-        echo "##vso[task.prependpath]$HOME/.cargo/bin"
-      fi
-    displayName: Install rust (unix)
-    condition: ne( variables['Agent.OS'], 'Windows_NT' )
-  - script: |
-      @echo on
-      if not defined TOOLCHAIN set TOOLCHAIN=nightly
-      rustup set profile minimal
-      rustup update --no-self-update %TOOLCHAIN%-%TARGET%
-      rustup default %TOOLCHAIN%-%TARGET%
-    displayName: Install rust (windows)
-    condition: eq( variables['Agent.OS'], 'Windows_NT' )
-  - script: |
-      set -ex
-      if [ -n "${TARGET}" ]; then
-        rustup target add $TARGET
-      fi
-    condition: ne( variables['Agent.OS'], 'Windows_NT' )
-    displayName: Install target (unix)
-  - script: |
-      @echo on
-      if defined TARGET rustup target add %TARGET%
-    condition: eq( variables['Agent.OS'], 'Windows_NT' )
-    displayName: Install target (windows)
-  - script: |
-      @echo on
-      if "%ARCH%" == "i686" choco install mingw --x86 --force
-    condition: eq( variables['Agent.OS'], 'Windows_NT' )
-    displayName: Install MinGW32 (windows)
-  - bash: |
-      set -ex
-      gcc -print-search-dirs
-      /usr/bin/find "C:\ProgramData\Chocolatey" -name "crt2*"
-      /usr/bin/find "C:\ProgramData\Chocolatey" -name "dllcrt2*"
-      /usr/bin/find "C:\ProgramData\Chocolatey" -name "libmsvcrt*"
-    condition: eq( variables['Agent.OS'], 'Windows_NT' )	
-    displayName: Find GCC libraries (windows)
-  - bash: |
-      set -ex
-      if [[ -n ${ARCH_BITS} ]]; then
-        for i in crt2.o dllcrt2.o libmingwex.a libmsvcrt.a ; do
-          cp -f "/C/ProgramData/Chocolatey/lib/mingw/tools/install/mingw${ARCH_BITS}/${ARCH}-w64-mingw32/lib/$i" "`rustc --print sysroot`/lib/rustlib/${TARGET}/lib"
-        done
-      fi
-    condition: eq( variables['Agent.OS'], 'Windows_NT' )	
-    displayName: Fix MinGW (windows)
-  - bash: |
-        set -ex
-        rustc -Vv
-        cargo -V
-        rustup -Vv
-        rustup show
-        which rustc
-        which cargo
-        which rustup
-    displayName: Query rust and cargo versions
-  - script: |
-      @echo on
-      where gcc
-    condition: eq( variables['Agent.OS'], 'Windows_NT' )
-    displayName: Query gcc path
-  # This often fails fetching. Let's try several times.
-  - bash: |
-      set -ex
-      cargo generate-lockfile
-      N=5
-      n=0
-      until [ $n -ge $N ]
-      do
-          if cargo generate-lockfile ; then
-              break
-          fi
-          n=$((n+1))
-          sleep 1
-      done
-    displayName: Generate lockfiles
diff --git a/ci/azure.yml b/ci/azure.yml
deleted file mode 100644
index d2f46f9360e905a7486265bfbab51f646e3a24d4..0000000000000000000000000000000000000000
--- a/ci/azure.yml
+++ /dev/null
@@ -1,226 +0,0 @@
-variables:
-  - group: secrets
-resources:
-  repositories:
-    - repository: rustinfra
-      type: github
-      name: rust-lang/simpleinfra
-      endpoint: gnzlbg
-trigger: ["auto-libc","try"]
-pr: ["master"]
-
-jobs:
-  - job: DockerLinuxTier1
-    pool:
-      vmImage: ubuntu-18.04
-    steps:
-      - template: azure-install-rust.yml
-      - bash: LIBC_CI=1 sh ./ci/run-docker.sh $TARGET
-        displayName: Execute run-docker.sh
-    strategy:
-      matrix:
-        i686-unknown-linux-gnu:
-          TARGET: i686-unknown-linux-gnu
-        x86_64-unknown-linux-gnu:
-          TARGET: x86_64-unknown-linux-gnu
-
-  - job: DockerLinuxTier2
-    #dependsOn: DockerLinuxTier1
-    pool:
-      vmImage: ubuntu-18.04
-    steps:
-      - template: azure-install-rust.yml
-      - bash: LIBC_CI=1 sh ./ci/run-docker.sh $TARGET
-        displayName: Execute run-docker.sh
-    strategy:
-      matrix:
-        aarch64-unknown-linux-android:
-          TARGET: aarch64-linux-android
-        aarch64-unknown-linux-gnu:
-          TARGET: aarch64-unknown-linux-gnu
-        aarch64-unknown-linux-musl:
-          TARGET: aarch64-unknown-linux-musl
-        arm-linux-androideabi:
-          TARGET: arm-linux-androideabi
-        arm-unknown-linux-gnueabihf:
-          TARGET: arm-unknown-linux-gnueabihf
-        arm-unknown-linux-musleabihf:
-          TARGET: arm-unknown-linux-musleabihf
-        # Disabled because currently broken, see:
-        # https://github.com/rust-lang/libc/issues/1591
-        # asmjs-unknown-emscripten:
-        #  TARGET: asmjs-unknown-emscripten
-        # FIXME: Disabled due to https://github.com/rust-lang/libc/issues/1765
-        # i686-linux-android:
-        #   TARGET: i686-linux-android
-        i686-unknown-linux-musl:
-          TARGET: i686-unknown-linux-musl
-        mips-unknown-linux-gnu:
-          TARGET: mips-unknown-linux-gnu
-        mips-unknown-linux-musl:
-          TARGET: mips-unknown-linux-musl
-        mips64-unknown-linux-gnuabi64:
-          TARGET: mips64-unknown-linux-gnuabi64
-        mips64el-unknown-linux-gnuabi64:
-          TARGET: mips64el-unknown-linux-gnuabi64
-        mipsel-unknown-linux-musl:
-          TARGET: mipsel-unknown-linux-musl
-        #powerpc-unknown-linux-gnu:
-        #  TARGET: powerpc-unknown-linux-gnu
-        powerpc64-unknown-linux-gnu:
-          TARGET: powerpc64-unknown-linux-gnu
-        powerpc64le-unknown-linux-gnu:
-          TARGET: powerpc64le-unknown-linux-gnu
-        s390x-unknown-linux-gnu:
-          TARGET: s390x-unknown-linux-gnu
-        riscv64gc-unknown-linux-gnu:
-          TARGET: riscv64gc-unknown-linux-gnu
-        #wasm32-wasi
-        #  TARGET: wasm32-wasi
-        sparc64-unknown-linux-gnu:
-          TARGET: sparc64-unknown-linux-gnu
-        wasm32-unknown-emscripten:
-          TARGET: wasm32-unknown-emscripten
-        x86_64-linux-android:
-          TARGET: x86_64-linux-android
-        x86_64-unknown-linux-gnux32:
-          TARGET: x86_64-unknown-linux-gnux32
-        x86_64-unknown-linux-musl:
-          TARGET: x86_64-unknown-linux-musl
-
-  - job: DockerOSX64
-    pool:
-      vmImage: macos-10.15
-    steps:
-      - template: azure-install-rust.yml
-      - bash: LIBC_CI=1 sh ./ci/run.sh $TARGET
-        displayName: Execute run.sh
-    strategy:
-      matrix:
-        x86_64-apple-darwin:
-          TARGET: x86_64-apple-darwin
-
-  - job: Windows
-    pool:
-      vmImage: windows-2019
-    steps:
-      - template: azure-install-rust.yml
-      - bash: LIBC_CI=1 sh ./ci/run.sh $TARGET
-        displayName: Execute run.sh
-    strategy:
-      matrix:
-        x86_64-pc-windows-gnu:
-          TARGET: x86_64-pc-windows-gnu
-          ARCH_BITS: 64
-          ARCH: x86_64
-        x86_64-pc-windows-msvc:
-          TARGET: x86_64-pc-windows-msvc
-        # Disabled because broken:
-        #  https://github.com/rust-lang/libc/issues/1592
-        #i686-pc-windows-gnu:
-        #  TARGET: i686-pc-windows-gnu
-        #  ARCH_BITS: 32
-        #  ARCH: i686
-        i686-pc-windows-msvc:
-          TARGET: i686-pc-windows-msvc
-
-  - job: StyleAndDocs
-    pool:
-      vmImage: ubuntu-18.04
-    steps:
-      - template: azure-install-rust.yml
-      - script: sh ci/style.sh
-        displayName: Check style
-      - script: LIBC_CI=1 sh ci/dox.sh
-        displayName: Generate documentation
-      - template: azure-configs/static-websites.yml@rustinfra
-        parameters:
-          deploy_dir: target/doc
-
-  - job: SemverLinux
-    dependsOn: BuildChannelsLinux
-    continueOnError: true
-    pool:
-      vmImage: ubuntu-18.04
-    steps:
-      - template: azure-install-rust.yml
-      - script: sh ci/semver.sh linux
-        displayName: Check breaking changes
-
-  - job: SemverOSX
-    dependsOn: BuildChannelsOSX
-    continueOnError: true
-    pool:
-      vmImage: macos-10.15
-    steps:
-      - template: azure-install-rust.yml
-      - script: sh ci/semver.sh osx
-        displayName: Check breaking changes
-
-  - job: BuildChannelsLinux
-    dependsOn: StyleAndDocs
-    pool:
-      vmImage: ubuntu-18.04
-    steps:
-      - template: azure-install-rust.yml
-      - script: LIBC_CI=1 sh ./ci/build.sh
-        displayName: Execute build.sh
-    strategy:
-      matrix:
-        stable:
-          TOOLCHAIN: stable
-        beta:
-          TOOLCHAIN: beta
-        nightly:
-          TOOLCHAIN: nightly
-        1.13.0:
-          TOOLCHAIN: 1.13.0
-        1.19.0:
-          TOOLCHAIN: 1.19.0
-        1.24.0:
-          TOOLCHAIN: 1.24.0
-        1.25.0:
-          TOOLCHAIN: 1.25.0
-        1.30.0:
-          TOOLCHAIN: 1.30.0
-    variables:
-      OS: linux
-
-  # devkitpro's pacman needs to be connected from Docker.
-  - job: DockerSwitch
-    dependsOn: StyleAndDocs
-    pool:
-      vmImage: ubuntu-18.04
-    steps:
-      - template: azure-install-rust.yml
-      - bash: LIBC_CI=1 sh ./ci/run-docker.sh switch
-        displayName: Execute run-docker.sh
-
-  - job: BuildChannelsOSX
-    dependsOn: StyleAndDocs
-    pool:
-      vmImage: macos-10.15
-    steps:
-      - template: azure-install-rust.yml
-      - script: LIBC_CI=1 sh ./ci/build.sh
-        displayName: Execute build.sh
-    strategy:
-      matrix:
-        stable:
-          TOOLCHAIN: stable
-        beta:
-          TOOLCHAIN: beta
-        nightly:
-          TOOLCHAIN: nightly
-        1.13.0:
-          TOOLCHAIN: 1.13.0
-        1.19.0:
-          TOOLCHAIN: 1.19.0
-        1.24.0:
-          TOOLCHAIN: 1.24.0
-        1.25.0:
-          TOOLCHAIN: 1.25.0
-        1.30.0:
-          TOOLCHAIN: 1.30.0
-    variables:
-      OS: osx
diff --git a/ci/build.sh b/ci/build.sh
index eb8fb360d60165ed6240e404b9c95670febb4ac2..9decfb75cfb5d341a129102946730ebdf3c40b47 100644
--- a/ci/build.sh
+++ b/ci/build.sh
@@ -180,7 +180,7 @@ case "${OS}" in
         fi
 
         ;;
-    osx*)
+    macos*)
         TARGETS="${RUST_OSX_TARGETS}"
         ;;
     *)
@@ -269,7 +269,7 @@ i386-apple-ios \
 i686-apple-darwin \
 "
 
-if [ "${RUST}" = "nightly" ] && [ "${OS}" = "osx" ]; then
+if [ "${RUST}" = "nightly" ] && [ "${OS}" = "macos" ]; then
     for TARGET in $RUST_OSX_NO_CORE_TARGETS; do
         if echo "$TARGET" | grep -q "$FILTER"; then
             test_target build "$TARGET" 1
diff --git a/ci/docker/aarch64-linux-android/Dockerfile b/ci/docker/aarch64-linux-android/Dockerfile
index 98da29df014d4389dbe55a2c46db69bc241decfb..71a1e6bdece4896755681bb5be50a49dfd5f3dab 100644
--- a/ci/docker/aarch64-linux-android/Dockerfile
+++ b/ci/docker/aarch64-linux-android/Dockerfile
@@ -5,7 +5,7 @@ RUN apt-get update
 RUN apt-get install -y --no-install-recommends libc6-dev gcc
 RUN apt-get install -y --no-install-recommends \
   file \
-  curl \
+  wget \
   ca-certificates \
   python3 \
   python3-distutils \
diff --git a/ci/docker/arm-linux-androideabi/Dockerfile b/ci/docker/arm-linux-androideabi/Dockerfile
index c88ceebe07a72651701c86e9ed7ab179d3e6ce47..3b200402c52d9cf37dff6dbe3f77e6703cbee5d6 100644
--- a/ci/docker/arm-linux-androideabi/Dockerfile
+++ b/ci/docker/arm-linux-androideabi/Dockerfile
@@ -5,7 +5,7 @@ RUN apt-get update
 RUN apt-get install -y --no-install-recommends libc6-dev gcc
 RUN apt-get install -y --no-install-recommends \
   file \
-  curl \
+  wget \
   ca-certificates \
   python3 \
   python3-distutils \
diff --git a/ci/docker/x86_64-linux-android/Dockerfile b/ci/docker/x86_64-linux-android/Dockerfile
index 87263bce9fec353bedb986ddcc2ed4cfa2f76a7d..50849e4cabc58a365f9ee074fa28e0353c3ba47d 100644
--- a/ci/docker/x86_64-linux-android/Dockerfile
+++ b/ci/docker/x86_64-linux-android/Dockerfile
@@ -3,7 +3,7 @@ FROM ubuntu:20.04
 RUN apt-get update && \
     apt-get install -y --no-install-recommends \
   ca-certificates \
-  curl \
+  wget \
   gcc \
   libc-dev \
   python3 \
diff --git a/ci/install-rust.sh b/ci/install-rust.sh
new file mode 100644
index 0000000000000000000000000000000000000000..598dec282d003abe4ddf64d6a247c7b9cadcaa69
--- /dev/null
+++ b/ci/install-rust.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env sh
+# This is intended to be used in CI only.
+
+set -ex
+
+echo "Setup toolchain"
+toolchain=
+if [ -n "$TOOLCHAIN" ]; then
+  toolchain=$TOOLCHAIN
+else
+  toolchain=nightly
+fi
+if [ "$OS" = "windows" ]; then
+  : "${TARGET?The TARGET environment variable must be set.}"
+  rustup set profile minimal
+  rustup update --force $toolchain-"$TARGET"
+  rustup default $toolchain-"$TARGET"
+else
+  rustup set profile minimal
+  rustup update --force $toolchain
+  rustup default $toolchain
+fi
+
+if [ -n "$TARGET" ]; then
+  echo "Install target"
+  rustup target add "$TARGET"
+fi
+
+if [ "$OS" = "windows" ]; then
+  if [ "$ARCH_BITS" = "i686" ]; then
+    echo "Install MinGW32"
+    choco install mingw --x86 --force
+  fi
+
+  echo "Find GCC libraries"
+  gcc -print-search-dirs
+  /usr/bin/find "C:\ProgramData\Chocolatey" -name "crt2*"
+  /usr/bin/find "C:\ProgramData\Chocolatey" -name "dllcrt2*"
+  /usr/bin/find "C:\ProgramData\Chocolatey" -name "libmsvcrt*"
+
+  if [ -n "$ARCH_BITS" ]; then
+    echo "Fix MinGW"
+    for i in crt2.o dllcrt2.o libmingwex.a libmsvcrt.a ; do
+      cp -f "/C/ProgramData/Chocolatey/lib/mingw/tools/install/mingw$ARCH_BITS/$ARCH-w64-mingw32/lib/$i" "$(rustc --print sysroot)/lib/rustlib/$TARGET/lib"
+    done
+  fi
+fi
+
+echo "Query rust and cargo versions"
+rustc -Vv
+cargo -V
+rustup -Vv
+rustup show
+which rustc
+which cargo
+which rustup
+
+echo "Generate lockfile"
+N=5
+n=0
+until [ $n -ge $N ]
+do
+  if cargo generate-lockfile; then
+    break
+  fi
+  n=$((n+1))
+  sleep 1
+done
diff --git a/ci/linux-sparc64.sh b/ci/linux-sparc64.sh
index d5b0462b4a8436190e43fa75ec12511aaf67b78b..57aa3b5fb9db7aad7698162ba977818b75a0c3f6 100644
--- a/ci/linux-sparc64.sh
+++ b/ci/linux-sparc64.sh
@@ -5,11 +5,11 @@ set -ex
 mkdir -m 777 /qemu
 cd /qemu
 
-curl --retry 5 -LO https://cdimage.debian.org/cdimage/ports/2020-04-19/debian-10.0-sparc64-NETINST-1.iso
-7z e debian-10.0-sparc64-NETINST-1.iso install/initrd.gz
-7z e debian-10.0-sparc64-NETINST-1.iso install/vmlinux
+curl --retry 5 -LO https://cdimage.debian.org/cdimage/ports/snapshots/2020-10-13/debian-10.0.0-sparc64-NETINST-1.iso
+7z e debian-10.0.0-sparc64-NETINST-1.iso install/initrd.gz
+7z e debian-10.0.0-sparc64-NETINST-1.iso install/vmlinux
 mv vmlinux kernel
-rm debian-10.0-sparc64-NETINST-1.iso
+rm debian-10.0.0-sparc64-NETINST-1.iso
 
 mkdir init
 cd init
diff --git a/ci/semver.sh b/ci/semver.sh
index 392f5206dd7ff5931f4c35c5ad80f971402bb704..75f83aedbb11ce3aba27c41c84a86d6f6133cc8e 100644
--- a/ci/semver.sh
+++ b/ci/semver.sh
@@ -13,15 +13,10 @@ if ! rustc --version | grep -E "nightly" ; then
     exit 1
 fi
 
-# FIXME: Pin nightly version to make semverver compile.
-NIGHTLY_DATE=nightly-2020-06-18
-
-rustup override set ${NIGHTLY_DATE}
-
 rustup component add rustc-dev llvm-tools-preview
 
 # FIXME: Use upstream once it gets rustup.
-cargo +${NIGHTLY_DATE} install semververfork
+cargo install semververfork
 
 TARGETS=
 case "${OS}" in
@@ -53,7 +48,7 @@ x86_64-fortanix-unknown-sgx \
 wasm32-unknown-unknown \
 "
     ;;
-    *osx*)
+    *macos*)
         TARGETS="\
 aarch64-apple-ios \
 x86_64-apple-darwin \
@@ -77,5 +72,5 @@ for TARGET in $TARGETS; do
     done
 
     # FIXME: Use upstream once it gets rustup.
-    cargo +${NIGHTLY_DATE} semverfork --api-guidelines --target="${TARGET}"
+    cargo semverfork --api-guidelines --target="${TARGET}"
 done
diff --git a/ci/style.sh b/ci/style.sh
index 7acd128de2480f6dd9a007ec743a66e0ded30582..6dc9f1333c9b932edda5e2c96cf70997053cb660 100644
--- a/ci/style.sh
+++ b/ci/style.sh
@@ -11,7 +11,8 @@ if rustup component add rustfmt-preview ; then
 fi
 
 if shellcheck --version ; then
-    shellcheck -e SC2103 ci/*.sh
+    # GHA's shellcheck is too old (0.4.6) and cannot handle SC2153 correctly.
+    shellcheck -e SC2103 -e SC2153 ci/*.sh
 else
     echo "shellcheck not found"
     exit 1