summaryrefslogblamecommitdiffstats
path: root/.travis.yml
blob: 1054ec5d29aab9f2137390bd5c9f74336542236f (plain) (tree)
1
2
3
4
5
6
7
8
9

                                                                    
         
           
           
         
      
                                                               
                                    
                                                  
                                                                                            
               
              
           
                            
 

             
                          


                     
                    
                       


                        
                  
                       
                  
                    
                         

                             
                  
                        
                      
                       
                   
                
             
                          
 
 

                                                                     

              
                                                                                                                                                                                              
                      
 
         
                       
                                                  
                       
                               
                                                                                                      
                                                                                                                      
                                                               
                            
 
 

                                
 

                                                        
                                                     
 
                                    
              
                                            
                                                                                  
                                                                
       
                                               




                                                              




                                   
             
         
                                                        
 
     
          
                               
                                            
                                                         
 
                                                                
                                                
          
                                                  
                                                              
                                                         
 
                                                                             
                                      
                                                                       
                                                       
 
                                                                                              
                              
                                                      
                                                           
 
                                                           
                                        
                                                                         
                                                         
 
                                                                                   
                                           
                                                          
                                                  
 
                                              
                                                             
                                                  
 
                                                     
                                     
          
                                                              
                                                                  
                                                         

                   
                            
                  
 
                                                                     
                          
                                                                 
                                                           
                     
 
                                  
                                                       
                                                            
                     
                                                                                                                       
 
                                   
                                                                              
                                                           
                     
 
                                 
                            
                  
          
                                                               
                                                       
 
                                                                  
                                                   
                                                           
                                                         

                     
                                                                  
                                                
                                                                             
 
                                               
                                                                              
 
                                            
                                                                           
 
                                     
                                            
                  
             
            
                      



                                       
                   



                                
                             





                              
                        
                          
                               

                                   
                              
                             



                       
                                              
                                                              
                     
                                                  
                                                                                                                    
 
                                      
                                  
                                                      
                                         
                                   
                                                           
 
                                           
                                          
                                                                                                            
                                         
                                   
                                                           
 
                                                          
                                                  
                                                                                                                             
                                         
                                   
                                                           
 
                                     
                 





















                            
                              

                                                                             
                         
 
                                   
                 





















                            
                              
                                             
                                                                                      
 
                                   






















                            
                              

                                                                                              
                         
             






                                                     
 





































                                                                          
                                         
                  
                     





















                            
                                    
                                                                 
                         
 

                                                                                      
                                                                



                                                                                               
                                           
                                                         


                                                                                    
                                                                                
                      
                          
# The current Travis default is a VM based 16.04 Xenial on GCE
# Additional builds with specific requirements for a full VM need to
# be added as additional matrix: entries later on
os: linux
dist: focal
language: c
compiler:
  - gcc
cache:
  # There is one cache per branch and compiler version.
  # characteristics of each job are used to identify the cache:
  # - OS name (currently only linux)
  # - OS distribution (for Linux, bionic or focal)
  # - Names and values of visible environment variables set in .travis.yml or Settings panel
  timeout: 1200
  ccache: true
  pip: true
  directories:
  - $HOME/avocado/data/cache


addons:
  apt:
    packages:
      # Build dependencies
      - libaio-dev
      - libattr1-dev
      - libbrlapi-dev
      - libcap-ng-dev
      - libgcc-7-dev
      - libgnutls28-dev
      - libgtk-3-dev
      - libiscsi-dev
      - liblttng-ust-dev
      - libncurses5-dev
      - libnfs-dev
      - libnss3-dev
      - libpixman-1-dev
      - libpng-dev
      - librados-dev
      - libsdl2-dev
      - libsdl2-image-dev
      - libseccomp-dev
      - libspice-protocol-dev
      - libspice-server-dev
      - libssh-dev
      - liburcu-dev
      - libusb-1.0-0-dev
      - libvdeplug-dev
      - libvte-2.91-dev
      - libzstd-dev
      - sparse
      - uuid-dev
      - gcovr
      # Tests dependencies
      - genisoimage


# The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
# to prevent IRC notifications from forks. This was created using:
# $ travis encrypt -r "qemu/qemu" "irc.oftc.net#qemu"
notifications:
  irc:
    channels:
      - secure: "F7GDRgjuOo5IUyRLqSkmDL7kvdU4UcH3Lm/W2db2JnDHTGCqgEdaYEYKciyCLZ57vOTsTsOgesN8iUT7hNHBd1KWKjZe9KDTZWppWRYVwAwQMzVeSOsbbU4tRoJ6Pp+3qhH1Z0eGYR9ZgKYAoTumDFgSAYRp4IscKS8jkoedOqM="
    on_success: change
    on_failure: always


env:
  global:
    - SRC_DIR=".."
    - BUILD_DIR="build"
    - BASE_CONFIG="--disable-docs --disable-tools"
    - TEST_BUILD_CMD=""
    - TEST_CMD="make check V=1"
    # This is broadly a list of "mainline" softmmu targets which have support across the major distros
    - MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
    - CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
    - CCACHE_MAXSIZE=1G
    - G_MESSAGES_DEBUG=error


git:
  # we want to do this ourselves
  submodules: false

# Common first phase for all steps
before_install:
  - if command -v ccache ; then ccache --zero-stats ; fi
  - export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
  - echo "=== Using ${JOBS} simultaneous jobs ==="

# Configure step - may be overridden
before_script:
  - mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
  - ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }

# Main build & test - rarely overridden - controlled by TEST_CMD
script:
  - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
  - |
    if [ "$BUILD_RC" -eq 0 ] && [ -n "$TEST_BUILD_CMD" ]; then
        ${TEST_BUILD_CMD} || BUILD_RC=$?
    else
        $(exit $BUILD_RC);
    fi
  - |
    if [ "$BUILD_RC" -eq 0 ] ; then
        ${TEST_CMD} ;
    else
        $(exit $BUILD_RC);
    fi
after_script:
  - df -h
  - if command -v ccache ; then ccache --show-stats ; fi


