diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 1220224..5b62c5c 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1408,6 +1408,8 @@ long arch_do_domctl(
     case XEN_DOMCTL_psr_cat_op:
         switch ( domctl->u.psr_cat_op.cmd )
         {
+            uint32_t val32;
+
         case XEN_DOMCTL_PSR_CAT_OP_SET_L3_CBM:
             ret = psr_set_l3_cbm(d, domctl->u.psr_cat_op.target,
                                  domctl->u.psr_cat_op.data,
@@ -1427,23 +1429,23 @@ long arch_do_domctl(
             break;
 
         case XEN_DOMCTL_PSR_CAT_OP_GET_L3_CBM:
-            ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target,
-                                 &domctl->u.psr_cat_op.data,
-                                 PSR_CBM_TYPE_L3);
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              &val32, PSR_CBM_TYPE_L3);
+            domctl->u.psr_cat_op.data = val32;
             copyback = 1;
             break;
 
         case XEN_DOMCTL_PSR_CAT_OP_GET_L3_CODE:
-            ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target,
-                                 &domctl->u.psr_cat_op.data,
-                                 PSR_CBM_TYPE_L3_CODE);
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              &val32, PSR_CBM_TYPE_L3_CODE);
+            domctl->u.psr_cat_op.data = val32;
             copyback = 1;
             break;
 
         case XEN_DOMCTL_PSR_CAT_OP_GET_L3_DATA:
-            ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target,
-                                 &domctl->u.psr_cat_op.data,
-                                 PSR_CBM_TYPE_L3_DATA);
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              &val32, PSR_CBM_TYPE_L3_DATA);
+            domctl->u.psr_cat_op.data = val32;
             copyback = 1;
             break;
 
diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
index 2e6595d..1b781e1 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -476,23 +476,34 @@ static struct psr_socket_info *get_socket_info(unsigned int socket)
     return socket_info + socket;
 }
 
+static struct feat_node *psr_get_feat_and_type(unsigned int socket,
+                                               enum cbm_type type,
+                                               enum psr_feat_type *feat_type)
+{
+    const struct psr_socket_info *info = get_socket_info(socket);
+
+    if ( IS_ERR(info) )
+        return ERR_PTR(PTR_ERR(info));
+
+    *feat_type = psr_cbm_type_to_feat_type(type);
+    if ( *feat_type >= ARRAY_SIZE(info->features) )
+        return NULL;
+
+    return info->features[*feat_type];
+}
+
 int psr_get_info(unsigned int socket, enum cbm_type type,
                  uint32_t data[], unsigned int array_len)
 {
-    const struct psr_socket_info *info = get_socket_info(socket);
     const struct feat_node *feat;
     enum psr_feat_type feat_type;
 
     ASSERT(data);
 
-    if ( IS_ERR(info) )
-        return PTR_ERR(info);
-
-    feat_type = psr_cbm_type_to_feat_type(type);
-    if ( feat_type >= ARRAY_SIZE(info->features) )
-        return -ENOENT;
+    feat = psr_get_feat_and_type(socket, type, &feat_type);
+    if ( IS_ERR(feat) )
+        return PTR_ERR(feat);
 
-    feat = info->features[feat_type];
     if ( !feat || !feat_props[feat_type] )
         return -ENOENT;
 
@@ -502,9 +513,38 @@ int psr_get_info(unsigned int socket, enum cbm_type type,
     return -EINVAL;
 }
 
-int psr_get_l3_cbm(struct domain *d, unsigned int socket,
-                   uint64_t *cbm, enum cbm_type type)
+int psr_get_val(struct domain *d, unsigned int socket,
+                uint32_t *val, enum cbm_type type)
 {
+    const struct feat_node *feat;
+    enum psr_feat_type feat_type;
+    unsigned int cos, i;
+
+    ASSERT(val);
+
+    feat = psr_get_feat_and_type(socket, type, &feat_type);
+    if ( IS_ERR(feat) )
+        return PTR_ERR(feat);
+
+    if ( !feat || !feat_props[feat_type] )
+        return -ENOENT;
+
+    cos = d->arch.psr_cos_ids[socket];
+    /*
+     * If input cos exceeds current feature's cos_max, we should return its
+     * default value which is stored in cos 0. This case only happens
+     * when more than two features enabled concurrently and at least one
+     * features's cos_max is bigger than others. When a domain's working cos
+     * id is bigger than some features' cos_max, HW automatically works as
+     * default value for those features which cos_max is smaller.
+     */
+    if ( cos > feat->cos_max )
+        cos = 0;
+
+    for ( i = 0; i < feat_props[feat_type]->cos_num; i++ )
+        if ( type == feat_props[feat_type]->type[i] )
+            *val = feat->cos_reg_val[cos * feat_props[feat_type]->cos_num + i];
+
     return 0;
 }
 
diff --git a/xen/include/asm-x86/psr.h b/xen/include/asm-x86/psr.h
index af3a465..7c6d38a 100644
--- a/xen/include/asm-x86/psr.h
+++ b/xen/include/asm-x86/psr.h
@@ -71,8 +71,8 @@ void psr_ctxt_switch_to(struct domain *d);
 
 int psr_get_info(unsigned int socket, enum cbm_type type,
                  uint32_t data[], unsigned int array_len);
-int psr_get_l3_cbm(struct domain *d, unsigned int socket,
-                   uint64_t *cbm, enum cbm_type type);
+int psr_get_val(struct domain *d, unsigned int socket,
+                uint32_t *val, enum cbm_type type);
 int psr_set_l3_cbm(struct domain *d, unsigned int socket,
                    uint64_t cbm, enum cbm_type type);
 
