<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_get_poundv_bucket_attr.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_pm_get_poundv_bucket_attr.C
/// @brief Grab PM data from certain bucket in #V keyword in LRPX record
///

// ----------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------
#include <p9_pm_get_poundv_bucket_attr.H>
#include <p9_pm_get_poundv_bucket.H>
#include <mvpd_access_defs.H>
#include <attribute_ids.H>

fapi2::ReturnCode p9_pm_get_poundv_bucket_attr(
    const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
    uint8_t* o_data)
{
    FAPI_DBG("Entering p9_pm_get_poundv_bucket_attr ....");
    uint8_t* l_prDataPtr = NULL;
    uint8_t* l_fullVpdData = NULL;
    uint8_t l_overridePresent = 0;
    uint32_t l_tempVpdSize = 0;
    uint32_t l_vpdSize = 0;
    uint8_t l_eqChipUnitPos = 0;
    uint8_t l_bucketId;
    uint8_t l_bucketSize = 0;
    uint32_t l_sysNestFreq = 0;
    fapi2::voltageBucketData_t* l_currentBucket = NULL;
    uint8_t l_numMatches = 0;
    uint16_t l_pbFreq = 0;

    fapi2::MvpdRecord lrpRecord = fapi2::MVPD_RECORD_LAST;
    //To read MVPD we will need the proc parent of the inputted EQ target
    fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> l_procParent =
        i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();

    //Need to determine which LRP record to read from depending on which
    //bucket we are getting the power management data from. FapiPos will
    //tell us which LRP record to use.
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                           i_target,
                           l_eqChipUnitPos));

    FAPI_ASSERT( l_eqChipUnitPos < NUM_BUCKETS ,
                 fapi2::INVALID_EQ_CHIP_POS().
                 set_EQ_POSITION( l_eqChipUnitPos ),
                 "Invalid EQ chip unit position = 0x%X",
                 l_eqChipUnitPos);

    //The enumeration for the LRPx records are just 3 more
    //than the EQ chip unit pos. See mvpd_access_defs.H
    lrpRecord = static_cast<fapi2::MvpdRecord>(l_eqChipUnitPos +
                fapi2::MVPD_RECORD_LRP0 );

    //check if bucket num has been overriden
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POUNDV_BUCKET_NUM_OVERRIDE,
                           i_target,
                           l_overridePresent));

    if(l_overridePresent != 0)
    {
        //If it has been overriden then get the override
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POUNDV_BUCKET_NUM,
                               i_target,
                               l_bucketId));
    }
    else
    {
        //First read is to get size of vpd record, note the o_buffer is NULL
        FAPI_TRY( getMvpdField(lrpRecord,
                               fapi2::MVPD_KEYWORD_PDV,
                               l_procParent,
                               NULL,
                               l_tempVpdSize) );

        //save off the actual vpd size
        l_vpdSize = l_tempVpdSize;
        //Allocate memory for vpd data
        l_fullVpdData = reinterpret_cast<uint8_t*>(malloc(l_tempVpdSize));

        //Second read is to get data of vpd record
        FAPI_TRY( getMvpdField(lrpRecord,
                               fapi2::MVPD_KEYWORD_PDV,
                               l_procParent,
                               l_fullVpdData,
                               l_tempVpdSize) );

        //Version 2:
        //#V record is laid out as follows:
        //Name:     0x2 byte
        //Length:   0x2 byte
        //Version:  0x1 byte **buffer starts here
        //PNP:      0x3 byte
        //bucket a: 0x33 byte
        //bucket b: 0x33 byte
        //bucket c: 0x33 byte
        //bucket d: 0x33 byte
        //bucket e: 0x33 byte
        //bucket f: 0x33 byte
        if( *l_fullVpdData == POUNDV_VERSION_2)
        {
            //Set the size of the bucket
            l_bucketSize = VERSION_2_BUCKET_SIZE;

            //Reset VPD size because we want to find size of another VPD record
            l_tempVpdSize = 0;

            //First read is to get size of vpd record, note the o_buffer is NULL
            FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_VINI,
                                   fapi2::MVPD_KEYWORD_PR,
                                   l_procParent,
                                   NULL,
                                   l_tempVpdSize) );

            l_prDataPtr = reinterpret_cast<uint8_t*>(malloc(l_tempVpdSize));

            //Second read is to get data of vpd record
            FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_VINI,
                                   fapi2::MVPD_KEYWORD_PR,
                                   l_procParent,
                                   l_prDataPtr,
                                   l_tempVpdSize) );

            //Bucket ID is byte[4] of the PR keyword
            memcpy(&l_bucketId, (l_prDataPtr + 4), sizeof(uint8_t));

        }
        //Version 3:
        //#V record is laid out as follows:
        //Name:     0x2 byte
        //Length:   0x2 byte
        //Version:  0x1 byte **buffer starts here
        //PNP:      0x3 byte
        //bucket a: 0x3D byte
        //bucket b: 0x3D byte
        //bucket c: 0x3D byte
        //bucket d: 0x3D byte
        //bucket e: 0x3D byte
        //bucket f: 0x3D byte
        else if( *l_fullVpdData == POUNDV_VERSION_3 )
        {
            // Set the size of the bucket
            l_bucketSize = VERSION_3_BUCKET_SIZE;

            //Save off some FFDC data about the #V data itself
            uint16_t l_bucketNestFreqs[NUM_BUCKETS] = { 0, 0, 0, 0, 0, 0 };

            // Version 3 uses the nest frequency to choose the bucket Id
            // get the system target to find the NEST_FREQ_MHZ
            fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> l_sysParent;

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_PB_MHZ,
                                   l_sysParent,
                                   l_sysNestFreq));
            //cast the voltage data into an array of buckets
            fapi2::voltageBucketData_t* l_buckets = reinterpret_cast
                                                    <fapi2::voltageBucketData_t*>
                                                    (l_fullVpdData + POUNDV_BUCKET_OFFSET);

            for(int i = 0; i < NUM_BUCKETS; i++)
            {
#ifndef _BIG_ENDIAN
                l_pbFreq = ( (((l_buckets[i].pbFreq) >> 8) & 0x00FF) | (((l_buckets[i].pbFreq) << 8) & 0xFF00) );
#else
                l_pbFreq = l_buckets[i].pbFreq;
#endif

                if(l_pbFreq == l_sysNestFreq)
                {
                    l_numMatches++;

                    if(l_numMatches > 1)
                    {
                        FAPI_ERR("p9_pm_get_poundv_bucket_attr::"
                                 " Multiple buckets (%d) reporting the same nest frequency"
                                 " Bucket Nest = %d Bucket ID = %d, First Bucket = %d",
                                 l_numMatches,
                                 l_pbFreq,
                                 (i + 1),
                                 l_currentBucket);

                    }
                    else
                    {
                        l_currentBucket = &l_buckets[i];
                    }
                }

                //save FFDC in case we fail
                l_bucketNestFreqs[i] = l_pbFreq;
            }

            if(l_numMatches == 1)
            {
                l_bucketId = l_currentBucket->bucketId;
            }
            else
            {

                FAPI_ERR("p9_pm_get_poundv_bucket_attr::Invalid number of matching nest freqs found for PBFreq=%d. Matches found = %d",
                         l_sysNestFreq, l_numMatches );
                FAPI_ASSERT(false,
                            fapi2::INVALID_MATCHING_FREQ_NUMBER().
                            set_MATCHES_FOUND(l_numMatches).
                            set_DESIRED_FREQPB(l_sysNestFreq).
                            set_LRPREC(lrpRecord).
                            set_BUCKETA_FREQPB(l_bucketNestFreqs[0]).
                            set_BUCKETB_FREQPB(l_bucketNestFreqs[1]).
                            set_BUCKETC_FREQPB(l_bucketNestFreqs[2]).
                            set_BUCKETD_FREQPB(l_bucketNestFreqs[3]).
                            set_BUCKETE_FREQPB(l_bucketNestFreqs[4]).
                            set_BUCKETF_FREQPB(l_bucketNestFreqs[5]).
                            set_EQ(i_target),
                            "Matches found is NOT 1" );
            }
        }
        else
        {
            FAPI_ASSERT( false,
                         fapi2::INVALID_POUNDV_VERSION()
                         .set_POUNDV_VERSION(*l_fullVpdData),
                         "p9_pm_get_poundv_bucket_attr::Invalid #V record version: 0x%x",
                         *l_fullVpdData);
        }

        // This assert ensures the size of the calculated data is correct
        FAPI_ASSERT(l_vpdSize - POUNDV_BUCKET_OFFSET - ((l_bucketId - 1) *
                    l_bucketSize) >= l_bucketSize,
                    fapi2::BAD_VPD_READ().set_EXPECTED_SIZE(sizeof(l_bucketSize))
                    .set_ACTUAL_SIZE(l_vpdSize - POUNDV_BUCKET_OFFSET -
                                     ((l_bucketId - 1) * l_bucketSize)),
                    "#V data read was too small!" );

    }// else no override

    // Ensure we got a valid bucket id
    // NOTE: Bucket IDs range from 1-6
    FAPI_ASSERT( (l_bucketId <= NUM_BUCKETS) && (l_bucketId != 0),
                 fapi2::INVALID_BUCKET_ID()
                 .set_TARGET(i_target)
                 .set_BUCKET_ID(l_bucketId),
                 "Invalid Bucket Id = %d",
                 l_bucketId );

    // Use the selected bucket id to populate the output data
    memcpy(o_data,
           l_fullVpdData + POUNDV_BUCKET_OFFSET + (l_bucketId - 1) * l_bucketSize,
           l_bucketSize);

fapi_try_exit:

    if(l_fullVpdData != NULL)
    {
        free(l_fullVpdData);
        l_fullVpdData = NULL;
    }

    if(l_prDataPtr != NULL)
    {
        free(l_prDataPtr);
        l_prDataPtr = NULL;
    }

    FAPI_DBG("Exiting p9_pm_get_poundv_bucket_attr ....");

    return fapi2::current_err;
}
<commit_msg>L3 Update - p9_pm_get_poundv/w_bucket HWPs<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_get_poundv_bucket_attr.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///

/// @file p9_pm_get_poundv_bucket_attr.C
/// @brief Grab PM data from certain bucket in #V keyword in LRPX record
///
/// *HWP HW Owner    : N/A (This is a FW delivered function)
/// *HWP FW Owner    : Thi Tran <thi@us.ibm.com>
/// *HWP Team        : PM - Calling this function.
/// *HWP Consumed by : FSP
/// *HWP Level       : 3
///

// ----------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------
#include <p9_pm_get_poundv_bucket_attr.H>
#include <p9_pm_get_poundv_bucket.H>
#include <mvpd_access_defs.H>
#include <attribute_ids.H>

