Ignore machine-check MSRs
[freebsd-src/fkvm-freebsd.git] / sys / kern / subr_msgbuf.c
blob14cd39dd83167f3f22dc4e63a28864867bb6bddf
1 /*-
2 * Copyright (c) 2003 Ian Dowse. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
25 * $FreeBSD$
29 * Generic message buffer support routines.
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/msgbuf.h>
36 /* Read/write sequence numbers are modulo a multiple of the buffer size. */
37 #define SEQMOD(size) ((size) * 16)
39 static u_int msgbuf_cksum(struct msgbuf *mbp);
42 * Initialize a message buffer of the specified size at the specified
43 * location. This also zeros the buffer area.
45 void
46 msgbuf_init(struct msgbuf *mbp, void *ptr, int size)
49 mbp->msg_ptr = ptr;
50 mbp->msg_size = size;
51 mbp->msg_seqmod = SEQMOD(size);
52 msgbuf_clear(mbp);
53 mbp->msg_magic = MSG_MAGIC;
57 * Reinitialize a message buffer, retaining its previous contents if
58 * the size and checksum are correct. If the old contents cannot be
59 * recovered, the message buffer is cleared.
61 void
62 msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size)
64 u_int cksum;
66 if (mbp->msg_magic != MSG_MAGIC || mbp->msg_size != size) {
67 msgbuf_init(mbp, ptr, size);
68 return;
70 mbp->msg_seqmod = SEQMOD(size);
71 mbp->msg_wseq = MSGBUF_SEQNORM(mbp, mbp->msg_wseq);
72 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq);
73 mbp->msg_ptr = ptr;
74 cksum = msgbuf_cksum(mbp);
75 if (cksum != mbp->msg_cksum) {
76 if (bootverbose) {
77 printf("msgbuf cksum mismatch (read %x, calc %x)\n",
78 mbp->msg_cksum, cksum);
79 printf("Old msgbuf not recovered\n");
81 msgbuf_clear(mbp);
86 * Clear the message buffer.
88 void
89 msgbuf_clear(struct msgbuf *mbp)
92 bzero(mbp->msg_ptr, mbp->msg_size);
93 mbp->msg_wseq = 0;
94 mbp->msg_rseq = 0;
95 mbp->msg_cksum = 0;
99 * Get a count of the number of unread characters in the message buffer.
102 msgbuf_getcount(struct msgbuf *mbp)
104 u_int len;
106 len = MSGBUF_SEQSUB(mbp, mbp->msg_wseq, mbp->msg_rseq);
107 if (len > mbp->msg_size)
108 len = mbp->msg_size;
109 return (len);
113 * Append a character to a message buffer. This function can be
114 * considered fully reentrant so long as the number of concurrent
115 * callers is less than the number of characters in the buffer.
116 * However, the message buffer is only guaranteed to be consistent
117 * for reading when there are no callers in this function.
119 void
120 msgbuf_addchar(struct msgbuf *mbp, int c)
122 u_int new_seq, pos, seq;
124 do {
125 seq = mbp->msg_wseq;
126 new_seq = MSGBUF_SEQNORM(mbp, seq + 1);
127 } while (atomic_cmpset_rel_int(&mbp->msg_wseq, seq, new_seq) == 0);
128 pos = MSGBUF_SEQ_TO_POS(mbp, seq);
129 atomic_add_int(&mbp->msg_cksum, (u_int)(u_char)c -
130 (u_int)(u_char)mbp->msg_ptr[pos]);
131 mbp->msg_ptr[pos] = c;
135 * Read and mark as read a character from a message buffer.
136 * Returns the character, or -1 if no characters are available.
139 msgbuf_getchar(struct msgbuf *mbp)
141 u_int len, wseq;
142 int c;
144 wseq = mbp->msg_wseq;
145 len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
146 if (len == 0)
147 return (-1);
148 if (len > mbp->msg_size)
149 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
150 c = (u_char)mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq)];
151 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + 1);
152 return (c);
156 * Read and mark as read a number of characters from a message buffer.
157 * Returns the number of characters that were placed in `buf'.
160 msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen)
162 u_int len, pos, wseq;
164 wseq = mbp->msg_wseq;
165 len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
166 if (len == 0)
167 return (0);
168 if (len > mbp->msg_size) {
169 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
170 len = mbp->msg_size;
172 pos = MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq);
173 len = min(len, mbp->msg_size - pos);
174 len = min(len, (u_int)buflen);
176 bcopy(&mbp->msg_ptr[pos], buf, len);
177 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + len);
178 return (len);
182 * Peek at the full contents of a message buffer without marking any
183 * data as read. `seqp' should point to an unsigned integer that
184 * msgbuf_peekbytes() can use to retain state between calls so that
185 * the whole message buffer can be read in multiple short reads.
186 * To initialise this variable to the start of the message buffer,
187 * call msgbuf_peekbytes() with a NULL `buf' parameter.
189 * Returns the number of characters that were placed in `buf'.
192 msgbuf_peekbytes(struct msgbuf *mbp, char *buf, int buflen, u_int *seqp)
194 u_int len, pos, wseq;
196 if (buf == NULL) {
197 /* Just initialise *seqp. */
198 *seqp = MSGBUF_SEQNORM(mbp, mbp->msg_wseq - mbp->msg_size);
199 return (0);
202 wseq = mbp->msg_wseq;
203 len = MSGBUF_SEQSUB(mbp, wseq, *seqp);
204 if (len == 0)
205 return (0);
206 if (len > mbp->msg_size) {
207 *seqp = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
208 len = mbp->msg_size;
210 pos = MSGBUF_SEQ_TO_POS(mbp, *seqp);
211 len = min(len, mbp->msg_size - pos);
212 len = min(len, (u_int)buflen);
213 bcopy(&mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, *seqp)], buf, len);
214 *seqp = MSGBUF_SEQNORM(mbp, *seqp + len);
215 return (len);
219 * Compute the checksum for the complete message buffer contents.
221 static u_int
222 msgbuf_cksum(struct msgbuf *mbp)
224 u_int i, sum;
226 sum = 0;
227 for (i = 0; i < mbp->msg_size; i++)
228 sum += (u_char)mbp->msg_ptr[i];
229 return (sum);
233 * Copy from one message buffer to another.
235 void
236 msgbuf_copy(struct msgbuf *src, struct msgbuf *dst)
238 int c;
240 while ((c = msgbuf_getchar(src)) >= 0)
241 msgbuf_addchar(dst, c);