4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
33 #include <topo_error.h>
34 #include <fm/topo_mod.h>
35 #include <sys/fm/protocol.h>
37 #include <topo_method.h>
41 * platform specific mem module
43 #define PLATFORM_MEM_VERSION MEM_VERSION
44 #define PLATFORM_MEM_NAME "platform-mem"
46 static int mem_enum(topo_mod_t
*, tnode_t
*, const char *, topo_instance_t
,
47 topo_instance_t
, void *, void *);
48 static void mem_release(topo_mod_t
*, tnode_t
*);
49 static int mem_nvl2str(topo_mod_t
*, tnode_t
*, topo_version_t
, nvlist_t
*,
51 static int mem_fmri_create(topo_mod_t
*, tnode_t
*, topo_version_t
,
52 nvlist_t
*, nvlist_t
**);
54 static const topo_method_t mem_methods
[] = {
55 { TOPO_METH_NVL2STR
, TOPO_METH_NVL2STR_DESC
, TOPO_METH_NVL2STR_VERSION
,
56 TOPO_STABILITY_INTERNAL
, mem_nvl2str
},
57 { TOPO_METH_FMRI
, TOPO_METH_FMRI_DESC
, TOPO_METH_FMRI_VERSION
,
58 TOPO_STABILITY_INTERNAL
, mem_fmri_create
},
62 static const topo_modops_t mem_ops
=
63 { mem_enum
, mem_release
};
64 static const topo_modinfo_t mem_info
=
65 { "mem", FM_FMRI_SCHEME_MEM
, MEM_VERSION
, &mem_ops
};
68 mem_init(topo_mod_t
*mod
, topo_version_t version
)
71 topo_mod_setdebug(mod
);
72 topo_mod_dprintf(mod
, "initializing mem builtin\n");
74 if (version
!= MEM_VERSION
)
75 return (topo_mod_seterrno(mod
, EMOD_VER_NEW
));
77 if (topo_mod_register(mod
, &mem_info
, TOPO_VERSION
) != 0) {
78 topo_mod_dprintf(mod
, "failed to register mem_info: "
79 "%s\n", topo_mod_errmsg(mod
));
80 return (-1); /* mod errno already set */
87 mem_fini(topo_mod_t
*mod
)
89 topo_mod_unregister(mod
);
94 mem_enum(topo_mod_t
*mod
, tnode_t
*pnode
, const char *name
,
95 topo_instance_t min
, topo_instance_t max
, void *notused1
, void *notused2
)
97 int isglobal
= (getzoneid() == GLOBAL_ZONEID
);
100 if (isglobal
&& (nmp
= topo_mod_load(mod
, PLATFORM_MEM_NAME
,
101 PLATFORM_MEM_VERSION
)) == NULL
) {
102 if (topo_mod_errno(mod
) == ETOPO_MOD_NOENT
) {
104 * There is no platform specific mem module.
106 (void) topo_method_register(mod
, pnode
, mem_methods
);
109 /* Fail to load the module */
110 topo_mod_dprintf(mod
, "Failed to load module %s: %s",
111 PLATFORM_MEM_NAME
, topo_mod_errmsg(mod
));
116 if (isglobal
&& topo_mod_enumerate(nmp
, pnode
, PLATFORM_MEM_NAME
, name
,
117 min
, max
, NULL
) < 0) {
118 topo_mod_dprintf(mod
, "%s failed to enumerate: %s",
119 PLATFORM_MEM_NAME
, topo_mod_errmsg(mod
));
122 (void) topo_method_register(mod
, pnode
, mem_methods
);
128 mem_release(topo_mod_t
*mod
, tnode_t
*node
)
130 topo_method_unregister_all(mod
, node
);
134 * Convert an input string to a URI escaped string and return the new string.
135 * RFC2396 Section 2.4 says that data must be escaped if it does not have a
136 * representation using an unreserved character, where an unreserved character
137 * is one that is either alphanumeric or one of the marks defined in S2.3.
140 mem_fmri_uriescape(const char *s
, const char *xmark
, char *buf
, size_t len
)
142 static const char rfc2396_mark
[] = "-_.!~*'()";
143 static const char hex_digits
[] = "0123456789ABCDEF";
144 static const char empty_str
[] = "";
156 for (p
= s
; (c
= *p
) != '\0'; p
++) {
157 if (isalnum(c
) || strchr(rfc2396_mark
, c
) || strchr(xmark
, c
))
158 n
++; /* represent c as itself */
160 n
+= 3; /* represent c as escape */
166 for (p
= s
, q
= buf
; (c
= *p
) != '\0' && q
< buf
+ len
; p
++) {
167 if (isalnum(c
) || strchr(rfc2396_mark
, c
) || strchr(xmark
, c
)) {
171 *q
++ = hex_digits
[((uchar_t
)c
& 0xf0) >> 4];
172 *q
++ = hex_digits
[(uchar_t
)c
& 0xf];
177 q
--; /* len is too small: truncate output string */
185 mem_nvl2str(topo_mod_t
*mod
, tnode_t
*node
, topo_version_t version
,
186 nvlist_t
*in
, nvlist_t
**out
)
194 char *preunum
, *escunum
, *prefix
;
198 if (topo_mod_nvalloc(mod
, &nvl
, NV_UNIQUE_NAME
) != 0)
199 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
201 if (nvlist_lookup_string(in
, FM_FMRI_MEM_UNUM
, &unum
) != 0) {
203 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
207 * If we have a DIMM offset, include it in the string. If we have a
208 * PA then use that. Otherwise just format the unum element.
210 if (nvlist_lookup_uint64(in
, FM_FMRI_MEM_OFFSET
, &val
) == 0) {
211 format
= FM_FMRI_SCHEME_MEM
":///%1$s%2$s/"
212 FM_FMRI_MEM_OFFSET
"=%3$llx";
213 } else if (nvlist_lookup_uint64(in
, FM_FMRI_MEM_PHYSADDR
, &val
) == 0) {
214 format
= FM_FMRI_SCHEME_MEM
":///%1$s%2$s/"
215 FM_FMRI_MEM_PHYSADDR
"=%3$llx";
217 format
= FM_FMRI_SCHEME_MEM
":///%1$s%2$s";
220 * If we have a well-formed unum we step over the hc:// and
223 if (strncmp(unum
, "hc://", 5) == 0) {
225 unum
= strchr(unum
, '/');
230 prefix
= FM_FMRI_MEM_UNUM
"=";
231 preunum
= topo_mod_strdup(mod
, unum
);
232 presz
= strlen(preunum
) + 1;
234 for (i
= 0; i
< presz
- 1; i
++) {
235 if (preunum
[i
] == ':' && preunum
[i
+ 1] == ' ') {
236 bcopy(preunum
+ i
+ 2, preunum
+ i
+ 1,
238 } else if (preunum
[i
] == ' ') {
243 i
= mem_fmri_uriescape(preunum
, ":,/", NULL
, 0);
244 escunum
= topo_mod_alloc(mod
, i
+ 1);
245 (void) mem_fmri_uriescape(preunum
, ":,/", escunum
, i
+ 1);
246 topo_mod_free(mod
, preunum
, presz
);
249 len
= snprintf(NULL
, 0, format
, prefix
, escunum
, val
) + 1;
250 buf
= topo_mod_zalloc(mod
, len
);
254 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
257 (void) snprintf(buf
, len
, format
, prefix
, escunum
, val
);
259 topo_mod_strfree(mod
, escunum
);
260 err
= nvlist_add_string(nvl
, "fmri-string", buf
);
261 topo_mod_free(mod
, buf
, len
);
265 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
273 mem_fmri(topo_mod_t
*mod
, uint64_t pa
, uint64_t offset
, char *unum
, int flags
)
278 if (topo_mod_nvalloc(mod
, &asru
, NV_UNIQUE_NAME
) != 0)
282 * If we have a well-formed unum we step over the hc:/// and
285 if (strncmp(unum
, "hc://", 5) == 0) {
288 tstr
= strchr(unum
, '/');
292 err
= nvlist_add_uint8(asru
, FM_VERSION
, FM_MEM_SCHEME_VERSION
);
293 err
|= nvlist_add_string(asru
, FM_FMRI_SCHEME
, FM_FMRI_SCHEME_MEM
);
294 err
|= nvlist_add_string(asru
, FM_FMRI_MEM_UNUM
, unum
);
295 if (flags
& TOPO_MEMFMRI_PA
)
296 err
|= nvlist_add_uint64(asru
, FM_FMRI_MEM_PHYSADDR
, pa
);
297 if (flags
& TOPO_MEMFMRI_OFFSET
)
298 err
|= nvlist_add_uint64(asru
, FM_FMRI_MEM_OFFSET
, offset
);
310 mem_fmri_create(topo_mod_t
*mod
, tnode_t
*node
, topo_version_t version
,
311 nvlist_t
*in
, nvlist_t
**out
)
313 uint64_t pa
= 0, offset
= 0;
318 if (nvlist_lookup_uint64(in
, FM_FMRI_MEM_PHYSADDR
, &pa
) == 0)
319 flags
|= TOPO_MEMFMRI_PA
;
320 if (nvlist_lookup_uint64(in
, FM_FMRI_MEM_OFFSET
, &offset
) == 0)
321 flags
|= TOPO_MEMFMRI_OFFSET
;
322 if (nvlist_lookup_string(in
, FM_FMRI_MEM_UNUM
, &unum
) != 0)
323 return (topo_mod_seterrno(mod
, EMOD_FMRI_MALFORM
));
325 asru
= mem_fmri(mod
, pa
, offset
, unum
, flags
);
328 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));