fapi2::ReturnCode p9_pm_get_poundv_bucket_attr(
    const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
    uint8_t* o_data)
{
    FAPI_DBG("Entering p9_pm_get_poundv_bucket_attr ....");
    uint8_t* l_prDataPtr = NULL;
    uint8_t* l_fullVpdData = NULL;
    uint8_t l_overridePresent = 0;
    uint32_t l_tempVpdSize = 0;
    uint32_t l_vpdSize = 0;
    uint8_t l_eqChipUnitPos = 0;
    uint8_t l_bucketId;
    uint8_t l_bucketSize = 0;
    uint32_t l_sysNestFreq = 0;
    fapi2::voltageBucketData_t* l_currentBucket = NULL;
    uint8_t l_numMatches = 0;
    uint16_t l_pbFreq = 0;

    fapi2::MvpdRecord lrpRecord = fapi2::MVPD_RECORD_LAST;
    //To read MVPD we will need the proc parent of the inputted EQ target
    fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> l_procParent =
        i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();

    //Need to determine which LRP record to read from depending on which
    //bucket we are getting the power management data from. FapiPos will
    //tell us which LRP record to use.
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                           i_target,
                           l_eqChipUnitPos));

    FAPI_ASSERT( l_eqChipUnitPos < NUM_BUCKETS ,
                 fapi2::INVALID_EQ_CHIP_POS().
                 set_EQ_POSITION( l_eqChipUnitPos ),
                 "Invalid EQ chip unit position = 0x%X",
                 l_eqChipUnitPos);

    //The enumeration for the LRPx records are just 3 more
    //than the EQ chip unit pos. See mvpd_access_defs.H
    lrpRecord = static_cast<fapi2::MvpdRecord>(l_eqChipUnitPos +
                fapi2::MVPD_RECORD_LRP0 );

    //check if bucket num has been overriden
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POUNDV_BUCKET_NUM_OVERRIDE,
                           i_target,
                           l_overridePresent));

    if(l_overridePresent != 0)
    {
        //If it has been overriden then get the override
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POUNDV_BUCKET_NUM,
                               i_target,
                               l_bucketId));
    }
    else
    {
        //First read is to get size of vpd record, note the o_buffer is NULL
        FAPI_TRY( getMvpdField(lrpRecord,
                               fapi2::MVPD_KEYWORD_PDV,
                               l_procParent,
                               NULL,
                               l_tempVpdSize) );

        //save off the actual vpd size
        l_vpdSize = l_tempVpdSize;
        //Allocate memory for vpd data
        l_fullVpdData = reinterpret_cast<uint8_t*>(malloc(l_tempVpdSize));

        //Second read is to get data of vpd record
        FAPI_TRY( getMvpdField(lrpRecord,
                               fapi2::MVPD_KEYWORD_PDV,
                               l_procParent,
                               l_fullVpdData,
                               l_tempVpdSize) );

        //Version 2:
        //#V record is laid out as follows:
        //Name:     0x2 byte
        //Length:   0x2 byte
        //Version:  0x1 byte **buffer starts here
        //PNP:      0x3 byte
        //bucket a: 0x33 byte
        //bucket b: 0x33 byte
        //bucket c: 0x33 byte
        //bucket d: 0x33 byte
        //bucket e: 0x33 byte
        //bucket f: 0x33 byte
        if( *l_fullVpdData == POUNDV_VERSION_2)
        {
            //Set the size of the bucket
            l_bucketSize = VERSION_2_BUCKET_SIZE;

            //Reset VPD size because we want to find size of another VPD record
            l_tempVpdSize = 0;

            //First read is to get size of vpd record, note the o_buffer is NULL
            FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_VINI,
                                   fapi2::MVPD_KEYWORD_PR,
                                   l_procParent,
                                   NULL,
                                   l_tempVpdSize) );

            l_prDataPtr = reinterpret_cast<uint8_t*>(malloc(l_tempVpdSize));

            //Second read is to get data of vpd record
            FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_VINI,
                                   fapi2::MVPD_KEYWORD_PR,
                                   l_procParent,
                                   l_prDataPtr,
                                   l_tempVpdSize) );

            //Bucket ID is byte[4] of the PR keyword
            memcpy(&l_bucketId, (l_prDataPtr + 4), sizeof(uint8_t));

        }
        //Version 3:
        //#V record is laid out as follows:
        //Name:     0x2 byte
        //Length:   0x2 byte
        //Version:  0x1 byte **buffer starts here
        //PNP:      0x3 byte
        //bucket a: 0x3D byte
        //bucket b: 0x3D byte
        //bucket c: 0x3D byte
        //bucket d: 0x3D byte
        //bucket e: 0x3D byte
        //bucket f: 0x3D byte
        else if( *l_fullVpdData == POUNDV_VERSION_3 )
        {
            // Set the size of the bucket
            l_bucketSize = VERSION_3_BUCKET_SIZE;

            //Save off some FFDC data about the #V data itself
            uint16_t l_bucketNestFreqs[NUM_BUCKETS] = { 0, 0, 0, 0, 0, 0 };

            // Version 3 uses the nest frequency to choose the bucket Id
            // get the system target to find the NEST_FREQ_MHZ
            fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> l_sysParent;

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_PB_MHZ,
                                   l_sysParent,
                                   l_sysNestFreq));
            //cast the voltage data into an array of buckets
            fapi2::voltageBucketData_t* l_buckets = reinterpret_cast
                                                    <fapi2::voltageBucketData_t*>
                                                    (l_fullVpdData + POUNDV_BUCKET_OFFSET);

            for(int i = 0; i < NUM_BUCKETS; i++)
            {
#ifndef _BIG_ENDIAN
                l_pbFreq = ( (((l_buckets[i].pbFreq) >> 8) & 0x00FF) | (((l_buckets[i].pbFreq) << 8) & 0xFF00) );
#else
                l_pbFreq = l_buckets[i].pbFreq;
#endif

                if(l_pbFreq == l_sysNestFreq)
                {
                    l_numMatches++;

                    if(l_numMatches > 1)
                    {
                        FAPI_ERR("p9_pm_get_poundv_bucket_attr::"
                                 " Multiple buckets (%d) reporting the same nest frequency"
                                 " Bucket Nest = %d Bucket ID = %d, First Bucket = %d",
                                 l_numMatches,
                                 l_pbFreq,
                                 (i + 1),
                                 l_currentBucket);

                    }
                    else
                    {
                        l_currentBucket = &l_buckets[i];
                    }
                }

                //save FFDC in case we fail
                l_bucketNestFreqs[i] = l_pbFreq;
            }

            if(l_numMatches == 1)
            {
                l_bucketId = l_currentBucket->bucketId;
            }
            else
            {

                FAPI_ERR("p9_pm_get_poundv_bucket_attr::Invalid number of matching "
                         "nest freqs found for PBFreq=%d. Matches found = %d",
                         l_sysNestFreq, l_numMatches );
                FAPI_ASSERT(false,
                            fapi2::INVALID_MATCHING_FREQ_NUMBER().
                            set_EQ_TARGET(i_target).
                            set_MATCHES_FOUND(l_numMatches).
                            set_DESIRED_FREQPB(l_sysNestFreq).
                            set_LRPREC(lrpRecord).
                            set_BUCKETA_FREQPB(l_bucketNestFreqs[0]).
                            set_BUCKETB_FREQPB(l_bucketNestFreqs[1]).
                            set_BUCKETC_FREQPB(l_bucketNestFreqs[2]).
                            set_BUCKETD_FREQPB(l_bucketNestFreqs[3]).
                            set_BUCKETE_FREQPB(l_bucketNestFreqs[4]).
                            set_BUCKETF_FREQPB(l_bucketNestFreqs[5]),
                            "Matches found is NOT 1" );
            }
        }
        else
        {
            FAPI_ASSERT( false,
                         fapi2::INVALID_POUNDV_VERSION()
                         .set_EQ_TARGET(i_target)
                         .set_POUNDV_VERSION(*l_fullVpdData),
                         "p9_pm_get_poundv_bucket_attr::Invalid #V record version: 0x%x",
                         *l_fullVpdData);
        }

        // This assert ensures the size of the calculated data is correct
        FAPI_ASSERT(l_vpdSize - POUNDV_BUCKET_OFFSET - ((l_bucketId - 1) *
                    l_bucketSize) >= l_bucketSize,
                    fapi2::BAD_VPD_READ()
                    .set_EQ_TARGET(i_target)
                    .set_EXPECTED_SIZE(sizeof(l_bucketSize))
                    .set_ACTUAL_SIZE(l_vpdSize - POUNDV_BUCKET_OFFSET -
                                     ((l_bucketId - 1) * l_bucketSize)),
                    "#V data read was too small!" );

    }// else no override

    // Ensure we got a valid bucket id
    // NOTE: Bucket IDs range from 1-6
    FAPI_ASSERT( (l_bucketId <= NUM_BUCKETS) && (l_bucketId != 0),
                 fapi2::INVALID_BUCKET_ID()
                 .set_EQ_TARGET(i_target)
                 .set_BUCKET_ID(l_bucketId),
                 "Invalid Bucket Id = %d",
                 l_bucketId );

    // Use the selected bucket id to populate the output data
    memcpy(o_data,
           l_fullVpdData + POUNDV_BUCKET_OFFSET + (l_bucketId - 1) * l_bucketSize,
           l_bucketSize);

fapi_try_exit:

    if(l_fullVpdData != NULL)
    {
        free(l_fullVpdData);
        l_fullVpdData = NULL;
    }

    if(l_prDataPtr != NULL)
    {
        free(l_prDataPtr);
        l_prDataPtr = NULL;
    }

    FAPI_DBG("Exiting p9_pm_get_poundv_bucket_attr ....");

    return fapi2::current_err;
}
<|endoftext|>


<commit_before>#include "Sky.hpp"
#include "Game.hpp"

static std::array<SkyManager::Flare, 11> g_lensFlares {
    {{
	 18.f,
	 0.9f,
	 {},
	 1.f
     },
     {
	 46.f,
	 0.45f,
	 {},
	 1.f
     }, {
	 100.f,
	 0.6f,
	 {},
	 1.f
     },
     {
	 200.f,
	 0.4f,
	 {},
	 1.f
     },
     {
	 300.f,
	 1.2f,
	 {},
	 1.f
     },
     {
	 360.f,
	 0.15f,
	 {},
	 1.f
     },
     {
	 500.f,
	 2.5f,
	 {},
	 1.f
     },
     {
	 525.f,
	 0.4f,
	 {},
	 1.f
     },
     {
	 1350.f,
	 4.5f,
	 {},
	 1.f
     },
     {
	 1700.f,
	 3.6f,
	 {},
	 1.f
     },
     {
	 1850.f,
	 4.8f,
	 {},
	 1.f
     }
    }
};

void SkyManager::Update(const glm::vec3 & cameraPos, const glm::vec3 & viewDir) {
    m_sunPos = cameraPos - glm::vec3{0, 0, 400};
    m_sunPos.y = 180;
    m_sunVisible = IntersectsFrustum(m_sunPos, cameraPos, viewDir);
    if (m_sunVisible) {
	auto windowSize = GetGame().GetWindowSize();
	glm::mat4 view = GetGame().GetCamera().GetWorldView();
	glm::mat4 proj = glm::perspective(45.0f, windowSize.x / (float)windowSize.y, 0.1f, 1.0f);
	glm::vec4 viewPort = {0, 0, windowSize.x, windowSize.y};
	auto sunScreenCoord = glm::project(m_sunPos, view, proj, viewPort);
	// The frustum check can be inexact for far away things (eg the sun), and it's really important here
	// to only draw the lens flare when the sun is visible in the view!
	static const float sunRad = 48.f;
	if (sunScreenCoord.y > windowSize.y + sunRad) {
	    m_sunVisible = false;
	    return;
	}
	glm::vec3 directionVec = {
	    glm::vec3{windowSize.x / 2, windowSize.y / 2, 0.f} -
	    glm::vec3{sunScreenCoord.x, sunScreenCoord.y, 0.f}
	};
	const float dist = glm::length(directionVec);
	directionVec = glm::normalize(directionVec);
	const float distRatioToMax = dist / 900.f;
	for (auto & flare : g_lensFlares) {
	    flare.position =
		glm::vec3{sunScreenCoord.x, sunScreenCoord.y, 0.f} + glm::vec3(directionVec * flare.displFactor *
									       distRatioToMax);
	    flare.intensity = 1.f - distRatioToMax;
	}
    }
}