jobs:
  include:
    - name: "GCC static (user)"
      env:
        - CONFIG="--disable-system --static"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"

    # Just build tools and run minimal unit and softfloat checks
    - name: "GCC check-unit and check-softfloat"
      env:
        - BASE_CONFIG="--enable-tools"
        - CONFIG="--disable-user --disable-system"
        - TEST_CMD="make check-unit check-softfloat -j${JOBS}"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"


    # --enable-debug implies --enable-debug-tcg, also runs quite a bit slower
    - name: "GCC debug (main-softmmu)"
      env:
        - CONFIG="--enable-debug --target-list=${MAIN_SOFTMMU_TARGETS}"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug"


    # TCG debug can be run just on its own and is mostly agnostic to user/softmmu distinctions
    - name: "GCC debug (user)"
      env:
        - CONFIG="--enable-debug-tcg --disable-system"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"

    # Module builds are mostly of interest to major distros
    - name: "GCC modules (main-softmmu)"
      env:
        - CONFIG="--enable-modules --target-list=${MAIN_SOFTMMU_TARGETS}"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"


    # Alternate coroutines implementations are only really of interest to KVM users
    # However we can't test against KVM on Travis so we can only run unit tests
    - name: "check-unit coroutine=ucontext"
      env:
        - CONFIG="--with-coroutine=ucontext --disable-tcg"
        - TEST_CMD="make check-unit -j${JOBS} V=1"


    - name: "check-unit coroutine=sigaltstack"
      env:
        - CONFIG="--with-coroutine=sigaltstack --disable-tcg"
        - TEST_CMD="make check-unit -j${JOBS} V=1"


    # Check we can build docs and tools (out of tree)
    - name: "tools and docs (bionic)"
      dist: bionic
      env:
        - BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
        - BASE_CONFIG="--enable-tools --enable-docs"
        - CONFIG="--target-list=x86_64-softmmu,aarch64-linux-user"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
      addons:
        apt:
          packages:
            - python3-sphinx
            - perl


    # Test with Clang for compile portability (Travis uses clang-5.0)
    - name: "Clang (user)"
      env:
        - CONFIG="--disable-system --host-cc=clang --cxx=clang++"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
      compiler: clang


    - name: "Clang (main-softmmu)"
      env:
        - CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS}
                  --host-cc=clang --cxx=clang++"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-sanitize"
      compiler: clang
      before_script:
        - mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
        - ${SRC_DIR}/configure ${CONFIG} --extra-cflags="-fsanitize=undefined -Werror" || { cat config.log && exit 1; }


    - name: "Clang (other-softmmu)"
      env:
        - CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}
                  --host-cc=clang --cxx=clang++"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
      compiler: clang


    # gprof/gcov are GCC features
    - name: "GCC gprof/gcov"
      dist: bionic
      env:
        - CONFIG="--enable-gprof --enable-gcov --disable-libssh
                  --target-list=${MAIN_SOFTMMU_TARGETS}"
      after_success:
        - ${SRC_DIR}/scripts/travis/coverage-summary.sh


    # We manually include builds which we disable "make check" for
    - name: "GCC without-default-devices (softmmu)"
      env:
        - CONFIG="--without-default-devices --disable-user"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
        - TEST_CMD=""


    # We don't need to exercise every backend with every front-end
    - name: "GCC trace log,simple,syslog (user)"
      env:
        - CONFIG="--enable-trace-backends=log,simple,syslog --disable-system"
        - TEST_CMD=""


    - name: "GCC trace ftrace (x86_64-softmmu)"
      env:
        - CONFIG="--enable-trace-backends=ftrace --target-list=x86_64-softmmu"
        - TEST_CMD=""


    - name: "GCC trace ust (x86_64-softmmu)"
      env:
        - CONFIG="--enable-trace-backends=ust --target-list=x86_64-softmmu"
        - TEST_CMD=""


    # Using newer GCC with sanitizers
    - name: "GCC9 with sanitizers (softmmu)"
      dist: bionic
      addons:
        apt:
          update: true
          sources:
            # PPAs for newer toolchains
            - ubuntu-toolchain-r-test
          packages:
            # Extra toolchains
            - gcc-9
            - g++-9
            # Build dependencies
            - libaio-dev
            - libattr1-dev
            - libbrlapi-dev
            - libcap-ng-dev
            - libgnutls28-dev
            - libgtk-3-dev
            - libiscsi-dev
            - liblttng-ust-dev
            - libnfs-dev
            - libncurses5-dev
            - libnss3-dev
            - libpixman-1-dev
            - libpng-dev
            - librados-dev
            - libsdl2-dev
            - libsdl2-image-dev
            - libseccomp-dev
            - libspice-protocol-dev
            - libspice-server-dev
            - liburcu-dev
            - libusb-1.0-0-dev
            - libvte-2.91-dev
            - sparse
            - uuid-dev
      language: generic
      compiler: none
      env:
        - COMPILER_NAME=gcc CXX=g++-9 CC=gcc-9
        - CONFIG="--cc=gcc-9 --cxx=g++-9 --disable-linux-user"
        - TEST_CMD=""
      before_script:
        - mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
        - ${SRC_DIR}/configure ${CONFIG} --extra-cflags="-g3 -O0 -fsanitize=thread" || { cat config.log && exit 1; }


    # Run check-tcg against linux-user
    - name: "GCC check-tcg (user)"
      env:
        - CONFIG="--disable-system --enable-debug-tcg"
        - TEST_BUILD_CMD="make build-tcg"
        - TEST_CMD="make check-tcg"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"


    # Run check-tcg against softmmu targets
    - name: "GCC check-tcg (some-softmmu)"
      env:
        - CONFIG="--enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
        - TEST_BUILD_CMD="make build-tcg"
        - TEST_CMD="make check-tcg"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"


    # Run check-tcg against softmmu targets (with plugins)
    - name: "GCC plugins check-tcg (some-softmmu)"
      env:
        - CONFIG="--enable-plugins --enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
        - TEST_BUILD_CMD="make build-tcg"
        - TEST_CMD="make check-tcg"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"

    - name: "[aarch64] GCC check-tcg"
      arch: arm64
      dist: focal
      addons:
        apt_packages:
          - libaio-dev
          - libattr1-dev
          - libbrlapi-dev
          - libcap-ng-dev
          - libgcrypt20-dev
          - libgnutls28-dev
          - libgtk-3-dev
          - libiscsi-dev
          - liblttng-ust-dev
          - libncurses5-dev
          - libnfs-dev
          - libnss3-dev
          - libpixman-1-dev
          - libpng-dev
          - librados-dev
          - libsdl2-dev
          - libseccomp-dev
          - liburcu-dev
          - libusb-1.0-0-dev
          - libvdeplug-dev
          - libvte-2.91-dev
          # Tests dependencies
          - genisoimage
      env:
        - TEST_CMD="make check check-tcg V=1"
        - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS}"
        - UNRELIABLE=true

    - name: "[ppc64] GCC check-tcg"
      arch: ppc64le
      dist: focal
      addons:
        apt_packages:
          - libaio-dev
          - libattr1-dev
          - libbrlapi-dev
          - libcap-ng-dev
          - libgcrypt20-dev
          - libgnutls28-dev
          - libgtk-3-dev
          - libiscsi-dev
          - liblttng-ust-dev
          - libncurses5-dev
          - libnfs-dev
          - libnss3-dev
          - libpixman-1-dev
          - libpng-dev
          - librados-dev
          - libsdl2-dev
          - libseccomp-dev
          - liburcu-dev
          - libusb-1.0-0-dev
          - libvdeplug-dev
          - libvte-2.91-dev
          # Tests dependencies
          - genisoimage
      env:
        - TEST_CMD="make check check-tcg V=1"
        - CONFIG="--disable-containers --target-list=ppc64-softmmu,ppc64le-linux-user"

    - name: "[s390x] GCC check-tcg"
      arch: s390x
      dist: bionic
      addons:
        apt_packages:
          - libaio-dev
          - libattr1-dev
          - libbrlapi-dev
          - libcap-ng-dev
          - libgcrypt20-dev
          - libgnutls28-dev
          - libgtk-3-dev
          - libiscsi-dev
          - liblttng-ust-dev
          - libncurses5-dev
          - libnfs-dev
          - libnss3-dev
          - libpixman-1-dev
          - libpng-dev
          - librados-dev
          - libsdl2-dev
          - libseccomp-dev
          - liburcu-dev
          - libusb-1.0-0-dev
          - libvdeplug-dev
          - libvte-2.91-dev
          # Tests dependencies
          - genisoimage
      env:
        - TEST_CMD="make check check-tcg V=1"
        - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user"
        - UNRELIABLE=true
      script:
        - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
        - |
          if [ "$BUILD_RC" -eq 0 ] ; then
              mv pc-bios/s390-ccw/*.img pc-bios/ ;
              ${TEST_CMD} ;
          else
              $(exit $BUILD_RC);
          fi

    - name: "[s390x] GCC (other-softmmu)"
      arch: s390x
      dist: bionic
      addons:
        apt_packages:
          - libaio-dev
          - libattr1-dev
          - libcap-ng-dev
          - libgnutls28-dev
          - libiscsi-dev
          - liblttng-ust-dev
          - liblzo2-dev
          - libncurses-dev
          - libnfs-dev
          - libnss3-dev
          - libpixman-1-dev
          - libsdl2-dev
          - libsdl2-image-dev
          - libseccomp-dev
          - libsnappy-dev
          - libzstd-dev
          - nettle-dev
          - xfslibs-dev
          # Tests dependencies
          - genisoimage
      env:
        - CONFIG="--disable-containers --audio-drv-list=sdl --disable-user
                  --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"

    - name: "[s390x] GCC (user)"
      arch: s390x
      dist: bionic
      addons:
        apt_packages:
          - libgcrypt20-dev
          - libgnutls28-dev
      env:
        - CONFIG="--disable-containers --disable-system"

    - name: "[s390x] Clang (disable-tcg)"
      arch: s390x
      dist: bionic
      compiler: clang
      addons:
        apt_packages:
          - libaio-dev
          - libattr1-dev
          - libbrlapi-dev
          - libcap-ng-dev
          - libgcrypt20-dev
          - libgnutls28-dev
          - libgtk-3-dev
          - libiscsi-dev
          - liblttng-ust-dev
          - libncurses5-dev
          - libnfs-dev
          - libnss3-dev
          - libpixman-1-dev
          - libpng-dev
          - librados-dev
          - libsdl2-dev
          - libseccomp-dev
          - liburcu-dev
          - libusb-1.0-0-dev
          - libvdeplug-dev
          - libvte-2.91-dev
      env:
        - TEST_CMD="make check-unit"
        - CONFIG="--disable-containers --disable-tcg --enable-kvm
                  --disable-tools --host-cc=clang --cxx=clang++"
        - UNRELIABLE=true

    # Release builds
    # The make-release script expect a QEMU version, so our tag must start with a 'v'.
    # This is the case when release candidate tags are created.
    - name: "Release tarball"
      if: tag IS present AND tag =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/
      env:
        # We want to build from the release tarball
        - BUILD_DIR="release/build/dir" SRC_DIR="../../.."
        - BASE_CONFIG="--prefix=$PWD/dist"
        - CONFIG="--target-list=x86_64-softmmu,aarch64-softmmu,armeb-linux-user,ppc-linux-user"
        - TEST_CMD="make install -j${JOBS}"
        - QEMU_VERSION="${TRAVIS_TAG:1}"
        - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
      script:
        - make -C ${SRC_DIR} qemu-${QEMU_VERSION}.tar.bz2
        - ls -l ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2
        - tar -xf ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2 && cd qemu-${QEMU_VERSION}
        - mkdir -p release-build && cd release-build
        - ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
        - make install
  allow_failures:
    - env: UNRELIABLE=true
n> Aml *aml_irq_no_flags(uint8_t irq) { uint16_t irq_mask; Aml *var = aml_alloc(); assert(irq < 16); build_append_byte(var->buf, 0x22); /* IRQ descriptor 2 byte form */ irq_mask = 1U << irq; build_append_byte(var->buf, irq_mask & 0xFF); /* IRQ mask bits[7:0] */ build_append_byte(var->buf, irq_mask >> 8); /* IRQ mask bits[15:8] */ return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLNot */ Aml *aml_lnot(Aml *arg) { Aml *var = aml_opcode(0x92 /* LNotOp */); aml_append(var, arg); return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLEqual */ Aml *aml_equal(Aml *arg1, Aml *arg2) { Aml *var = aml_opcode(0x93 /* LequalOp */); aml_append(var, arg1); aml_append(var, arg2); return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreater */ Aml *aml_lgreater(Aml *arg1, Aml *arg2) { Aml *var = aml_opcode(0x94 /* LGreaterOp */); aml_append(var, arg1); aml_append(var, arg2); return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreaterEqual */ Aml *aml_lgreater_equal(Aml *arg1, Aml *arg2) { /* LGreaterEqualOp := LNotOp LLessOp */ Aml *var = aml_opcode(0x92 /* LNotOp */); build_append_byte(var->buf, 0x95 /* LLessOp */); aml_append(var, arg1); aml_append(var, arg2); return var; } /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefIfElse */ Aml *aml_if(Aml *predicate) { Aml *var = aml_bundle(0xA0 /* IfOp */, AML_PACKAGE); aml_append(var, predicate); return var; } /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefElse */ Aml *aml_else(void) { Aml *var = aml_bundle(0xA1 /* ElseOp */, AML_PACKAGE); return var; } /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefWhile */ Aml *aml_while(Aml *predicate) { Aml *var = aml_bundle(0xA2 /* WhileOp */, AML_PACKAGE); aml_append(var, predicate); return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */ Aml *aml_method(const char *name, int arg_count, AmlSerializeFlag sflag) { Aml *var = aml_bundle(0x14 /* MethodOp */, AML_PACKAGE); int methodflags; /* * MethodFlags: * bit 0-2: ArgCount (0-7) * bit 3: SerializeFlag * 0: NotSerialized * 1: Serialized * bit 4-7: reserved (must be 0) */ assert(arg_count < 8); methodflags = arg_count | (sflag << 3); build_append_namestring(var->buf, "%s", name); build_append_byte(var->buf, methodflags); /* MethodFlags: ArgCount */ return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefDevice */ Aml *aml_device(const char *name_format, ...) { va_list ap; Aml *var = aml_bundle(0x82 /* DeviceOp */, AML_EXT_PACKAGE); va_start(ap, name_format); build_append_namestringv(var->buf, name_format, ap); va_end(ap); return var; } /* ACPI 1.0b: 6.4.1 ASL Macros for Resource Descriptors */ Aml *aml_resource_template(void) { /* ResourceTemplate is a buffer of Resources with EndTag at the end */ Aml *var = aml_bundle(0x11 /* BufferOp */, AML_RES_TEMPLATE); return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer * Pass byte_list as NULL to request uninitialized buffer to reserve space. */ Aml *aml_buffer(int buffer_size, uint8_t *byte_list) { int i; Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER); for (i = 0; i < buffer_size; i++) { if (byte_list == NULL) { build_append_byte(var->buf, 0x0); } else { build_append_byte(var->buf, byte_list[i]); } } return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefPackage */ Aml *aml_package(uint8_t num_elements) { Aml *var = aml_bundle(0x12 /* PackageOp */, AML_PACKAGE); build_append_byte(var->buf, num_elements); return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefOpRegion */ Aml *aml_operation_region(const char *name, AmlRegionSpace rs, Aml *offset, uint32_t len) { Aml *var = aml_alloc(); build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ build_append_byte(var->buf, 0x80); /* OpRegionOp */ build_append_namestring(var->buf, "%s", name); build_append_byte(var->buf, rs); aml_append(var, offset); build_append_int(var->buf, len); return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: NamedField */ Aml *aml_named_field(const char *name, unsigned length) { Aml *var = aml_alloc(); build_append_nameseg(var->buf, name); build_append_pkg_length(var->buf, length, false); return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: ReservedField */ Aml *aml_reserved_field(unsigned length) { Aml *var = aml_alloc(); /* ReservedField := 0x00 PkgLength */ build_append_byte(var->buf, 0x00); build_append_pkg_length(var->buf, length, false); return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefField */ Aml *aml_field(const char *name, AmlAccessType type, AmlLockRule lock, AmlUpdateRule rule) { Aml *var = aml_bundle(0x81 /* FieldOp */, AML_EXT_PACKAGE); uint8_t flags = rule << 5 | type; flags |= lock << 4; /* LockRule at 4 bit offset */ build_append_namestring(var->buf, "%s", name); build_append_byte(var->buf, flags); return var; } static Aml *create_field_common(int opcode, Aml *srcbuf, Aml *index, const char *name) { Aml *var = aml_opcode(opcode); aml_append(var, srcbuf); aml_append(var, index); build_append_namestring(var->buf, "%s", name); return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateField */ Aml *aml_create_field(Aml *srcbuf, Aml *bit_index, Aml *num_bits, const char *name) { Aml *var = aml_alloc(); build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ build_append_byte(var->buf, 0x13); /* CreateFieldOp */ aml_append(var, srcbuf); aml_append(var, bit_index); aml_append(var, num_bits); build_append_namestring(var->buf, "%s", name); return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateDWordField */ Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name) { return create_field_common(0x8A /* CreateDWordFieldOp */, srcbuf, index, name); } /* ACPI 2.0a: 17.2.4.2 Named Objects Encoding: DefCreateQWordField */ Aml *aml_create_qword_field(Aml *srcbuf, Aml *index, const char *name) { return create_field_common(0x8F /* CreateQWordFieldOp */, srcbuf, index, name); } /* ACPI 1.0b: 16.2.3 Data Objects Encoding: String */ Aml *aml_string(const char *name_format, ...) { Aml *var = aml_opcode(0x0D /* StringPrefix */); va_list ap; char *s; int len; va_start(ap, name_format); len = g_vasprintf(&s, name_format, ap); va_end(ap); g_array_append_vals(var->buf, s, len + 1); g_free(s); return var; } /* ACPI 1.0b: 16.2.6.2 Local Objects Encoding */ Aml *aml_local(int num) { uint8_t op = 0x60 /* Local0Op */ + num; assert(num <= 7); return aml_opcode(op); } /* ACPI 2.0a: 17.2.2 Data Objects Encoding: DefVarPackage */ Aml *aml_varpackage(uint32_t num_elements) { Aml *var = aml_bundle(0x13 /* VarPackageOp */, AML_PACKAGE); build_append_int(var->buf, num_elements); return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefProcessor */ Aml *aml_processor(uint8_t proc_id, uint32_t pblk_addr, uint8_t pblk_len, const char *name_format, ...) { va_list ap; Aml *var = aml_bundle(0x83 /* ProcessorOp */, AML_EXT_PACKAGE); va_start(ap, name_format); build_append_namestringv(var->buf, name_format, ap); va_end(ap); build_append_byte(var->buf, proc_id); /* ProcID */ build_append_int_noprefix(var->buf, pblk_addr, sizeof(pblk_addr)); build_append_byte(var->buf, pblk_len); /* PblkLen */ return var; } static uint8_t Hex2Digit(char c) { if (c >= 'A') { return c - 'A' + 10; } return c - '0'; } /* ACPI 1.0b: 15.2.3.6.4.1 EISAID Macro - Convert EISA ID String To Integer */ Aml *aml_eisaid(const char *str) { Aml *var = aml_alloc(); uint32_t id; g_assert(strlen(str) == 7); id = (str[0] - 0x40) << 26 | (str[1] - 0x40) << 21 | (str[2] - 0x40) << 16 | Hex2Digit(str[3]) << 12 | Hex2Digit(str[4]) << 8 | Hex2Digit(str[5]) << 4 | Hex2Digit(str[6]); build_append_byte(var->buf, 0x0C); /* DWordPrefix */ build_append_int_noprefix(var->buf, bswap32(id), sizeof(id)); return var; } /* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor: bytes 3-5 */ static Aml *aml_as_desc_header(AmlResourceType type, AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlDecode dec, uint8_t type_flags) { uint8_t flags = max_fixed | min_fixed | dec; Aml *var = aml_alloc(); build_append_byte(var->buf, type); build_append_byte(var->buf, flags); build_append_byte(var->buf, type_flags); /* Type Specific Flags */ return var; } /* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor */ static Aml *aml_word_as_desc(AmlResourceType type, AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlDecode dec, uint16_t addr_gran, uint16_t addr_min, uint16_t addr_max, uint16_t addr_trans, uint16_t len, uint8_t type_flags) { Aml *var = aml_alloc(); build_append_byte(var->buf, 0x88); /* Word Address Space Descriptor */ /* minimum length since we do not encode optional fields */ build_append_byte(var->buf, 0x0D); build_append_byte(var->buf, 0x0); aml_append(var, aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags)); build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran)); build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min)); build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max)); build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans)); build_append_int_noprefix(var->buf, len, sizeof(len)); return var; } /* ACPI 1.0b: 6.4.3.5.3 DWord Address Space Descriptor */ static Aml *aml_dword_as_desc(AmlResourceType type, AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlDecode dec, uint32_t addr_gran, uint32_t addr_min, uint32_t addr_max, uint32_t addr_trans, uint32_t len, uint8_t type_flags) { Aml *var = aml_alloc(); build_append_byte(var->buf, 0x87); /* DWord Address Space Descriptor */ /* minimum length since we do not encode optional fields */ build_append_byte(var->buf, 23); build_append_byte(var->buf, 0x0); aml_append(var, aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags)); build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran)); build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min)); build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max)); build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans)); build_append_int_noprefix(var->buf, len, sizeof(len)); return var; } /* ACPI 1.0b: 6.4.3.5.1 QWord Address Space Descriptor */ static Aml *aml_qword_as_desc(AmlResourceType type, AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlDecode dec, uint64_t addr_gran, uint64_t addr_min, uint64_t addr_max, uint64_t addr_trans, uint64_t len, uint8_t type_flags) { Aml *var = aml_alloc(); build_append_byte(var->buf, 0x8A); /* QWord Address Space Descriptor */ /* minimum length since we do not encode optional fields */ build_append_byte(var->buf, 0x2B); build_append_byte(var->buf, 0x0); aml_append(var, aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags)); build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran)); build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min)); build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max)); build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans)); build_append_int_noprefix(var->buf, len, sizeof(len)); return var; } /* * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor * * More verbose description at: * ACPI 5.0: 19.5.141 WordBusNumber (Word Bus Number Resource Descriptor Macro) */ Aml *aml_word_bus_number(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlDecode dec, uint16_t addr_gran, uint16_t addr_min, uint16_t addr_max, uint16_t addr_trans, uint16_t len) { return aml_word_as_desc(AML_BUS_NUMBER_RANGE, min_fixed, max_fixed, dec, addr_gran, addr_min, addr_max, addr_trans, len, 0); } /* * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor * * More verbose description at: * ACPI 5.0: 19.5.142 WordIO (Word IO Resource Descriptor Macro) */ Aml *aml_word_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlDecode dec, AmlISARanges isa_ranges, uint16_t addr_gran, uint16_t addr_min, uint16_t addr_max, uint16_t addr_trans, uint16_t len) { return aml_word_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec, addr_gran, addr_min, addr_max, addr_trans, len, isa_ranges); } /* * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Descriptor * * More verbose description at: * ACPI 5.0: 19.5.33 DWordIO (DWord IO Resource Descriptor Macro) */ Aml *aml_dword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlDecode dec, AmlISARanges isa_ranges, uint32_t addr_gran, uint32_t addr_min, uint32_t addr_max, uint32_t addr_trans, uint32_t len) { return aml_dword_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec, addr_gran, addr_min, addr_max, addr_trans, len, isa_ranges); } /* * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Space Descriptor * * More verbose description at: * ACPI 5.0: 19.5.34 DWordMemory (DWord Memory Resource Descriptor Macro) */ Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlCacheable cacheable, AmlReadAndWrite read_and_write, uint32_t addr_gran, uint32_t addr_min, uint32_t addr_max, uint32_t addr_trans, uint32_t len) { uint8_t flags = read_and_write | (cacheable << 1); return aml_dword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed, dec, addr_gran, addr_min, addr_max, addr_trans, len, flags); } /* * ACPI 1.0b: 6.4.3.5.2 ASL Macros for QWORD Address Space Descriptor * * More verbose description at: * ACPI 5.0: 19.5.102 QWordMemory (QWord Memory Resource Descriptor Macro) */ Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlCacheable cacheable, AmlReadAndWrite read_and_write, uint64_t addr_gran, uint64_t addr_min, uint64_t addr_max, uint64_t addr_trans, uint64_t len) { uint8_t flags = read_and_write | (cacheable << 1); return aml_qword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed, dec, addr_gran, addr_min, addr_max, addr_trans, len, flags); } /* ACPI 1.0b: 6.4.2.2 DMA Format/6.4.2.2.1 ASL Macro for DMA Descriptor */ Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz, uint8_t channel) { Aml *var = aml_alloc(); uint8_t flags = sz | bm << 2 | typ << 5; assert(channel < 8); build_append_byte(var->buf, 0x2A); /* Byte 0: DMA Descriptor */ build_append_byte(var->buf, 1U << channel); /* Byte 1: _DMA - DmaChannel */ build_append_byte(var->buf, flags); /* Byte 2 */ return var; } /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefSleep */ Aml *aml_sleep(uint64_t msec) { Aml *var = aml_alloc(); build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ build_append_byte(var->buf, 0x22); /* SleepOp */ aml_append(var, aml_int(msec)); return var; } static uint8_t Hex2Byte(const char *src) { int hi, lo; hi = Hex2Digit(src[0]); assert(hi >= 0); assert(hi <= 15); lo = Hex2Digit(src[1]); assert(lo >= 0); assert(lo <= 15); return (hi << 4) | lo; } /* * ACPI 3.0: 17.5.124 ToUUID (Convert String to UUID Macro) * e.g. UUID: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp * call aml_touuid("aabbccdd-eeff-gghh-iijj-kkllmmnnoopp"); */ Aml *aml_touuid(const char *uuid) { Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER); assert(strlen(uuid) == 36); assert(uuid[8] == '-'); assert(uuid[13] == '-'); assert(uuid[18] == '-'); assert(uuid[23] == '-'); build_append_byte(var->buf, Hex2Byte(uuid + 6)); /* dd - at offset 00 */ build_append_byte(var->buf, Hex2Byte(uuid + 4)); /* cc - at offset 01 */ build_append_byte(var->buf, Hex2Byte(uuid + 2)); /* bb - at offset 02 */ build_append_byte(var->buf, Hex2Byte(uuid + 0)); /* aa - at offset 03 */ build_append_byte(var->buf, Hex2Byte(uuid + 11)); /* ff - at offset 04 */ build_append_byte(var->buf, Hex2Byte(uuid + 9)); /* ee - at offset 05 */ build_append_byte(var->buf, Hex2Byte(uuid + 16)); /* hh - at offset 06 */ build_append_byte(var->buf, Hex2Byte(uuid + 14)); /* gg - at offset 07 */ build_append_byte(var->buf, Hex2Byte(uuid + 19)); /* ii - at offset 08 */ build_append_byte(var->buf, Hex2Byte(uuid + 21)); /* jj - at offset 09 */ build_append_byte(var->buf, Hex2Byte(uuid + 24)); /* kk - at offset 10 */ build_append_byte(var->buf, Hex2Byte(uuid + 26)); /* ll - at offset 11 */ build_append_byte(var->buf, Hex2Byte(uuid + 28)); /* mm - at offset 12 */ build_append_byte(var->buf, Hex2Byte(uuid + 30)); /* nn - at offset 13 */ build_append_byte(var->buf, Hex2Byte(uuid + 32)); /* oo - at offset 14 */ build_append_byte(var->buf, Hex2Byte(uuid + 34)); /* pp - at offset 15 */ return var; } /* * ACPI 2.0b: 16.2.3.6.4.3 Unicode Macro (Convert Ascii String To Unicode) */ Aml *aml_unicode(const char *str) { int i = 0; Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER); do { build_append_byte(var->buf, str[i]); build_append_byte(var->buf, 0); i++; } while (i <= strlen(str)); return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefRefOf */ Aml *aml_refof(Aml *arg) { Aml *var = aml_opcode(0x71 /* RefOfOp */); aml_append(var, arg); return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDerefOf */ Aml *aml_derefof(Aml *arg) { Aml *var = aml_opcode(0x83 /* DerefOfOp */); aml_append(var, arg); return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefSizeOf */ Aml *aml_sizeof(Aml *arg) { Aml *var = aml_opcode(0x87 /* SizeOfOp */); aml_append(var, arg); return var; } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMutex */ Aml *aml_mutex(const char *name, uint8_t sync_level) { Aml *var = aml_alloc(); build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ build_append_byte(var->buf, 0x01); /* MutexOp */ build_append_namestring(var->buf, "%s", name); assert(!(sync_level & 0xF0)); build_append_byte(var->buf, sync_level); return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAcquire */ Aml *aml_acquire(Aml *mutex, uint16_t timeout) { Aml *var = aml_alloc(); build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ build_append_byte(var->buf, 0x23); /* AcquireOp */ aml_append(var, mutex); build_append_int_noprefix(var->buf, timeout, sizeof(timeout)); return var; } /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefRelease */ Aml *aml_release(Aml *mutex) { Aml *var = aml_alloc(); build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ build_append_byte(var->buf, 0x27); /* ReleaseOp */ aml_append(var, mutex); return var; } /* ACPI 1.0b: 16.2.5.1 Name Space Modifier Objects Encoding: DefAlias */ Aml *aml_alias(const char *source_object, const char *alias_object) { Aml *var = aml_opcode(0x06 /* AliasOp */); aml_append(var, aml_name("%s", source_object)); aml_append(var, aml_name("%s", alias_object)); return var; } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefConcat */ Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target) { return build_opcode_2arg_dst(0x73 /* ConcatOp */, source1, source2, target); } /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefObjectType */ Aml *aml_object_type(Aml *object) { Aml *var = aml_opcode(0x8E /* ObjectTypeOp */); aml_append(var, object); return var; } void build_header(BIOSLinker *linker, GArray *table_data, AcpiTableHeader *h, const char *sig, int len, uint8_t rev, const char *oem_id, const char *oem_table_id) { unsigned tbl_offset = (char *)h - table_data->data; unsigned checksum_offset = (char *)&h->checksum - table_data->data; memcpy(&h->signature, sig, 4); h->length = cpu_to_le32(len); h->revision = rev; if (oem_id) { strncpy((char *)h->oem_id, oem_id, sizeof h->oem_id); } else { memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); } if (oem_table_id) { strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id)); } else { memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4); memcpy(h->oem_table_id + 4, sig, 4); } h->oem_revision = cpu_to_le32(1); memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4); h->asl_compiler_revision = cpu_to_le32(1); /* Checksum to be filled in by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE, tbl_offset, len, checksum_offset); } void *acpi_data_push(GArray *table_data, unsigned size) { unsigned off = table_data->len; g_array_set_size(table_data, off + size); return table_data->data + off; } unsigned acpi_data_len(GArray *table) { assert(g_array_get_element_size(table) == 1); return table->len; } void acpi_add_table(GArray *table_offsets, GArray *table_data) { uint32_t offset = table_data->len; g_array_append_val(table_offsets, offset); } void acpi_build_tables_init(AcpiBuildTables *tables) { tables->rsdp = g_array_new(false, true /* clear */, 1); tables->table_data = g_array_new(false, true /* clear */, 1); tables->tcpalog = g_array_new(false, true /* clear */, 1); tables->vmgenid = g_array_new(false, true /* clear */, 1); tables->hardware_errors = g_array_new(false, true /* clear */, 1); tables->linker = bios_linker_loader_init(); } void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre) { bios_linker_loader_cleanup(tables->linker); g_array_free(tables->rsdp, true); g_array_free(tables->table_data, true); g_array_free(tables->tcpalog, mfre); g_array_free(tables->vmgenid, mfre); g_array_free(tables->hardware_errors, mfre); } /* * ACPI spec 5.2.5.3 Root System Description Pointer (RSDP). * (Revision 1.0 or later) */ void build_rsdp(GArray *tbl, BIOSLinker *linker, AcpiRsdpData *rsdp_data) { int tbl_off = tbl->len; /* Table offset in the RSDP file */ switch (rsdp_data->revision) { case 0: /* With ACPI 1.0, we must have an RSDT pointer */ g_assert(rsdp_data->rsdt_tbl_offset); break; case 2: /* With ACPI 2.0+, we must have an XSDT pointer */ g_assert(rsdp_data->xsdt_tbl_offset); break; default: /* Only revisions 0 (ACPI 1.0) and 2 (ACPI 2.0+) are valid for RSDP */ g_assert_not_reached(); } bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, tbl, 16, true /* fseg memory */); g_array_append_vals(tbl, "RSD PTR ", 8); /* Signature */ build_append_int_noprefix(tbl, 0, 1); /* Checksum */ g_array_append_vals(tbl, rsdp_data->oem_id, 6); /* OEMID */ build_append_int_noprefix(tbl, rsdp_data->revision, 1); /* Revision */ build_append_int_noprefix(tbl, 0, 4); /* RsdtAddress */ if (rsdp_data->rsdt_tbl_offset) { /* RSDT address to be filled by guest linker */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE, tbl_off + 16, 4, ACPI_BUILD_TABLE_FILE, *rsdp_data->rsdt_tbl_offset); } /* Checksum to be filled by guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, tbl_off, 20, /* ACPI rev 1.0 RSDP size */ 8); if (rsdp_data->revision == 0) { /* ACPI 1.0 RSDP, we're done */ return; } build_append_int_noprefix(tbl, 36, 4); /* Length */ /* XSDT address to be filled by guest linker */ build_append_int_noprefix(tbl, 0, 8); /* XsdtAddress */ /* We already validated our xsdt pointer */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE, tbl_off + 24, 8, ACPI_BUILD_TABLE_FILE, *rsdp_data->xsdt_tbl_offset); build_append_int_noprefix(tbl, 0, 1); /* Extended Checksum */ build_append_int_noprefix(tbl, 0, 3); /* Reserved */ /* Extended checksum to be filled by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, tbl_off, 36, /* ACPI rev 2.0 RSDP size */ 32); } /* Build rsdt table */ void build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, const char *oem_id, const char *oem_table_id) { int i; unsigned rsdt_entries_offset; AcpiRsdtDescriptorRev1 *rsdt; const unsigned table_data_len = (sizeof(uint32_t) * table_offsets->len); const unsigned rsdt_entry_size = sizeof(rsdt->table_offset_entry[0]); const size_t rsdt_len = sizeof(*rsdt) + table_data_len; rsdt = acpi_data_push(table_data, rsdt_len); rsdt_entries_offset = (char *)rsdt->table_offset_entry - table_data->data; for (i = 0; i < table_offsets->len; ++i) { uint32_t ref_tbl_offset = g_array_index(table_offsets, uint32_t, i); uint32_t rsdt_entry_offset = rsdt_entries_offset + rsdt_entry_size * i; /* rsdt->table_offset_entry to be filled by Guest linker */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, rsdt_entry_offset, rsdt_entry_size, ACPI_BUILD_TABLE_FILE, ref_tbl_offset); } build_header(linker, table_data, (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id); } /* Build xsdt table */ void build_xsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, const char *oem_id, const char *oem_table_id) { int i; unsigned xsdt_entries_offset; AcpiXsdtDescriptorRev2 *xsdt; const unsigned table_data_len = (sizeof(uint64_t) * table_offsets->len); const unsigned xsdt_entry_size = sizeof(xsdt->table_offset_entry[0]); const size_t xsdt_len = sizeof(*xsdt) + table_data_len; xsdt = acpi_data_push(table_data, xsdt_len); xsdt_entries_offset = (char *)xsdt->table_offset_entry - table_data->data; for (i = 0; i < table_offsets->len; ++i) { uint64_t ref_tbl_offset = g_array_index(table_offsets, uint32_t, i); uint64_t xsdt_entry_offset = xsdt_entries_offset + xsdt_entry_size * i; /* xsdt->table_offset_entry to be filled by Guest linker */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, xsdt_entry_offset, xsdt_entry_size, ACPI_BUILD_TABLE_FILE, ref_tbl_offset); } build_header(linker, table_data, (void *)xsdt, "XSDT", xsdt_len, 1, oem_id, oem_table_id); } void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, uint64_t len, int node, MemoryAffinityFlags flags) { numamem->type = ACPI_SRAT_MEMORY; numamem->length = sizeof(*numamem); numamem->proximity = cpu_to_le32(node); numamem->flags = cpu_to_le32(flags); numamem->base_addr = cpu_to_le64(base); numamem->range_length = cpu_to_le64(len); } /* * ACPI spec 5.2.17 System Locality Distance Information Table * (Revision 2.0 or later) */ void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms) { int slit_start, i, j; slit_start = table_data->len; int nb_numa_nodes = ms->numa_state->num_nodes; acpi_data_push(table_data, sizeof(AcpiTableHeader)); build_append_int_noprefix(table_data, nb_numa_nodes, 8); for (i = 0; i < nb_numa_nodes; i++) { for (j = 0; j < nb_numa_nodes; j++) { assert(ms->numa_state->nodes[i].distance[j]); build_append_int_noprefix(table_data, ms->numa_state->nodes[i].distance[j], 1); } } build_header(linker, table_data, (void *)(table_data->data + slit_start), "SLIT", table_data->len - slit_start, 1, NULL, NULL); } /* build rev1/rev3/rev5.1 FADT */ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, const char *oem_id, const char *oem_table_id) { int off; int fadt_start = tbl->len; acpi_data_push(tbl, sizeof(AcpiTableHeader)); /* FACS address to be filled by Guest linker at runtime */ off = tbl->len; build_append_int_noprefix(tbl, 0, 4); /* FIRMWARE_CTRL */ if (f->facs_tbl_offset) { /* don't patch if not supported by platform */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, off, 4, ACPI_BUILD_TABLE_FILE, *f->facs_tbl_offset); } /* DSDT address to be filled by Guest linker at runtime */ off = tbl->len; build_append_int_noprefix(tbl, 0, 4); /* DSDT */ if (f->dsdt_tbl_offset) { /* don't patch if not supported by platform */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, off, 4, ACPI_BUILD_TABLE_FILE, *f->dsdt_tbl_offset); } /* ACPI1.0: INT_MODEL, ACPI2.0+: Reserved */ build_append_int_noprefix(tbl, f->int_model /* Multiple APIC */, 1); /* Preferred_PM_Profile */ build_append_int_noprefix(tbl, 0 /* Unspecified */, 1); build_append_int_noprefix(tbl, f->sci_int, 2); /* SCI_INT */ build_append_int_noprefix(tbl, f->smi_cmd, 4); /* SMI_CMD */ build_append_int_noprefix(tbl, f->acpi_enable_cmd, 1); /* ACPI_ENABLE */ build_append_int_noprefix(tbl, f->acpi_disable_cmd, 1); /* ACPI_DISABLE */ build_append_int_noprefix(tbl, 0 /* not supported */, 1); /* S4BIOS_REQ */ /* ACPI1.0: Reserved, ACPI2.0+: PSTATE_CNT */ build_append_int_noprefix(tbl, 0, 1); build_append_int_noprefix(tbl, f->pm1a_evt.address, 4); /* PM1a_EVT_BLK */ build_append_int_noprefix(tbl, 0, 4); /* PM1b_EVT_BLK */ build_append_int_noprefix(tbl, f->pm1a_cnt.address, 4); /* PM1a_CNT_BLK */ build_append_int_noprefix(tbl, 0, 4); /* PM1b_CNT_BLK */ build_append_int_noprefix(tbl, 0, 4); /* PM2_CNT_BLK */ build_append_int_noprefix(tbl, f->pm_tmr.address, 4); /* PM_TMR_BLK */ build_append_int_noprefix(tbl, f->gpe0_blk.address, 4); /* GPE0_BLK */ build_append_int_noprefix(tbl, 0, 4); /* GPE1_BLK */ /* PM1_EVT_LEN */ build_append_int_noprefix(tbl, f->pm1a_evt.bit_width / 8, 1); /* PM1_CNT_LEN */ build_append_int_noprefix(tbl, f->pm1a_cnt.bit_width / 8, 1); build_append_int_noprefix(tbl, 0, 1); /* PM2_CNT_LEN */ build_append_int_noprefix(tbl, f->pm_tmr.bit_width / 8, 1); /* PM_TMR_LEN */ /* GPE0_BLK_LEN */ build_append_int_noprefix(tbl, f->gpe0_blk.bit_width / 8, 1); build_append_int_noprefix(tbl, 0, 1); /* GPE1_BLK_LEN */ build_append_int_noprefix(tbl, 0, 1); /* GPE1_BASE */ build_append_int_noprefix(tbl, 0, 1); /* CST_CNT */ build_append_int_noprefix(tbl, f->plvl2_lat, 2); /* P_LVL2_LAT */ build_append_int_noprefix(tbl, f->plvl3_lat, 2); /* P_LVL3_LAT */ build_append_int_noprefix(tbl, 0, 2); /* FLUSH_SIZE */ build_append_int_noprefix(tbl, 0, 2); /* FLUSH_STRIDE */ build_append_int_noprefix(tbl, 0, 1); /* DUTY_OFFSET */ build_append_int_noprefix(tbl, 0, 1); /* DUTY_WIDTH */ build_append_int_noprefix(tbl, 0, 1); /* DAY_ALRM */ build_append_int_noprefix(tbl, 0, 1); /* MON_ALRM */ build_append_int_noprefix(tbl, f->rtc_century, 1); /* CENTURY */ build_append_int_noprefix(tbl, 0, 2); /* IAPC_BOOT_ARCH */ build_append_int_noprefix(tbl, 0, 1); /* Reserved */ build_append_int_noprefix(tbl, f->flags, 4); /* Flags */ if (f->rev == 1) { goto build_hdr; } build_append_gas_from_struct(tbl, &f->reset_reg); /* RESET_REG */ build_append_int_noprefix(tbl, f->reset_val, 1); /* RESET_VALUE */ /* Since ACPI 5.1 */ if ((f->rev >= 6) || ((f->rev == 5) && f->minor_ver > 0)) { build_append_int_noprefix(tbl, f->arm_boot_arch, 2); /* ARM_BOOT_ARCH */ /* FADT Minor Version */ build_append_int_noprefix(tbl, f->minor_ver, 1); } else { build_append_int_noprefix(tbl, 0, 3); /* Reserved upto ACPI 5.0 */ } build_append_int_noprefix(tbl, 0, 8); /* X_FIRMWARE_CTRL */ /* XDSDT address to be filled by Guest linker at runtime */ off = tbl->len; build_append_int_noprefix(tbl, 0, 8); /* X_DSDT */ if (f->xdsdt_tbl_offset) { bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, off, 8, ACPI_BUILD_TABLE_FILE, *f->xdsdt_tbl_offset); } build_append_gas_from_struct(tbl, &f->pm1a_evt); /* X_PM1a_EVT_BLK */ /* X_PM1b_EVT_BLK */ build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0); build_append_gas_from_struct(tbl, &f->pm1a_cnt); /* X_PM1a_CNT_BLK */ /* X_PM1b_CNT_BLK */ build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0); /* X_PM2_CNT_BLK */ build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0); build_append_gas_from_struct(tbl, &f->pm_tmr); /* X_PM_TMR_BLK */ build_append_gas_from_struct(tbl, &f->gpe0_blk); /* X_GPE0_BLK */ build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0); /* X_GPE1_BLK */ if (f->rev <= 4) { goto build_hdr; } /* SLEEP_CONTROL_REG */ build_append_gas_from_struct(tbl, &f->sleep_ctl); /* SLEEP_STATUS_REG */ build_append_gas_from_struct(tbl, &f->sleep_sts); /* TODO: extra fields need to be added to support revisions above rev5 */ assert(f->rev == 5); build_hdr: build_header(linker, tbl, (void *)(tbl->data + fadt_start), "FACP", tbl->len - fadt_start, f->rev, oem_id, oem_table_id); } /* * build_tpm2 - Build the TPM2 table as specified in * table 7: TCG Hardware Interface Description Table Format for TPM 2.0 * of TCG ACPI Specification, Family “1.2” and “2.0”, Version 1.2, Rev 8 */ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) { uint8_t start_method_params[12] = {}; unsigned log_addr_offset, tpm2_start; uint64_t control_area_start_address; TPMIf *tpmif = tpm_find(); uint32_t start_method; void *tpm2_ptr; tpm2_start = table_data->len; tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader)); /* Platform Class */ build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2); /* Reserved */ build_append_int_noprefix(table_data, 0, 2); if (TPM_IS_TIS_ISA(tpmif) || TPM_IS_TIS_SYSBUS(tpmif)) { control_area_start_address = 0; start_method = TPM2_START_METHOD_MMIO; } else if (TPM_IS_CRB(tpmif)) { control_area_start_address = TPM_CRB_ADDR_CTRL; start_method = TPM2_START_METHOD_CRB; } else { g_assert_not_reached(); } /* Address of Control Area */ build_append_int_noprefix(table_data, control_area_start_address, 8); /* Start Method */ build_append_int_noprefix(table_data, start_method, 4); /* Platform Specific Parameters */ g_array_append_vals(table_data, &start_method_params, ARRAY_SIZE(start_method_params)); /* Log Area Minimum Length */ build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4); acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE); bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1, false); log_addr_offset = table_data->len; /* Log Area Start Address to be filled by Guest linker */ build_append_int_noprefix(table_data, 0, 8); bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, log_addr_offset, 8, ACPI_BUILD_TPMLOG_FILE, 0); build_header(linker, table_data, tpm2_ptr, "TPM2", table_data->len - tpm2_start, 4, NULL, NULL); } /* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */ static Aml *aml_serial_bus_device(uint8_t serial_bus_type, uint8_t flags, uint16_t type_flags, uint8_t revid, uint16_t data_length, uint16_t resource_source_len) { Aml *var = aml_alloc(); uint16_t length = data_length + resource_source_len + 9; build_append_byte(var->buf, 0x8e); /* Serial Bus Connection Descriptor */ build_append_int_noprefix(var->buf, length, sizeof(length)); build_append_byte(var->buf, 1); /* Revision ID */ build_append_byte(var->buf, 0); /* Resource Source Index */ build_append_byte(var->buf, serial_bus_type); /* Serial Bus Type */ build_append_byte(var->buf, flags); /* General Flags */ build_append_int_noprefix(var->buf, type_flags, /* Type Specific Flags */ sizeof(type_flags)); build_append_byte(var->buf, revid); /* Type Specification Revision ID */ build_append_int_noprefix(var->buf, data_length, sizeof(data_length)); return var; } /* ACPI 5.0: 6.4.3.8.2.1 I2C Serial Bus Connection Resource Descriptor */ Aml *aml_i2c_serial_bus_device(uint16_t address, const char *resource_source) { uint16_t resource_source_len = strlen(resource_source) + 1; Aml *var = aml_serial_bus_device(AML_SERIAL_BUS_TYPE_I2C, 0, 0, 1, 6, resource_source_len); /* Connection Speed. Just set to 100K for now, it doesn't really matter. */ build_append_int_noprefix(var->buf, 100000, 4); build_append_int_noprefix(var->buf, address, sizeof(address)); /* This is a string, not a name, so just copy it directly in. */ g_array_append_vals(var->buf, resource_source, resource_source_len); return var; }