xref: /netbsd-src/sys/arch/i386/stand/efiboot/efidisk_ll.c (revision 8ecbf5f02b752fcb7debe1a8fab1dc82602bc760)
1 /*	$NetBSD: efidisk_ll.c,v 1.2 2018/03/08 10:34:33 nonaka Exp $	 */
2 /*	NetBSD: biosdisk_ll.c,v 1.31 2011/02/21 02:58:02 jakllsch Exp	 */
3 
4 /*-
5  * Copyright (c) 2005 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Bang Jun-Young.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1996
35  * 	Matthias Drochner.  All rights reserved.
36  * Copyright (c) 1996
37  * 	Perry E. Metzger.  All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgements:
49  *	This product includes software developed for the NetBSD Project
50  *	by Matthias Drochner.
51  *	This product includes software developed for the NetBSD Project
52  *	by Perry E. Metzger.
53  * 4. The names of the authors may not be used to endorse or promote products
54  *    derived from this software without specific prior written permission.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
57  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
58  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
59  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
60  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
61  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
62  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
63  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
64  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
65  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66  */
67 
68 /*
69  * shared by bootsector startup (bootsectmain) and biosdisk.c
70  * needs lowlevel parts from bios_disk.S
71  */
72 
73 #include "efiboot.h"
74 
75 #include "biosdisk_ll.h"
76 #include "diskbuf.h"
77 #include "efidisk.h"
78 
79 static int do_read(struct biosdisk_ll *, daddr_t, int, char *);
80 
81 #ifndef BIOSDISK_RETRIES
82 #define BIOSDISK_RETRIES 5
83 #endif
84 
85 int
86 set_geometry(struct biosdisk_ll *d, struct biosdisk_extinfo *ed)
87 {
88 	const struct efidiskinfo *edi;
89 	EFI_BLOCK_IO_MEDIA *media;
90 
91 	edi = efidisk_getinfo(d->dev);
92 	if (edi == NULL)
93 		return 1;
94 
95 	media = edi->bio->Media;
96 
97 	d->secsize = media->BlockSize;
98 	d->type = edi->type;
99 	d->flags = BIOSDISK_INT13EXT;
100 
101 	if (ed != NULL) {
102 		ed->totsec = media->LastBlock + 1;
103 		ed->sbytes = media->BlockSize;
104 		ed->flags = 0;
105 		if (media->RemovableMedia)
106 			ed->flags |= EXTINFO_REMOVABLE;
107 	}
108 
109 	return 0;
110 }
111 
112 /*
113  * Global shared "diskbuf" is used as read ahead buffer.  For reading from
114  * floppies, the bootstrap has to be loaded on a 64K boundary to ensure that
115  * this buffer doesn't cross a 64K DMA boundary.
116  */
117 static int      ra_dev;
118 static daddr_t  ra_end;
119 static daddr_t  ra_first;
120 
121 static int
122 do_read(struct biosdisk_ll *d, daddr_t dblk, int num, char *buf)
123 {
124 	EFI_STATUS status;
125 	const struct efidiskinfo *edi;
126 
127 	edi = efidisk_getinfo(d->dev);
128 	if (edi == NULL)
129 		return -1;
130 
131 	status = uefi_call_wrapper(edi->bio->ReadBlocks, 5, edi->bio,
132 	    edi->media_id, dblk, num * d->secsize, buf);
133 	if (EFI_ERROR(status))
134 		return -1;
135 	return num;
136 }
137 
138 /*
139  * NB if 'cold' is set below not all of the program is loaded, so
140  * mustn't use data segment, bss, call library functions or do read-ahead.
141  */
142 int
143 readsects(struct biosdisk_ll *d, daddr_t dblk, int num, char *buf, int cold)
144 {
145 	while (num) {
146 		int nsec;
147 
148 		/* check for usable data in read-ahead buffer */
149 		if (cold || diskbuf_user != &ra_dev || d->dev != ra_dev
150 		    || dblk < ra_first || dblk >= ra_end) {
151 
152 			/* no, read from disk */
153 			char *trbuf;
154 			int maxsecs;
155 			int retries = BIOSDISK_RETRIES;
156 
157 			if (cold) {
158 				/* transfer directly to buffer */
159 				trbuf = buf;
160 				maxsecs = num;
161 			} else {
162 				/* fill read-ahead buffer */
163 				trbuf = alloc_diskbuf(0); /* no data yet */
164 				maxsecs = DISKBUFSIZE / d->secsize;
165 			}
166 
167 			while ((nsec = do_read(d, dblk, maxsecs, trbuf)) < 0) {
168 #ifdef DISK_DEBUG
169 				if (!cold)
170 					printf("read error dblk %"PRId64"-%"PRId64"\n",
171 					    dblk, (dblk + maxsecs - 1));
172 #endif
173 				if (--retries >= 0)
174 					continue;
175 				return -1;	/* XXX cannot output here if
176 						 * (cold) */
177 			}
178 			if (!cold) {
179 				ra_dev = d->dev;
180 				ra_first = dblk;
181 				ra_end = dblk + nsec;
182 				diskbuf_user = &ra_dev;
183 			}
184 		} else		/* can take blocks from end of read-ahead
185 				 * buffer */
186 			nsec = ra_end - dblk;
187 
188 		if (!cold) {
189 			/* copy data from read-ahead to user buffer */
190 			if (nsec > num)
191 				nsec = num;
192 			memcpy(buf,
193 			       diskbufp + (dblk - ra_first) * d->secsize,
194 			       nsec * d->secsize);
195 		}
196 		buf += nsec * d->secsize;
197 		num -= nsec;
198 		dblk += nsec;
199 	}
200 
201 	return 0;
202 }
203