void SkyManager::Display() {
    if (m_sunVisible) {
	const GLuint textrdQuadProg =
	    GetGame().GetAssets().GetShaderProgram(ShaderProgramId::GenericTextured);
	glUseProgram(textrdQuadProg);
	glActiveTexture(GL_TEXTURE1);
	glUniform1i(glGetUniformLocation(textrdQuadProg, "tex"), 1);
	glBindTexture(GL_TEXTURE_2D, GetGame().GetAssets().GetTexture(TextureId::Sun)->GetId());
	const GLint modelLoc = glGetUniformLocation(textrdQuadProg, "model");
	glm::mat4 model;
	// FIXME: Rotate the sun so that its normal points toward the eye
	model = glm::translate(model, m_sunPos);
	glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
	Primitives::Quad quad;
	quad.Display(textrdQuadProg, {BlendMode::Mode::One, BlendMode::Mode::One});
	glBindTexture(GL_TEXTURE_2D, 0);
    }
}

void SkyManager::DoLensFlare() {
    if (m_sunVisible) {
	const GLuint lensFlareProg = GetGame().GetAssets().GetShaderProgram(ShaderProgramId::LensFlare);
	glUseProgram(lensFlareProg);
	for (auto & flare : g_lensFlares) {
	    const auto intensityLoc = glGetUniformLocation(lensFlareProg, "intensity");
	    glUniform1f(intensityLoc, 0.35f * flare.intensity);
	    Primitives::Hexagon hex;
	    glm::mat4 model = glm::translate(glm::mat4(1), flare.position);
	    model = glm::scale(model, {flare.scale, flare.scale, flare.scale});
	    const GLint modelLoc = glGetUniformLocation(lensFlareProg, "model");
	    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
	    hex.Display(lensFlareProg, {BlendMode::Mode::One, BlendMode::Mode::One});
	}
    }
}
<commit_msg>lens flare constant decreased by 0.5f<commit_after>#include "Sky.hpp"
#include "Game.hpp"

static std::array<SkyManager::Flare, 11> g_lensFlares {
    {{
	 18.f,
	 0.9f,
	 {},
	 1.f
     },
     {
	 46.f,
	 0.45f,
	 {},
	 1.f
     }, {
	 100.f,
	 0.6f,
	 {},
	 1.f
     },
     {
	 200.f,
	 0.4f,
	 {},
	 1.f
     },
     {
	 300.f,
	 1.2f,
	 {},
	 1.f
     },
     {
	 360.f,
	 0.15f,
	 {},
	 1.f
     },
     {
	 500.f,
	 2.5f,
	 {},
	 1.f
     },
     {
	 525.f,
	 0.4f,
	 {},
	 1.f
     },
     {
	 1350.f,
	 4.5f,
	 {},
	 1.f
     },
     {
	 1700.f,
	 3.6f,
	 {},
	 1.f
     },
     {
	 1850.f,
	 4.8f,
	 {},
	 1.f
     }
    }
};

void SkyManager::Update(const glm::vec3 & cameraPos, const glm::vec3 & viewDir) {
    m_sunPos = cameraPos - glm::vec3{0, 0, 400};
    m_sunPos.y = 180;
    m_sunVisible = IntersectsFrustum(m_sunPos, cameraPos, viewDir);
    if (m_sunVisible) {
	auto windowSize = GetGame().GetWindowSize();
	glm::mat4 view = GetGame().GetCamera().GetWorldView();
	glm::mat4 proj = glm::perspective(45.0f, windowSize.x / (float)windowSize.y, 0.1f, 1.0f);
	glm::vec4 viewPort = {0, 0, windowSize.x, windowSize.y};
	auto sunScreenCoord = glm::project(m_sunPos, view, proj, viewPort);
	// The frustum check can be inexact for far away things (eg the sun), and it's really important here
	// to only draw the lens flare when the sun is visible in the view!
	static const float sunRad = 48.f;
	if (sunScreenCoord.y > windowSize.y + sunRad) {
	    m_sunVisible = false;
	    return;
	}
	glm::vec3 directionVec = {
	    glm::vec3{windowSize.x / 2, windowSize.y / 2, 0.f} -
	    glm::vec3{sunScreenCoord.x, sunScreenCoord.y, 0.f}
	};
	const float dist = glm::length(directionVec);
	directionVec = glm::normalize(directionVec);
	const float distRatioToMax = dist / 900.f;
	for (auto & flare : g_lensFlares) {
	    flare.position =
		glm::vec3{sunScreenCoord.x, sunScreenCoord.y, 0.f} + glm::vec3(directionVec * flare.displFactor *
									       distRatioToMax);
	    flare.intensity = 1.f - distRatioToMax;
	}
    }
}

void SkyManager::Display() {
    if (m_sunVisible) {
	const GLuint textrdQuadProg =
	    GetGame().GetAssets().GetShaderProgram(ShaderProgramId::GenericTextured);
	glUseProgram(textrdQuadProg);
	glActiveTexture(GL_TEXTURE1);
	glUniform1i(glGetUniformLocation(textrdQuadProg, "tex"), 1);
	glBindTexture(GL_TEXTURE_2D, GetGame().GetAssets().GetTexture(TextureId::Sun)->GetId());
	const GLint modelLoc = glGetUniformLocation(textrdQuadProg, "model");
	glm::mat4 model;
	// FIXME: Rotate the sun so that its normal points toward the eye
	model = glm::translate(model, m_sunPos);
	glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
	Primitives::Quad quad;
	quad.Display(textrdQuadProg, {BlendMode::Mode::One, BlendMode::Mode::One});
	glBindTexture(GL_TEXTURE_2D, 0);
    }
}

