diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 02b48e8..e714d1d 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1455,23 +1455,26 @@ 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);
+            domctl->u.psr_cat_op.data = 0;
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              (uint32_t *)&domctl->u.psr_cat_op.data,
+                              PSR_CBM_TYPE_L3);
             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);
+            domctl->u.psr_cat_op.data = 0;
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              (uint32_t *)&domctl->u.psr_cat_op.data,
+                              PSR_CBM_TYPE_L3_CODE);
             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);
+            domctl->u.psr_cat_op.data = 0;
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              (uint32_t *)&domctl->u.psr_cat_op.data,
+                              PSR_CBM_TYPE_L3_DATA);
             copyback = 1;
             break;
 
diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
index 83358e3..53105f5 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -97,6 +97,10 @@ struct feat_node {
         /* get_feat_info is used to get feature HW info. */
         bool (*get_feat_info)(const struct feat_node *feat,
                               uint32_t data[], unsigned int array_len);
+
+        /* get_val is used to get feature COS register value. */
+        void (*get_val)(const struct feat_node *feat, unsigned int cos,
+                        enum cbm_type type, uint32_t *val);
     } ops;
 
     /* Encapsulate feature specific HW info here. */
@@ -275,10 +279,17 @@ static bool cat_get_feat_info(const struct feat_node *feat,
     return true;
 }
 
+static void cat_get_val(const struct feat_node *feat, unsigned int cos,
+                        enum cbm_type type, uint32_t *val)
+{
+    *val = feat->cos_reg_val[cos];
+}
+
 /* L3 CAT ops */
 static const struct feat_ops l3_cat_ops = {
     .get_cos_max = cat_get_cos_max,
     .get_feat_info = cat_get_feat_info,
+    .get_val = cat_get_val,
 };
 
 static void __init parse_psr_bool(char *s, char *value, char *feature,
@@ -504,21 +515,30 @@ static struct psr_socket_info *get_socket_info(unsigned int socket)
     return socket_info + socket;
 }
 
-int psr_get_info(unsigned int socket, enum cbm_type type,
-                 uint32_t data[], unsigned int array_len)
+static const struct feat_node * psr_get_feat(unsigned int socket,
+                                             enum cbm_type type)
 {
     const struct psr_socket_info *info = get_socket_info(socket);
     const struct feat_node *feat;
     enum psr_feat_type feat_type;
 
     if ( IS_ERR(info) )
-        return PTR_ERR(info);
+        return NULL;
+
+    feat_type = psr_cbm_type_to_feat_type(type);
+    feat = info->features[feat_type];
+    return feat;
+}
+
+int psr_get_info(unsigned int socket, enum cbm_type type,
+                 uint32_t data[], unsigned int array_len)
+{
+    const struct feat_node *feat;
 
     if ( !data )
         return -EINVAL;
 
-    feat_type = psr_cbm_type_to_feat_type(type);
-    feat = info->features[feat_type];
+    feat = psr_get_feat(socket, type);
     if ( !feat )
         return -ENOENT;
 
@@ -528,9 +548,33 @@ 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;
+    unsigned int cos;
+
+    if ( !d || !val )
+        return -EINVAL;
+
+    feat = psr_get_feat(socket, type);
+    if ( !feat )
+        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->ops.get_cos_max(feat) )
+        cos = 0;
+
+    feat->ops.get_val(feat, cos, type, val);
+
     return 0;
 }
 
diff --git a/xen/include/asm-x86/psr.h b/xen/include/asm-x86/psr.h
index e27e685..cd00733 100644
--- a/xen/include/asm-x86/psr.h
+++ b/xen/include/asm-x86/psr.h
@@ -72,8 +72,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);
 