void SkyManager::DoLensFlare() {
    if (m_sunVisible) {
	const GLuint lensFlareProg = GetGame().GetAssets().GetShaderProgram(ShaderProgramId::LensFlare);
	glUseProgram(lensFlareProg);
	for (auto & flare : g_lensFlares) {
	    const auto intensityLoc = glGetUniformLocation(lensFlareProg, "intensity");
	    glUniform1f(intensityLoc, 0.3f * flare.intensity);
	    Primitives::Hexagon hex;
	    glm::mat4 model = glm::translate(glm::mat4(1), flare.position);
	    model = glm::scale(model, {flare.scale, flare.scale, flare.scale});
	    const GLint modelLoc = glGetUniformLocation(lensFlareProg, "model");
	    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
	    hex.Display(lensFlareProg, {BlendMode::Mode::One, BlendMode::Mode::One});
	}
    }
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// insert_plan.cpp
//
// Identification: src/planner/insert_plan.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "planner/insert_plan.h"

#include "catalog/catalog.h"
#include "expression/constant_value_expression.h"
#include "storage/data_table.h"
#include "type/ephemeral_pool.h"
#include "type/value_factory.h"

namespace peloton {
namespace planner {

/**
 * @brief Create an insert plan
 *
 * @param[in] table          Table to insert into
 * @param[in] columns        Columns to insert into
 * @param[in] insert_values  Values
 */
InsertPlan::InsertPlan(storage::DataTable *table,
    const std::vector<std::string> *columns,
    const std::vector<std::vector<
        std::unique_ptr<expression::AbstractExpression>>> *insert_values)
    : target_table_(table), bulk_insert_count_(insert_values->size()) {
  LOG_TRACE("Creating an Insert Plan with multiple expressions");
  PL_ASSERT(target_table_);

  // We assume we are not processing a prepared statement insert.
  // Only after we have finished processing, do we know if it is a
  // PS or not a PS.
  bool is_prepared_stmt = false;
  auto *schema = target_table_->GetSchema();
  auto schema_col_count = schema->GetColumnCount();
  vtos_.resize(insert_values->size());
  // initialize mapping from schema cols to insert values vector.
  // will be updated later based on insert columns and values
  stov_.resize(schema_col_count);
  for (uint32_t idx = 0; idx < schema_col_count; idx++) {
    stov_[idx].in_insert_cols = false;
    stov_[idx].set_value = false;
    stov_[idx].val_idx = 0;
    // remember the column types
    stov_[idx].type = schema->GetType(idx);
  }

  if (columns->empty()) {
    // INSERT INTO table_name VALUES (val1, val2, ...), (val1, val2, ...)
    for (uint32_t tuple_idx = 0; tuple_idx < insert_values->size();
         tuple_idx++) {
      auto &values = (*insert_values)[tuple_idx];
      PL_ASSERT(values.size() <= schema_col_count);
      // uint32_t param_idx = 0;
      for (uint32_t column_id = 0; column_id < values.size(); column_id++) {

        auto &exp = values[column_id];
	auto exp_ptr = exp.get();
	auto ret_bool = ProcessValueExpr(exp_ptr, column_id);
	// there is no column specification, so we have a
	// direct mapping between schema cols and the value vector
	stov_[column_id].in_insert_cols = true;
	stov_[column_id].val_idx = column_id;
	if (ret_bool == true) {
	  is_prepared_stmt = true;
	}
      }
    }
  } else {
    // INSERT INTO table_name (col1, col2, ...) VALUES (val1, val2, ...);
    // Columns may be in any order. Values may include constants.
    PL_ASSERT(columns->size() <= schema_col_count);
    // construct the mapping between schema cols and insert cols
    ProcessColumnSpec(columns);
    for (uint32_t tuple_idx = 0; tuple_idx < insert_values->size();
         tuple_idx++) {
      auto &values = (*insert_values)[tuple_idx];
      PL_ASSERT(values.size() <= schema_col_count);

      for (uint32_t idx = 0; idx < schema_col_count; idx++) {
	if (stov_[idx].in_insert_cols) {
	  // this schema column is present in the insert columns spec.
	  // get index into values
	  auto val_idx = stov_[idx].val_idx;
	  auto &exp = values[val_idx];
	  auto exp_ptr = exp.get();
	  bool ret_bool = ProcessValueExpr(exp_ptr, idx);
	  if (ret_bool) {
	    is_prepared_stmt = true;
	  }
	}
	else {
	  // schema column not present in insert columns spec. Set
	  // column to its default value
	  SetDefaultValue(idx);
	}
      }

      if (is_prepared_stmt) {
	// Adjust indexes into values. When constants are present in the
	// value tuple spec., the value vector supplied by the prepared
	// statement when SetParameterValues is called, will be smaller.
	// It will not include any of the constants.
	// Adjust the mapping from schema cols -> values vector to exclude
	// the constant columns. If there are no constants, this is a no-op.
	uint32_t adjust = 0;
	for (uint32_t idx=0; idx < columns->size(); idx++) {
	  uint32_t stov_idx = vtos_[idx];
	  if (stov_[stov_idx].set_value) {
	    // constant, not present in PS values
	    adjust++;
	  } else {
	    // adjust the index
	    stov_[stov_idx].val_idx -= adjust;
	  }
	}
      }
    }
  }
  if (is_prepared_stmt) {
    // We've been assuming it is not a PS and saving into the values_
    // vector. Now that we know it is a PS, we must clear those values
    // so SetParameterValues will operate correctly.
    ClearParameterValues();
  }
}

/**
 * Process column specification supplied in the insert statement.
 * Construct a map from insert columns to schema columns. Once
 * we know which columns will receive constant inserts, further
 * adjustment of the map will be needed.
 *
 * @param[in] columns        Column specification
 */
void InsertPlan::ProcessColumnSpec(const std::vector<std::string> *columns) {
  auto *schema = target_table_->GetSchema();
  auto &table_columns = schema->GetColumns();
  auto usr_col_count = columns->size();

  // iterate over supplied columns
  for (size_t usr_col_id = 0; usr_col_id < usr_col_count; usr_col_id++) {
    uint32_t idx;
    auto col_name = columns->at(usr_col_id);

    // determine index of column in schema
    bool found_col = FindSchemaColIndex(col_name, table_columns, idx);
    // PL_ASSERT(found_col == true);
    if (not found_col) {
      throw Exception("column " + col_name + " not in table " +
		      target_table_->GetName() + " columns");
    }
    // we have values for this column
    stov_[idx].in_insert_cols = true;
    // remember how to map schema col -> value for col in tuple
    stov_[idx].val_idx = usr_col_id;
    // and the reverse
    vtos_[usr_col_id] = idx;
  }
}

/**
 * Process a single expression to be inserted.
 *
 * @param[in] expr       insert expression
 * @param[in] schema_idx index into schema columns, where the expr
 *                       will be inserted.
 * @return  true if values imply a prepared statement
 *          false if all values are constants. This does not rule
 *             out the insert being a prepared statement.
 */
bool InsertPlan::ProcessValueExpr(expression::AbstractExpression *expr,
				  uint32_t schema_idx) {
  auto type = stov_[schema_idx].type;

  if (expr == nullptr) {
    SetDefaultValue(schema_idx);
  } else if (expr->GetExpressionType() == ExpressionType::VALUE_CONSTANT) {

    auto *const_expr =
      dynamic_cast<expression::ConstantValueExpression *>(expr);
    type::Value value = const_expr->GetValue().CastAs(type);

    stov_[schema_idx].set_value = true;
    stov_[schema_idx].value = value;
    // save it, in case this is not a PS
    values_.push_back(value);

    return false;
  } else {
    PL_ASSERT(expr->GetExpressionType() == ExpressionType::VALUE_PARAMETER);
    return true;
  }
  return false;
}

/**
 * Set default value into a schema column
 *
 * @param[in] idx  schema column index
 */
void InsertPlan::SetDefaultValue(uint32_t idx) {
  auto *schema = target_table_->GetSchema();
  type::Value *v = schema->GetDefaultValue(idx);
  type::TypeId type = stov_[idx].type;

  if (v == nullptr)
    // null default value
    values_.push_back(type::ValueFactory::GetNullValueByType(type));
  else
    // non-null default value
    values_.push_back(*v);
}

/**
 * Lookup a column name in the schema columns
 *
 * @param[in]  col_name    column name, from insert statement
 * @param[in]  tbl_columns table columns from the schema
 * @param[out] index       index into schema columns, only if found
 *
 * @return      true if column was found, false otherwise
 */
bool InsertPlan::FindSchemaColIndex(std::string col_name,
				    const std::vector<catalog::Column> &tbl_columns,
				    uint32_t &index) {
  for (auto tcol = tbl_columns.begin(); tcol != tbl_columns.end(); tcol++) {
    if (tcol->GetName() == col_name) {
      index = std::distance(tbl_columns.begin(), tcol);
      return true;
    }
  }
  return false;
}

type::AbstractPool *InsertPlan::GetPlanPool() {
  if (pool_.get() == nullptr)
    pool_.reset(new type::EphemeralPool());
  return pool_.get();
}

/**
 * @brief Save values for jdbc prepared statement insert.
 *    Only a single tuple is presented to this function.
 *
 * @param[in] values  Values for insertion
 */
void InsertPlan::SetParameterValues(std::vector<type::Value> *values) {
  LOG_TRACE("Set Parameter Values in Insert");
  auto *schema = target_table_->GetSchema();
  auto schema_col_count = schema->GetColumnCount();

  PL_ASSERT(values->size() <= schema_col_count);
  for (uint32_t idx = 0; idx < schema_col_count; idx++) {
    if (stov_[idx].set_value) {
      values_.push_back(stov_[idx].value);
    } else if (stov_[idx].in_insert_cols) {
      // get index into values
      auto val_idx = stov_[idx].val_idx;
      auto type = stov_[idx].type;
      type::Value value = values->at(val_idx).CastAs(type);
      values_.push_back(value);
    } else {
      // not in insert cols, set default value
      SetDefaultValue(idx);
    }
  }
}

void InsertPlan::PerformBinding(BindingContext &binding_context) {
  const auto &children = GetChildren();

  if (children.size() == 1) {
    children[0]->PerformBinding(binding_context);

    auto *scan = static_cast<planner::AbstractScan *>(children[0].get());
    auto &col_ids = scan->GetColumnIds();
    for (oid_t col_id = 0; col_id < col_ids.size(); col_id++) {
      ais_.push_back(binding_context.Find(col_id));
    }
  }
  // Binding is not required if there is no child
}

hash_t InsertPlan::Hash() const {
  auto type = GetPlanNodeType();
  hash_t hash = HashUtil::Hash(&type);

  hash = HashUtil::CombineHashes(hash, GetTable()->Hash());
  if (GetChildren().size() == 0) {
    auto bulk_insert_count = GetBulkInsertCount();
    hash = HashUtil::CombineHashes(hash, HashUtil::Hash(&bulk_insert_count));
  }

  return HashUtil::CombineHashes(hash, AbstractPlan::Hash());
}

bool InsertPlan::operator==(const AbstractPlan &rhs) const {
  if (GetPlanNodeType() != rhs.GetPlanNodeType())
    return false;

  auto &other = static_cast<const planner::InsertPlan &>(rhs);

  auto *table = GetTable();
  auto *other_table = other.GetTable();
  PL_ASSERT(table && other_table);
  if (*table != *other_table)
    return false;

  if (GetChildren().size() == 0) {
    if (other.GetChildren().size() != 0)
      return false;

    if (GetBulkInsertCount() != other.GetBulkInsertCount())
      return false;
  }

  return AbstractPlan::operator==(rhs);
}

void InsertPlan::VisitParameters(
    codegen::QueryParametersMap &map, std::vector<peloton::type::Value> &values,
    const std::vector<peloton::type::Value> &values_from_user) {
  if (GetChildren().size() == 0) {
    auto *schema = target_table_->GetSchema();
    auto columns_num = schema->GetColumnCount();

    for (uint32_t i = 0; i < values_.size(); i++) {
      auto value = values_[i];
      auto column_id = i % columns_num;
      map.Insert(expression::Parameter::CreateConstParameter(value.GetTypeId(),
          schema->AllowNull(column_id)), nullptr);
      values.push_back(value);
    }
  } else {
    PL_ASSERT(GetChildren().size() == 1);
    auto *plan = const_cast<planner::AbstractPlan *>(GetChild(0));
    plan->VisitParameters(map, values, values_from_user);
  }
}

}  // namespace planner
}  // namespace peloton
<commit_msg>Fix vector sizing bug (heap corruption)<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// insert_plan.cpp
//
// Identification: src/planner/insert_plan.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "planner/insert_plan.h"

#include "catalog/catalog.h"
#include "expression/constant_value_expression.h"
#include "storage/data_table.h"
#include "type/ephemeral_pool.h"
#include "type/value_factory.h"

namespace peloton {
namespace planner {

/**
 * @brief Create an insert plan
 *
 * @param[in] table          Table to insert into
 * @param[in] columns        Columns to insert into
 * @param[in] insert_values  Values
 */
InsertPlan::InsertPlan(storage::DataTable *table,
    const std::vector<std::string> *columns,
    const std::vector<std::vector<
        std::unique_ptr<expression::AbstractExpression>>> *insert_values)
    : target_table_(table), bulk_insert_count_(insert_values->size()) {
  LOG_TRACE("Creating an Insert Plan with multiple expressions");
  PL_ASSERT(target_table_);

  // We assume we are not processing a prepared statement insert.
  // Only after we have finished processing, do we know if it is a
  // PS or not a PS.
  bool is_prepared_stmt = false;
  auto *schema = target_table_->GetSchema();
  auto schema_col_count = schema->GetColumnCount();
  vtos_.resize(columns->size());
  // initialize mapping from schema cols to insert values vector.
  // will be updated later based on insert columns and values
  stov_.resize(schema_col_count);
  for (uint32_t idx = 0; idx < schema_col_count; idx++) {
    stov_[idx].in_insert_cols = false;
    stov_[idx].set_value = false;
    stov_[idx].val_idx = 0;
    // remember the column types
    stov_[idx].type = schema->GetType(idx);
  }

  if (columns->empty()) {
    // INSERT INTO table_name VALUES (val1, val2, ...), (val1, val2, ...)
    for (uint32_t tuple_idx = 0; tuple_idx < insert_values->size();
         tuple_idx++) {
      auto &values = (*insert_values)[tuple_idx];
      PL_ASSERT(values.size() <= schema_col_count);
      // uint32_t param_idx = 0;
      for (uint32_t column_id = 0; column_id < values.size(); column_id++) {

        auto &exp = values[column_id];
	auto exp_ptr = exp.get();
	auto ret_bool = ProcessValueExpr(exp_ptr, column_id);
	// there is no column specification, so we have a
	// direct mapping between schema cols and the value vector
	stov_[column_id].in_insert_cols = true;
	stov_[column_id].val_idx = column_id;
	if (ret_bool == true) {
	  is_prepared_stmt = true;
	}
      }
    }
  } else {
    // INSERT INTO table_name (col1, col2, ...) VALUES (val1, val2, ...);
    // Columns may be in any order. Values may include constants.
    PL_ASSERT(columns->size() <= schema_col_count);
    // construct the mapping between schema cols and insert cols
    ProcessColumnSpec(columns);
    for (uint32_t tuple_idx = 0; tuple_idx < insert_values->size();
         tuple_idx++) {
      auto &values = (*insert_values)[tuple_idx];
      PL_ASSERT(values.size() <= schema_col_count);

      for (uint32_t idx = 0; idx < schema_col_count; idx++) {
	if (stov_[idx].in_insert_cols) {
	  // this schema column is present in the insert columns spec.
	  // get index into values
	  auto val_idx = stov_[idx].val_idx;
	  auto &exp = values[val_idx];
	  auto exp_ptr = exp.get();
	  bool ret_bool = ProcessValueExpr(exp_ptr, idx);
	  if (ret_bool) {
	    is_prepared_stmt = true;
	  }
	}
	else {
	  // schema column not present in insert columns spec. Set
	  // column to its default value
	  SetDefaultValue(idx);
	}
      }

      if (is_prepared_stmt) {
	// Adjust indexes into values. When constants are present in the
	// value tuple spec., the value vector supplied by the prepared
	// statement when SetParameterValues is called, will be smaller.
	// It will not include any of the constants.
	// Adjust the mapping from schema cols -> values vector to exclude
	// the constant columns. If there are no constants, this is a no-op.
	uint32_t adjust = 0;
	for (uint32_t idx=0; idx < columns->size(); idx++) {
	  uint32_t stov_idx = vtos_[idx];
	  if (stov_[stov_idx].set_value) {
	    // constant, not present in PS values
	    adjust++;
	  } else {
	    // adjust the index
	    stov_[stov_idx].val_idx -= adjust;
	  }
	}
      }
    }
  }
  if (is_prepared_stmt) {
    // We've been assuming it is not a PS and saving into the values_
    // vector. Now that we know it is a PS, we must clear those values
    // so SetParameterValues will operate correctly.
    ClearParameterValues();
  }
}

/**
 * Process column specification supplied in the insert statement.
 * Construct a map from insert columns to schema columns. Once
 * we know which columns will receive constant inserts, further
 * adjustment of the map will be needed.
 *
 * @param[in] columns        Column specification
 */
void InsertPlan::ProcessColumnSpec(const std::vector<std::string> *columns) {
  auto *schema = target_table_->GetSchema();
  auto &table_columns = schema->GetColumns();
  auto usr_col_count = columns->size();

  // iterate over supplied columns
  for (size_t usr_col_id = 0; usr_col_id < usr_col_count; usr_col_id++) {
    uint32_t idx;
    auto col_name = columns->at(usr_col_id);

    // determine index of column in schema
    bool found_col = FindSchemaColIndex(col_name, table_columns, idx);
    if (not found_col) {
      throw Exception("column " + col_name + " not in table " +
		      target_table_->GetName() + " columns");
    }
    // we have values for this column
    stov_[idx].in_insert_cols = true;
    // remember how to map schema col -> value for col in tuple
    stov_[idx].val_idx = usr_col_id;
    // and the reverse
    vtos_[usr_col_id] = idx;
  }
}

/**
 * Process a single expression to be inserted.
 *
 * @param[in] expr       insert expression
 * @param[in] schema_idx index into schema columns, where the expr
 *                       will be inserted.
 * @return  true if values imply a prepared statement
 *          false if all values are constants. This does not rule
 *             out the insert being a prepared statement.
 */
bool InsertPlan::ProcessValueExpr(expression::AbstractExpression *expr,
				  uint32_t schema_idx) {
  auto type = stov_[schema_idx].type;

  if (expr == nullptr) {
    SetDefaultValue(schema_idx);
  } else if (expr->GetExpressionType() == ExpressionType::VALUE_CONSTANT) {

    auto *const_expr =
      dynamic_cast<expression::ConstantValueExpression *>(expr);
    type::Value value = const_expr->GetValue().CastAs(type);

    stov_[schema_idx].set_value = true;
    stov_[schema_idx].value = value;
    // save it, in case this is not a PS
    values_.push_back(value);

    return false;
  } else {
    PL_ASSERT(expr->GetExpressionType() == ExpressionType::VALUE_PARAMETER);
    return true;
  }
  return false;
}

/**
 * Set default value into a schema column
 *
 * @param[in] idx  schema column index
 */
void InsertPlan::SetDefaultValue(uint32_t idx) {
  auto *schema = target_table_->GetSchema();
  type::Value *v = schema->GetDefaultValue(idx);
  type::TypeId type = stov_[idx].type;

  if (v == nullptr)
    // null default value
    values_.push_back(type::ValueFactory::GetNullValueByType(type));
  else
    // non-null default value
    values_.push_back(*v);
}

/**
 * Lookup a column name in the schema columns
 *
 * @param[in]  col_name    column name, from insert statement
 * @param[in]  tbl_columns table columns from the schema
 * @param[out] index       index into schema columns, only if found
 *
 * @return      true if column was found, false otherwise
 */
bool InsertPlan::FindSchemaColIndex(std::string col_name,
				    const std::vector<catalog::Column> &tbl_columns,
				    uint32_t &index) {
  for (auto tcol = tbl_columns.begin(); tcol != tbl_columns.end(); tcol++) {
    if (tcol->GetName() == col_name) {
      index = std::distance(tbl_columns.begin(), tcol);
      return true;
    }
  }
  return false;
}

type::AbstractPool *InsertPlan::GetPlanPool() {
  if (pool_.get() == nullptr)
    pool_.reset(new type::EphemeralPool());
  return pool_.get();
}

/**
 * @brief Save values for jdbc prepared statement insert.
 *    Only a single tuple is presented to this function.
 *
 * @param[in] values  Values for insertion
 */
void InsertPlan::SetParameterValues(std::vector<type::Value> *values) {
  LOG_TRACE("Set Parameter Values in Insert");
  auto *schema = target_table_->GetSchema();
  auto schema_col_count = schema->GetColumnCount();

  PL_ASSERT(values->size() <= schema_col_count);
  for (uint32_t idx = 0; idx < schema_col_count; idx++) {
    if (stov_[idx].set_value) {
      values_.push_back(stov_[idx].value);
    } else if (stov_[idx].in_insert_cols) {
      // get index into values
      auto val_idx = stov_[idx].val_idx;
      auto type = stov_[idx].type;
      type::Value value = values->at(val_idx).CastAs(type);
      values_.push_back(value);
    } else {
      // not in insert cols, set default value
      SetDefaultValue(idx);
    }
  }
}

void InsertPlan::PerformBinding(BindingContext &binding_context) {
  const auto &children = GetChildren();

  if (children.size() == 1) {
    children[0]->PerformBinding(binding_context);

    auto *scan = static_cast<planner::AbstractScan *>(children[0].get());
    auto &col_ids = scan->GetColumnIds();
    for (oid_t col_id = 0; col_id < col_ids.size(); col_id++) {
      ais_.push_back(binding_context.Find(col_id));
    }
  }
  // Binding is not required if there is no child
}

hash_t InsertPlan::Hash() const {
  auto type = GetPlanNodeType();
  hash_t hash = HashUtil::Hash(&type);

  hash = HashUtil::CombineHashes(hash, GetTable()->Hash());
  if (GetChildren().size() == 0) {
    auto bulk_insert_count = GetBulkInsertCount();
    hash = HashUtil::CombineHashes(hash, HashUtil::Hash(&bulk_insert_count));
  }

  return HashUtil::CombineHashes(hash, AbstractPlan::Hash());
}

bool InsertPlan::operator==(const AbstractPlan &rhs) const {
  if (GetPlanNodeType() != rhs.GetPlanNodeType())
    return false;

  auto &other = static_cast<const planner::InsertPlan &>(rhs);

  auto *table = GetTable();
  auto *other_table = other.GetTable();
  PL_ASSERT(table && other_table);
  if (*table != *other_table)
    return false;

  if (GetChildren().size() == 0) {
    if (other.GetChildren().size() != 0)
      return false;

    if (GetBulkInsertCount() != other.GetBulkInsertCount())
      return false;
  }

  return AbstractPlan::operator==(rhs);
}

void InsertPlan::VisitParameters(
    codegen::QueryParametersMap &map, std::vector<peloton::type::Value> &values,
    const std::vector<peloton::type::Value> &values_from_user) {
  if (GetChildren().size() == 0) {
    auto *schema = target_table_->GetSchema();
    auto columns_num = schema->GetColumnCount();

    for (uint32_t i = 0; i < values_.size(); i++) {
      auto value = values_[i];
      auto column_id = i % columns_num;
      map.Insert(expression::Parameter::CreateConstParameter(value.GetTypeId(),
          schema->AllowNull(column_id)), nullptr);
      values.push_back(value);
    }
  } else {
    PL_ASSERT(GetChildren().size() == 1);
    auto *plan = const_cast<planner::AbstractPlan *>(GetChild(0));
    plan->VisitParameters(map, values, values_from_user);
  }
}

}  // namespace planner
}  // namespace peloton
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkFontMgr.h"
#include "SkFontStyle.h"
#include "SkFontConfigInterface.h"
#include "SkFontConfigTypeface.h"
#include "SkMath.h"
#include "SkString.h"
#include "SkTDArray.h"
#include "SkThread.h"

// for now we pull these in directly. eventually we will solely rely on the
// SkFontConfigInterface instance.
#include <fontconfig/fontconfig.h>
#include <unistd.h>

namespace {

// Fontconfig is not threadsafe before 2.10.91.  Before that, we lock with a global mutex.
// See skia:1497 for background.
SK_DECLARE_STATIC_MUTEX(gFCMutex);
static bool gFCSafeToUse;

struct FCLocker {
    FCLocker() {
        if (FcGetVersion() < 21091) {  // We assume FcGetVersion() has always been thread safe.
            gFCMutex.acquire();
            fUnlock = true;
        } else {
            fUnlock = false;
        }
        gFCSafeToUse = true;
    }

    ~FCLocker() {
        gFCSafeToUse = false;
        if (fUnlock) {
            gFCMutex.release();
        }
    }

private:
    bool fUnlock;
};

} // namespace

// Defined in SkFontHost_FreeType.cpp
bool find_name_and_attributes(SkStream* stream, SkString* name,
                              SkTypeface::Style* style, bool* isFixedWidth);

// borrow this global from SkFontHost_fontconfig. eventually that file should
// go away, and be replaced with this one.
extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global();
static SkFontConfigInterface* RefFCI() {
    return SkFontHost_fontconfig_ref_global();
}

// look for the last substring after a '/' and return that, or return null.
static const char* find_just_name(const char* str) {
    const char* last = strrchr(str, '/');
    return last ? last + 1 : NULL;
}

static bool is_lower(char c) {
    return c >= 'a' && c <= 'z';
}

static int get_int(FcPattern* pattern, const char field[]) {
    SkASSERT(gFCSafeToUse);
    int value;
    if (FcPatternGetInteger(pattern, field, 0, &value) != FcResultMatch) {
        value = SK_MinS32;
    }
    return value;
}

static const char* get_name(FcPattern* pattern, const char field[]) {
    SkASSERT(gFCSafeToUse);
    const char* name;
    if (FcPatternGetString(pattern, field, 0, (FcChar8**)&name) != FcResultMatch) {
        name = "";
    }
    return name;
}

static bool valid_pattern(FcPattern* pattern) {
    SkASSERT(gFCSafeToUse);
    FcBool is_scalable;
    if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch || !is_scalable) {
        return false;
    }

    // fontconfig can also return fonts which are unreadable
    const char* c_filename = get_name(pattern, FC_FILE);
    if (0 == *c_filename) {
        return false;
    }
    if (access(c_filename, R_OK) != 0) {
        return false;
    }
    return true;
}

static bool match_name(FcPattern* pattern, const char family_name[]) {
    return !strcasecmp(family_name, get_name(pattern, FC_FAMILY));
}

static FcPattern** MatchFont(FcFontSet* font_set,
                             const char post_config_family[],
                             int* count) {
  // Older versions of fontconfig have a bug where they cannot select
  // only scalable fonts so we have to manually filter the results.

    FcPattern** iter = font_set->fonts;
    FcPattern** stop = iter + font_set->nfont;
    // find the first good match
    for (; iter < stop; ++iter) {
        if (valid_pattern(*iter)) {
            break;
        }
    }

    if (iter == stop || !match_name(*iter, post_config_family)) {
        return NULL;
    }

    FcPattern** firstIter = iter++;
    for (; iter < stop; ++iter) {
        if (!valid_pattern(*iter) || !match_name(*iter, post_config_family)) {
            break;
        }
    }

    *count = iter - firstIter;
    return firstIter;
}

class SkFontStyleSet_FC : public SkFontStyleSet {
public:
    SkFontStyleSet_FC(FcPattern** matches, int count);
    virtual ~SkFontStyleSet_FC();

    virtual int count() SK_OVERRIDE { return fRecCount; }
    virtual void getStyle(int index, SkFontStyle*, SkString* style) SK_OVERRIDE;
    virtual SkTypeface* createTypeface(int index) SK_OVERRIDE;
    virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE;

private:
    struct Rec {
        SkString    fStyleName;
        SkString    fFileName;
        SkFontStyle fStyle;
    };
    Rec* fRecs;
    int  fRecCount;
};

static int map_range(int value,
                     int old_min, int old_max, int new_min, int new_max) {
    SkASSERT(old_min < old_max);
    SkASSERT(new_min < new_max);
    return new_min + SkMulDiv(value - old_min,
                              new_max - new_min, old_max - old_min);
}

static SkFontStyle make_fontconfig_style(FcPattern* match) {
    int weight = get_int(match, FC_WEIGHT);
    int width = get_int(match, FC_WIDTH);
    int slant = get_int(match, FC_SLANT);
//    SkDebugf("old weight %d new weight %d\n", weight, map_range(weight, 0, 80, 0, 400));

    // fontconfig weight seems to be 0..200 or so, so we remap it here
    weight = map_range(weight, 0, 80, 0, 400);
    width = map_range(width, 0, 200, 0, 9);
    return SkFontStyle(weight, width, slant > 0 ? SkFontStyle::kItalic_Slant
                                                : SkFontStyle::kUpright_Slant);
}

SkFontStyleSet_FC::SkFontStyleSet_FC(FcPattern** matches, int count) {
    fRecCount = count;
    fRecs = SkNEW_ARRAY(Rec, count);
    for (int i = 0; i < count; ++i) {
        fRecs[i].fStyleName.set(get_name(matches[i], FC_STYLE));
        fRecs[i].fFileName.set(get_name(matches[i], FC_FILE));
        fRecs[i].fStyle = make_fontconfig_style(matches[i]);
    }
}

SkFontStyleSet_FC::~SkFontStyleSet_FC() {
    SkDELETE_ARRAY(fRecs);
}

void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style,
                                 SkString* styleName) {
    SkASSERT((unsigned)index < (unsigned)fRecCount);
    if (style) {
        *style = fRecs[index].fStyle;
    }
    if (styleName) {
        *styleName = fRecs[index].fStyleName;
    }
}

SkTypeface* SkFontStyleSet_FC::createTypeface(int index) {
    return NULL;
}

SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) {
    return NULL;
}

class SkFontMgr_fontconfig : public SkFontMgr {
    SkAutoTUnref<SkFontConfigInterface> fFCI;
    SkDataTable* fFamilyNames;

public:
    SkFontMgr_fontconfig(SkFontConfigInterface* fci)
        : fFCI(fci)
        , fFamilyNames(fFCI->getFamilyNames()) {}

    virtual ~SkFontMgr_fontconfig() {
        SkSafeUnref(fFamilyNames);
    }

protected:
    virtual int onCountFamilies() const SK_OVERRIDE {
        return fFamilyNames->count();
    }

    virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
        familyName->set(fFamilyNames->atStr(index));
    }

    virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
        return this->onMatchFamily(fFamilyNames->atStr(index));
    }

    virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
        FCLocker lock;

        FcPattern* pattern = FcPatternCreate();

        FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
#if 0
        FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
#endif
        FcConfigSubstitute(NULL, pattern, FcMatchPattern);
        FcDefaultSubstitute(pattern);

        const char* post_config_family = get_name(pattern, FC_FAMILY);

        FcResult result;
        FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
        if (!font_set) {
            FcPatternDestroy(pattern);
            return NULL;
        }

        int count;
        FcPattern** match = MatchFont(font_set, post_config_family, &count);
        if (!match) {
            FcPatternDestroy(pattern);
            FcFontSetDestroy(font_set);
            return NULL;
        }

        FcPatternDestroy(pattern);

        SkTDArray<FcPattern*> trimmedMatches;
        for (int i = 0; i < count; ++i) {
            const char* justName = find_just_name(get_name(match[i], FC_FILE));
            if (!is_lower(*justName)) {
                *trimmedMatches.append() = match[i];
            }
        }

        SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC,
                                             (trimmedMatches.begin(),
                                              trimmedMatches.count()));
        return sset;
    }

    virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
                                           const SkFontStyle&) const SK_OVERRIDE { return NULL; }
    virtual SkTypeface* onMatchFaceStyle(const SkTypeface*,
                                         const SkFontStyle&) const SK_OVERRIDE { return NULL; }

    virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) const SK_OVERRIDE { return NULL; }

    virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
        const size_t length = stream->getLength();
        if (!length) {
            return NULL;
        }
        if (length >= 1024 * 1024 * 1024) {
            return NULL;  // don't accept too large fonts (>= 1GB) for safety.
        }

        // TODO should the caller give us the style or should we get it from freetype?
        SkTypeface::Style style = SkTypeface::kNormal;
        bool isFixedWidth = false;
        if (!find_name_and_attributes(stream, NULL, &style, &isFixedWidth)) {
            return NULL;
        }

        SkTypeface* face = FontConfigTypeface::Create(style, isFixedWidth, stream);
        return face;
    }

    virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
        SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
        return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL;
    }

    virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
                                               unsigned styleBits) const SK_OVERRIDE {
        FCLocker lock;
        return FontConfigTypeface::LegacyCreateTypeface(NULL, familyName,
                                                  (SkTypeface::Style)styleBits);
    }
};

SkFontMgr* SkFontMgr::Factory() {
    SkFontConfigInterface* fci = RefFCI();
    return fci ? SkNEW_ARGS(SkFontMgr_fontconfig, (fci)) : NULL;
}
<commit_msg>Don't unset gFCSafeToUse when it's still safe to use.<commit_after>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkFontMgr.h"
#include "SkFontStyle.h"
#include "SkFontConfigInterface.h"
#include "SkFontConfigTypeface.h"
#include "SkMath.h"
#include "SkString.h"
#include "SkTDArray.h"
#include "SkThread.h"

// for now we pull these in directly. eventually we will solely rely on the
// SkFontConfigInterface instance.
#include <fontconfig/fontconfig.h>
#include <unistd.h>

namespace {

// Fontconfig is not threadsafe before 2.10.91.  Before that, we lock with a global mutex.
// See skia:1497 for background.
SK_DECLARE_STATIC_MUTEX(gFCMutex);
static bool gFCSafeToUse;

struct FCLocker {
    FCLocker() {
        if (FcGetVersion() < 21091) {  // We assume FcGetVersion() has always been thread safe.
            gFCMutex.acquire();
            fUnlock = true;
        } else {
            fUnlock = false;
        }
        gFCSafeToUse = true;
    }

    ~FCLocker() {
        if (fUnlock) {
            gFCSafeToUse = false;
            gFCMutex.release();
        }
    }

private:
    bool fUnlock;
};

} // namespace

// Defined in SkFontHost_FreeType.cpp
bool find_name_and_attributes(SkStream* stream, SkString* name,
                              SkTypeface::Style* style, bool* isFixedWidth);

// borrow this global from SkFontHost_fontconfig. eventually that file should
// go away, and be replaced with this one.
extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global();
static SkFontConfigInterface* RefFCI() {
    return SkFontHost_fontconfig_ref_global();
}

// look for the last substring after a '/' and return that, or return null.
static const char* find_just_name(const char* str) {
    const char* last = strrchr(str, '/');
    return last ? last + 1 : NULL;
}

static bool is_lower(char c) {
    return c >= 'a' && c <= 'z';
}

static int get_int(FcPattern* pattern, const char field[]) {
    SkASSERT(gFCSafeToUse);
    int value;
    if (FcPatternGetInteger(pattern, field, 0, &value) != FcResultMatch) {
        value = SK_MinS32;
    }
    return value;
}

static const char* get_name(FcPattern* pattern, const char field[]) {
    SkASSERT(gFCSafeToUse);
    const char* name;
    if (FcPatternGetString(pattern, field, 0, (FcChar8**)&name) != FcResultMatch) {
        name = "";
    }
    return name;
}

static bool valid_pattern(FcPattern* pattern) {
    SkASSERT(gFCSafeToUse);
    FcBool is_scalable;
    if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch || !is_scalable) {
        return false;
    }

    // fontconfig can also return fonts which are unreadable
    const char* c_filename = get_name(pattern, FC_FILE);
    if (0 == *c_filename) {
        return false;
    }
    if (access(c_filename, R_OK) != 0) {
        return false;
    }
    return true;
}

static bool match_name(FcPattern* pattern, const char family_name[]) {
    return !strcasecmp(family_name, get_name(pattern, FC_FAMILY));
}

static FcPattern** MatchFont(FcFontSet* font_set,
                             const char post_config_family[],
                             int* count) {
  // Older versions of fontconfig have a bug where they cannot select
  // only scalable fonts so we have to manually filter the results.

    FcPattern** iter = font_set->fonts;
    FcPattern** stop = iter + font_set->nfont;
    // find the first good match
    for (; iter < stop; ++iter) {
        if (valid_pattern(*iter)) {
            break;
        }
    }

    if (iter == stop || !match_name(*iter, post_config_family)) {
        return NULL;
    }

    FcPattern** firstIter = iter++;
    for (; iter < stop; ++iter) {
        if (!valid_pattern(*iter) || !match_name(*iter, post_config_family)) {
            break;
        }
    }

    *count = iter - firstIter;
    return firstIter;
}

class SkFontStyleSet_FC : public SkFontStyleSet {
public:
    SkFontStyleSet_FC(FcPattern** matches, int count);
    virtual ~SkFontStyleSet_FC();

    virtual int count() SK_OVERRIDE { return fRecCount; }
    virtual void getStyle(int index, SkFontStyle*, SkString* style) SK_OVERRIDE;
    virtual SkTypeface* createTypeface(int index) SK_OVERRIDE;
    virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE;

private:
    struct Rec {
        SkString    fStyleName;
        SkString    fFileName;
        SkFontStyle fStyle;
    };
    Rec* fRecs;
    int  fRecCount;
};

static int map_range(int value,
                     int old_min, int old_max, int new_min, int new_max) {
    SkASSERT(old_min < old_max);
    SkASSERT(new_min < new_max);
    return new_min + SkMulDiv(value - old_min,
                              new_max - new_min, old_max - old_min);
}

static SkFontStyle make_fontconfig_style(FcPattern* match) {
    int weight = get_int(match, FC_WEIGHT);
    int width = get_int(match, FC_WIDTH);
    int slant = get_int(match, FC_SLANT);
//    SkDebugf("old weight %d new weight %d\n", weight, map_range(weight, 0, 80, 0, 400));

    // fontconfig weight seems to be 0..200 or so, so we remap it here
    weight = map_range(weight, 0, 80, 0, 400);
    width = map_range(width, 0, 200, 0, 9);
    return SkFontStyle(weight, width, slant > 0 ? SkFontStyle::kItalic_Slant
                                                : SkFontStyle::kUpright_Slant);
}

SkFontStyleSet_FC::SkFontStyleSet_FC(FcPattern** matches, int count) {
    fRecCount = count;
    fRecs = SkNEW_ARRAY(Rec, count);
    for (int i = 0; i < count; ++i) {
        fRecs[i].fStyleName.set(get_name(matches[i], FC_STYLE));
        fRecs[i].fFileName.set(get_name(matches[i], FC_FILE));
        fRecs[i].fStyle = make_fontconfig_style(matches[i]);
    }
}

SkFontStyleSet_FC::~SkFontStyleSet_FC() {
    SkDELETE_ARRAY(fRecs);
}

void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style,
                                 SkString* styleName) {
    SkASSERT((unsigned)index < (unsigned)fRecCount);
    if (style) {
        *style = fRecs[index].fStyle;
    }
    if (styleName) {
        *styleName = fRecs[index].fStyleName;
    }
}

SkTypeface* SkFontStyleSet_FC::createTypeface(int index) {
    return NULL;
}

SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) {
    return NULL;
}

class SkFontMgr_fontconfig : public SkFontMgr {
    SkAutoTUnref<SkFontConfigInterface> fFCI;
    SkDataTable* fFamilyNames;

public:
    SkFontMgr_fontconfig(SkFontConfigInterface* fci)
        : fFCI(fci)
        , fFamilyNames(fFCI->getFamilyNames()) {}

    virtual ~SkFontMgr_fontconfig() {
        SkSafeUnref(fFamilyNames);
    }

protected:
    virtual int onCountFamilies() const SK_OVERRIDE {
        return fFamilyNames->count();
    }

    virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
        familyName->set(fFamilyNames->atStr(index));
    }

    virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
        return this->onMatchFamily(fFamilyNames->atStr(index));
    }

    virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
        FCLocker lock;

        FcPattern* pattern = FcPatternCreate();

        FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
#if 0
        FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
#endif
        FcConfigSubstitute(NULL, pattern, FcMatchPattern);
        FcDefaultSubstitute(pattern);

        const char* post_config_family = get_name(pattern, FC_FAMILY);

        FcResult result;
        FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
        if (!font_set) {
            FcPatternDestroy(pattern);
            return NULL;
        }

        int count;
        FcPattern** match = MatchFont(font_set, post_config_family, &count);
        if (!match) {
            FcPatternDestroy(pattern);
            FcFontSetDestroy(font_set);
            return NULL;
        }

        FcPatternDestroy(pattern);

        SkTDArray<FcPattern*> trimmedMatches;
        for (int i = 0; i < count; ++i) {
            const char* justName = find_just_name(get_name(match[i], FC_FILE));
            if (!is_lower(*justName)) {
                *trimmedMatches.append() = match[i];
            }
        }

        SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC,
                                             (trimmedMatches.begin(),
                                              trimmedMatches.count()));
        return sset;
    }

    virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
                                           const SkFontStyle&) const SK_OVERRIDE { return NULL; }
    virtual SkTypeface* onMatchFaceStyle(const SkTypeface*,
                                         const SkFontStyle&) const SK_OVERRIDE { return NULL; }

    virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) const SK_OVERRIDE { return NULL; }

    virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
        const size_t length = stream->getLength();
        if (!length) {
            return NULL;
        }
        if (length >= 1024 * 1024 * 1024) {
            return NULL;  // don't accept too large fonts (>= 1GB) for safety.
        }

        // TODO should the caller give us the style or should we get it from freetype?
        SkTypeface::Style style = SkTypeface::kNormal;
        bool isFixedWidth = false;
        if (!find_name_and_attributes(stream, NULL, &style, &isFixedWidth)) {
            return NULL;
        }

        SkTypeface* face = FontConfigTypeface::Create(style, isFixedWidth, stream);
        return face;
    }

    virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
        SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
        return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL;
    }

    virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
                                               unsigned styleBits) const SK_OVERRIDE {
        FCLocker lock;
        return FontConfigTypeface::LegacyCreateTypeface(NULL, familyName,
                                                  (SkTypeface::Style)styleBits);
    }
};

SkFontMgr* SkFontMgr::Factory() {
    SkFontConfigInterface* fci = RefFCI();
    return fci ? SkNEW_ARGS(SkFontMgr_fontconfig, (fci)) : NULL;
}
<|endoftext|>


<commit_before>#include "idt.hpp"
#include <kernel/events.hpp>
#include <kernel/syscalls.hpp>
#include <kprint>
#include <info>
#define RING0_CODE_SEG   0x8

extern "C" {
  extern void unused_interrupt_handler();
  extern void modern_interrupt_handler();
  extern void spurious_intr();
  extern void cpu_enable_panicking();
}

#define IRQ_LINES  Events::NUM_EVENTS
#define INTR_LINES (IRQ_BASE + IRQ_LINES)

namespace x86
{
typedef void (*intr_handler_t)();
typedef void (*except_handler_t)();

struct x86_IDT
{
  IDTDescr entry[INTR_LINES] __attribute__((aligned(16)));

  intr_handler_t get_handler(uint8_t vec);
  void set_handler(uint8_t, intr_handler_t);
  void set_exception_handler(uint8_t, except_handler_t);

  void init();
};
static std::array<x86_IDT, SMP_MAX_CORES> idt;

void idt_initialize_for_cpu(int cpu) {
  idt.at(cpu).init();
}

// A union to be able to extract the lower and upper part of an address
union addr_union {
  uintptr_t whole;
  struct {
    uint16_t lo16;
    uint16_t hi16;
#ifdef ARCH_x86_64
    uint32_t top32;
#endif
  };
};

static void set_intr_entry(
    IDTDescr* idt_entry,
    intr_handler_t func,
    uint8_t  ist,
    uint16_t segment_sel,
    char attributes)
{
  addr_union addr;
  addr.whole           = (uintptr_t) func;
  idt_entry->offset_1  = addr.lo16;
  idt_entry->offset_2  = addr.hi16;
#ifdef ARCH_x86_64
  idt_entry->offset_3  = addr.top32;
#endif
  idt_entry->selector  = segment_sel;
  idt_entry->type_attr = attributes;
#ifdef ARCH_x86_64
  idt_entry->ist       = ist;
  idt_entry->zero2     = 0;
#else
  (void) ist;
  idt_entry->zero      = 0;
#endif
}

intr_handler_t x86_IDT::get_handler(uint8_t vec)
{
  addr_union addr;
  addr.lo16  = entry[vec].offset_1;
  addr.hi16  = entry[vec].offset_2;
#ifdef ARCH_x86_64
  addr.top32 = entry[vec].offset_3;
#endif

  return (intr_handler_t) addr.whole;
}

void x86_IDT::set_handler(uint8_t vec, intr_handler_t func) {
  set_intr_entry(&entry[vec], func, 1, RING0_CODE_SEG, 0x8e);
}
void x86_IDT::set_exception_handler(uint8_t vec, except_handler_t func) {
  set_intr_entry(&entry[vec], (intr_handler_t) func, 2, RING0_CODE_SEG, 0x8e);
}

extern "C" {
  void __cpu_except_0();
  void __cpu_except_1();
  void __cpu_except_2();
  void __cpu_except_3();
  void __cpu_except_4();
  void __cpu_except_5();
  void __cpu_except_6();
  void __cpu_except_7();
  void __cpu_except_8();
  void __cpu_except_9();
  void __cpu_except_10();
  void __cpu_except_11();
  void __cpu_except_12();
  void __cpu_except_13();
  void __cpu_except_14();
  void __cpu_except_15();
  void __cpu_except_16();
  void __cpu_except_17();
  void __cpu_except_18();
  void __cpu_except_19();
  void __cpu_except_20();
  void __cpu_except_30();
}

void x86_IDT::init()
{
  // make sure its all zeroes
  memset(&this->entry[0], 0, sizeof(x86_IDT::entry));

  set_exception_handler(0, __cpu_except_0);
  set_exception_handler(1, __cpu_except_1);
  set_exception_handler(2, __cpu_except_2);
  set_exception_handler(3, __cpu_except_3);
  set_exception_handler(4, __cpu_except_4);
  set_exception_handler(5, __cpu_except_5);
  set_exception_handler(6, __cpu_except_6);
  set_exception_handler(7, __cpu_except_7);
  set_exception_handler(8, __cpu_except_8);
  set_exception_handler(9, __cpu_except_9);
  set_exception_handler(10, __cpu_except_10);
  set_exception_handler(11, __cpu_except_11);
  set_exception_handler(12, __cpu_except_12);
  set_exception_handler(13, __cpu_except_13);
  set_exception_handler(14, __cpu_except_14);
  set_exception_handler(15, __cpu_except_15);
  set_exception_handler(16, __cpu_except_16);
  set_exception_handler(17, __cpu_except_17);
  set_exception_handler(18, __cpu_except_18);
  set_exception_handler(19, __cpu_except_19);
  set_exception_handler(20, __cpu_except_20);
  set_exception_handler(30, __cpu_except_30);

  for (size_t i = 32; i < INTR_LINES - 2; i++) {
    set_handler(i, unused_interrupt_handler);
  }
  // spurious interrupt handler
  set_handler(INTR_LINES - 1, spurious_intr);

  // Load IDT
  IDTR idt_reg;
  idt_reg.limit = INTR_LINES * sizeof(IDTDescr) - 1;
  idt_reg.base = (uintptr_t) &entry[0];
  asm volatile ("lidt %0" : : "m"(idt_reg));
}

} // x86

void __arch_subscribe_irq(uint8_t irq)
{
  assert(irq < IRQ_LINES);
  PER_CPU(x86::idt).set_handler(IRQ_BASE + irq, modern_interrupt_handler);
}
void __arch_install_irq(uint8_t irq, x86::intr_handler_t handler)
{
  assert(irq < IRQ_LINES);
  PER_CPU(x86::idt).set_handler(IRQ_BASE + irq, handler);
}
void __arch_unsubscribe_irq(uint8_t irq)
{
  assert(irq < IRQ_LINES);
  PER_CPU(x86::idt).set_handler(IRQ_BASE + irq, unused_interrupt_handler);
}

/// CPU EXCEPTIONS ///

#define PAGE_FAULT 14

static const char* exception_names[] =
{
  "Divide-by-zero Error",
  "Debug",
  "Non-maskable Interrupt",
  "Breakpoint",
  "Overflow",
  "Bound Range Exceeded",
  "Invalid Opcode",
  "Device Not Available",
  "Double Fault",
  "Reserved",
  "Invalid TSS",
  "Segment Not Present",
  "Stack-Segment Fault",
  "General Protection Fault",
  "Page Fault",
  "Reserved",
  "x87 Floating-point Exception",
  "Alignment Check",
  "Machine Check",
  "SIMD Floating-point Exception",
  "Virtualization Exception",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Security Exception",
  "Reserved"
};

void __cpu_dump_regs(uintptr_t* regs)
{
#if defined(ARCH_x86_64)
# define RIP_REG 16
  // AMD64 CPU registers
  struct desc_table_t {
    uint16_t  limit;
    uintptr_t location;
  } __attribute__((packed))  gdt, idt;
  asm ("sgdtq %0" : : "m" (* &gdt));
  asm ("sidtq %0" : : "m" (* &idt));

  fprintf(stderr, "\n");
  printf("  RAX:  %016lx  R 8:  %016lx\n", regs[0], regs[5]);
  printf("  RBX:  %016lx  R 9:  %016lx\n", regs[1], regs[6]);
  printf("  RCX:  %016lx  R10:  %016lx\n", regs[2], regs[7]);
  printf("  RDX:  %016lx  R11:  %016lx\n", regs[3], regs[8]);
  fprintf(stderr, "\n");

  printf("  RBP:  %016lx  R12:  %016lx\n", regs[4], regs[9]);
  printf("  RSP:  %016lx  R13:  %016lx\n", regs[13], regs[10]);
  printf("  RSI:  %016lx  R14:  %016lx\n", regs[14], regs[11]);
  printf("  RDI:  %016lx  R15:  %016lx\n", regs[15], regs[12]);
  printf("  RIP:  %016lx  FLA:  %016lx\n", regs[16], regs[17]);
  fprintf(stderr, "\n");

  printf("  CR0:  %016lx  CR4:  %016lx\n", regs[18], regs[22]);
  printf("  CR1:  %016lx  CR8:  %016lx\n", regs[19], regs[23]);
  printf("  CR2:  %016lx  GDT:  %016lx (%u)\n", regs[20], gdt.location, gdt.limit);
  printf("  CR3:  %016lx  IDT:  %016lx (%u)\n", regs[21], idt.location, idt.limit);

#elif defined(ARCH_i686)
# define RIP_REG 8
  // i386 CPU registers
  fprintf(stderr, "\n");
  printf("  EAX:  %08x  EBP:  %08x\n", regs[0], regs[4]);
  printf("  EBX:  %08x  ESP:  %08x\n", regs[1], regs[5]);
  printf("  ECX:  %08x  ESI:  %08x\n", regs[2], regs[6]);
  printf("  EDX:  %08x  EDI:  %08x\n", regs[3], regs[7]);

  fprintf(stderr, "\n");
  printf("  EIP:  %08x  EFL:  %08x\n", regs[8], regs[9]);

#else
  #error "Unknown architecture"
#endif
  fprintf(stderr, "\n");
}

extern "C" void double_fault(const char*);

void __page_fault(uintptr_t* regs, uint32_t code) {
  const char* reason = "Protection violation";

  if (not(code & 1))
    reason = "Page not present";

  kprintf("%s, trying to access 0x%lx\n", reason, regs[20]);

  if (code & 2)
    kprintf("Page write failed.\n");
  else
    kprintf("Page read failed.\n");

  if (code & 4)
    kprintf("Privileged page access from user space.\n");

  if (code & 8)
    kprintf("Found bit set in reserved field.\n");

  if (code & 16)
    kprintf("Instruction fetch. XD\n");

  if (code & 32)
    kprintf("Protection key violation.\n");

  if (code & 0x8000)
    kprintf("SGX access violation.\n");
}

extern "C"
__attribute__((noreturn, weak))
void __cpu_exception(uintptr_t* regs, int error, uint32_t code)
{
  cpu_enable_panicking();
  SMP::global_lock();
  kprintf("\n>>>> !!! CPU %u EXCEPTION !!! <<<<\n", SMP::cpu_id());
  kprintf("%s (%d)   EIP  %p   CODE %#x\n",
          exception_names[error], error, (void*) regs[RIP_REG], code);

  if (error == PAGE_FAULT) {
    __page_fault(regs, code);
  }

  __cpu_dump_regs(regs);

  SMP::global_unlock();
  // error message:
  char buffer[64];
  snprintf(buffer, sizeof(buffer), "%s (%d)", exception_names[error], error);
  // normal CPU exception
  if (error != 0x8) {
    // call panic, which will decide what to do next
    panic(buffer);
  }
  else {
    // handle double faults differently
    double_fault(buffer);
  }

  __builtin_unreachable();
}
<commit_msg>kernel: prevent infinite loops of cpu-exceptions + use fprintf always<commit_after>#include "idt.hpp"
#include <kernel/events.hpp>
#include <kernel/syscalls.hpp>
#include <kprint>
#include <info>
#include <os>
#include <kernel/memory.hpp>
#define RING0_CODE_SEG   0x8

extern "C" {
  extern void unused_interrupt_handler();
  extern void modern_interrupt_handler();
  extern void spurious_intr();
  extern void cpu_enable_panicking();
}

#define IRQ_LINES  Events::NUM_EVENTS
#define INTR_LINES (IRQ_BASE + IRQ_LINES)

namespace x86
{
typedef void (*intr_handler_t)();
typedef void (*except_handler_t)();

struct x86_IDT
{
  IDTDescr entry[INTR_LINES] __attribute__((aligned(16)));

  intr_handler_t get_handler(uint8_t vec);
  void set_handler(uint8_t, intr_handler_t);
  void set_exception_handler(uint8_t, except_handler_t);

  void init();
};
static std::array<x86_IDT, SMP_MAX_CORES> idt;

void idt_initialize_for_cpu(int cpu) {
  idt.at(cpu).init();
}

// A union to be able to extract the lower and upper part of an address
union addr_union {
  uintptr_t whole;
  struct {
    uint16_t lo16;
    uint16_t hi16;
#ifdef ARCH_x86_64
    uint32_t top32;
#endif
  };
};

static void set_intr_entry(
    IDTDescr* idt_entry,
    intr_handler_t func,
    uint8_t  ist,
    uint16_t segment_sel,
    char attributes)
{
  addr_union addr;
  addr.whole           = (uintptr_t) func;
  idt_entry->offset_1  = addr.lo16;
  idt_entry->offset_2  = addr.hi16;
#ifdef ARCH_x86_64
  idt_entry->offset_3  = addr.top32;
#endif
  idt_entry->selector  = segment_sel;
  idt_entry->type_attr = attributes;
#ifdef ARCH_x86_64
  idt_entry->ist       = ist;
  idt_entry->zero2     = 0;
#else
  (void) ist;
  idt_entry->zero      = 0;
#endif
}

intr_handler_t x86_IDT::get_handler(uint8_t vec)
{
  addr_union addr;
  addr.lo16  = entry[vec].offset_1;
  addr.hi16  = entry[vec].offset_2;
#ifdef ARCH_x86_64
  addr.top32 = entry[vec].offset_3;
#endif

  return (intr_handler_t) addr.whole;
}

void x86_IDT::set_handler(uint8_t vec, intr_handler_t func) {
  set_intr_entry(&entry[vec], func, 1, RING0_CODE_SEG, 0x8e);
}
void x86_IDT::set_exception_handler(uint8_t vec, except_handler_t func) {
  set_intr_entry(&entry[vec], (intr_handler_t) func, 2, RING0_CODE_SEG, 0x8e);
}

extern "C" {
  void __cpu_except_0();
  void __cpu_except_1();
  void __cpu_except_2();
  void __cpu_except_3();
  void __cpu_except_4();
  void __cpu_except_5();
  void __cpu_except_6();
  void __cpu_except_7();
  void __cpu_except_8();
  void __cpu_except_9();
  void __cpu_except_10();
  void __cpu_except_11();
  void __cpu_except_12();
  void __cpu_except_13();
  void __cpu_except_14();
  void __cpu_except_15();
  void __cpu_except_16();
  void __cpu_except_17();
  void __cpu_except_18();
  void __cpu_except_19();
  void __cpu_except_20();
  void __cpu_except_30();
}

void x86_IDT::init()
{
  // make sure its all zeroes
  memset(&this->entry[0], 0, sizeof(x86_IDT::entry));

  set_exception_handler(0, __cpu_except_0);
  set_exception_handler(1, __cpu_except_1);
  set_exception_handler(2, __cpu_except_2);
  set_exception_handler(3, __cpu_except_3);
  set_exception_handler(4, __cpu_except_4);
  set_exception_handler(5, __cpu_except_5);
  set_exception_handler(6, __cpu_except_6);
  set_exception_handler(7, __cpu_except_7);
  set_exception_handler(8, __cpu_except_8);
  set_exception_handler(9, __cpu_except_9);
  set_exception_handler(10, __cpu_except_10);
  set_exception_handler(11, __cpu_except_11);
  set_exception_handler(12, __cpu_except_12);
  set_exception_handler(13, __cpu_except_13);
  set_exception_handler(14, __cpu_except_14);
  set_exception_handler(15, __cpu_except_15);
  set_exception_handler(16, __cpu_except_16);
  set_exception_handler(17, __cpu_except_17);
  set_exception_handler(18, __cpu_except_18);
  set_exception_handler(19, __cpu_except_19);
  set_exception_handler(20, __cpu_except_20);
  set_exception_handler(30, __cpu_except_30);

  for (size_t i = 32; i < INTR_LINES - 2; i++) {
    set_handler(i, unused_interrupt_handler);
  }
  // spurious interrupt handler
  set_handler(INTR_LINES - 1, spurious_intr);

  // Load IDT
  IDTR idt_reg;
  idt_reg.limit = INTR_LINES * sizeof(IDTDescr) - 1;
  idt_reg.base = (uintptr_t) &entry[0];
  asm volatile ("lidt %0" : : "m"(idt_reg));
}

} // x86

void __arch_subscribe_irq(uint8_t irq)
{
  assert(irq < IRQ_LINES);
  PER_CPU(x86::idt).set_handler(IRQ_BASE + irq, modern_interrupt_handler);
}
void __arch_install_irq(uint8_t irq, x86::intr_handler_t handler)
{
  assert(irq < IRQ_LINES);
  PER_CPU(x86::idt).set_handler(IRQ_BASE + irq, handler);
}
void __arch_unsubscribe_irq(uint8_t irq)
{
  assert(irq < IRQ_LINES);
  PER_CPU(x86::idt).set_handler(IRQ_BASE + irq, unused_interrupt_handler);
}

/// CPU EXCEPTIONS ///

#define PAGE_FAULT 14

static const char* exception_names[] =
{
  "Divide-by-zero Error",
  "Debug",
  "Non-maskable Interrupt",
  "Breakpoint",
  "Overflow",
  "Bound Range Exceeded",
  "Invalid Opcode",
  "Device Not Available",
  "Double Fault",
  "Reserved",
  "Invalid TSS",
  "Segment Not Present",
  "Stack-Segment Fault",
  "General Protection Fault",
  "Page Fault",
  "Reserved",
  "x87 Floating-point Exception",
  "Alignment Check",
  "Machine Check",
  "SIMD Floating-point Exception",
  "Virtualization Exception",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Reserved",
  "Security Exception",
  "Reserved"
};

void __cpu_dump_regs(uintptr_t* regs)
{
#if defined(ARCH_x86_64)
# define RIP_REG 16
  // AMD64 CPU registers
  struct desc_table_t {
    uint16_t  limit;
    uintptr_t location;
  } __attribute__((packed))  gdt, idt;
  asm ("sgdtq %0" : : "m" (* &gdt));
  asm ("sidtq %0" : : "m" (* &idt));

  fprintf(stderr, "\n");
  fprintf(stderr,"  RAX:  %016lx  R 8:  %016lx\n", regs[0], regs[5]);
  fprintf(stderr,"  RBX:  %016lx  R 9:  %016lx\n", regs[1], regs[6]);
  fprintf(stderr,"  RCX:  %016lx  R10:  %016lx\n", regs[2], regs[7]);
  fprintf(stderr,"  RDX:  %016lx  R11:  %016lx\n", regs[3], regs[8]);
  fprintf(stderr, "\n");

  fprintf(stderr,"  RBP:  %016lx  R12:  %016lx\n", regs[4], regs[9]);
  fprintf(stderr,"  RSP:  %016lx  R13:  %016lx\n", regs[13], regs[10]);
  fprintf(stderr,"  RSI:  %016lx  R14:  %016lx\n", regs[14], regs[11]);
  fprintf(stderr,"  RDI:  %016lx  R15:  %016lx\n", regs[15], regs[12]);
  fprintf(stderr,"  RIP:  %016lx  FLA:  %016lx\n", regs[16], regs[17]);
  fprintf(stderr, "\n");

  fprintf(stderr,"  CR0:  %016lx  CR4:  %016lx\n", regs[18], regs[22]);
  fprintf(stderr,"  CR1:  %016lx  CR8:  %016lx\n", regs[19], regs[23]);
  fprintf(stderr,"  CR2:  %016lx  GDT:  %016lx (%u)\n", regs[20], gdt.location, gdt.limit);
  fprintf(stderr,"  CR3:  %016lx  IDT:  %016lx (%u)\n", regs[21], idt.location, idt.limit);

#elif defined(ARCH_i686)
# define RIP_REG 8
  // i386 CPU registers
  fprintf(stderr, "\n");
  fprintf(stderr,"  EAX:  %08x  EBP:  %08x\n", regs[0], regs[4]);
  fprintf(stderr,"  EBX:  %08x  ESP:  %08x\n", regs[1], regs[5]);
  fprintf(stderr,"  ECX:  %08x  ESI:  %08x\n", regs[2], regs[6]);
  fprintf(stderr,"  EDX:  %08x  EDI:  %08x\n", regs[3], regs[7]);

  fprintf(stderr, "\n");
  fprintf(stderr,"  EIP:  %08x  EFL:  %08x\n", regs[8], regs[9]);

#else
  #error "Unknown architecture"
#endif
  fprintf(stderr, "\n");
}

extern "C" void double_fault(const char*);

void __page_fault(uintptr_t* regs, uint32_t code) {
  const char* reason = "Protection violation";
  auto addr = regs[20];

  if (not(code & 1))
    reason = "Page not present";

  fprintf(stderr,"%s, trying to access 0x%lx\n", reason, addr);

  if (code & 2)
    fprintf(stderr,"Page write failed.\n");
  else
    fprintf(stderr,"Page read failed.\n");

  if (code & 4)
    fprintf(stderr,"Privileged page access from user space.\n");

  if (code & 8)
    fprintf(stderr,"Found bit set in reserved field.\n");

  if (code & 16)
    fprintf(stderr,"Instruction fetch. XD\n");

  if (code & 32)
    fprintf(stderr,"Protection key violation.\n");

  if (code & 0x8000)
    fprintf(stderr,"SGX access violation.\n");

  auto key = OS::memory_map().in_range(addr);
  if (key) {
    auto& range = OS::memory_map().at(key);
    printf("Violated address is in mapped range \"%s\" \n", range.name());
  } else {
    printf("Violated ddress is outside mapped memory\n");
  }

}

static int exception_counter = 0;

extern "C"
__attribute__((noreturn, weak))
void __cpu_exception(uintptr_t* regs, int error, uint32_t code)
{
  __sync_fetch_and_add(&exception_counter, 1);
  if (exception_counter > 1) {
    panic("Double CPU exception");
  }

  SMP::global_lock();
  fprintf(stderr,"\n>>>> !!! CPU %u EXCEPTION !!! <<<<\n", SMP::cpu_id());
  fprintf(stderr,"%s (%d)   EIP  %p   CODE %#x\n",
          exception_names[error], error, (void*) regs[RIP_REG], code);

  if (error == PAGE_FAULT) {
    __page_fault(regs, code);
  }

  __cpu_dump_regs(regs);

  SMP::global_unlock();
  // error message:
  char buffer[64];
  snprintf(buffer, sizeof(buffer), "%s (%d)", exception_names[error], error);

  // normal CPU exception
  if (error != 0x8) {
    // call panic, which will decide what to do next
    panic(buffer);
  }
  else {
    // handle double faults differently
    double_fault(buffer);
  }

  __builtin_unreachable();
}
<|endoftext|>