Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / platform / pc32 / boot / dosboot / disk.c
1 /*\r
2  * Mach Operating System\r
3  * Copyright (c) 1992, 1991 Carnegie Mellon University\r
4  * All Rights Reserved.\r
5  * \r
6  * Permission to use, copy, modify and distribute this software and its\r
7  * documentation is hereby granted, provided that both the copyright\r
8  * notice and this permission notice appear in all copies of the\r
9  * software, derivative works or modified versions, and any portions\r
10  * thereof, and that both notices appear in supporting documentation.\r
11  * \r
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"\r
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR\r
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.\r
15  * \r
16  * Carnegie Mellon requests users of this software to return to\r
17  * \r
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU\r
19  *  School of Computer Science\r
20  *  Carnegie Mellon University\r
21  *  Pittsburgh PA 15213-3890\r
22  * \r
23  * any improvements or extensions that they make and grant Carnegie Mellon\r
24  * the rights to redistribute these changes.\r
25  *\r
26  *      from: Mach, Revision 2.2  92/04/04  11:35:49  rpd\r
27  * $FreeBSD: src/sys/i386/boot/dosboot/disk.c,v 1.6 1999/12/08 09:32:49 phk Exp $\r
28  */\r
29 #include <stdio.h>\r
30 #include <memory.h>\r
31 \r
32 #define bcopy(a,b,c)    memcpy(b,a,c)\r
33 \r
34 #include "boot.h"\r
35 #include "disklabe.h"\r
36 #include "diskslic.h"\r
37 \r
38 #define BIOS_DEV_FLOPPY 0x0\r
39 #define BIOS_DEV_WIN    0x80\r
40 \r
41 #define BPS                     512\r
42 #define SPT(di)         ((di)&0xff)\r
43 #define HEADS(di)       ((((di)>>8)&0xff)+1)\r
44 \r
45 static char i_buf[BPS];\r
46 #define I_ADDR          ((void *) i_buf)        /* XXX where all reads go */\r
47 \r
48 \r
49 static int spt, spc;\r
50 \r
51 char *iodest;\r
52 struct fs *fs;\r
53 struct inode inode;\r
54 long dosdev, slice, unit, part, maj, boff, poff, bnum, cnt;\r
55 \r
56 extern int biosread(int dev, int track, int head, int sector, int cnt, unsigned char far *buffer);\r
57 \r
58 struct  disklabel disklabel;\r
59 \r
60 static void Bread(int dosdev, long sector);\r
61 \r
62 unsigned long get_diskinfo(int drive)\r
63 {\r
64         char dr = (char) drive;\r
65         unsigned long rt;\r
66 \r
67         _asm {\r
68                 mov ah,8                ; get diskinfo\r
69                 mov dl,dr               ; drive\r
70                 int 13h\r
71                 cmp ah,0\r
72                 je ok\r
73                 ;\r
74                 ; Failure! We assume it's a floppy!\r
75                 ;\r
76                 sub ax,ax\r
77                 mov bh,ah\r
78                 mov bl,2\r
79                 mov ch,79\r
80                 mov cl,15\r
81                 mov dh,1\r
82                 mov dl,1\r
83         ok:\r
84                 mov ah,dh\r
85                 mov al,cl\r
86                 and al,3fh\r
87                 mov word ptr rt,ax\r
88 \r
89                 xor bx,bx\r
90                 mov bl,cl\r
91                 and bl,0c0h\r
92                 shl bx,2\r
93                 mov bl,ch\r
94                 mov word ptr rt+2,bx\r
95         }\r
96         return rt;\r
97 }\r
98 \r
99 int devopen(void)\r
100 {\r
101         struct dos_partition *dptr;\r
102         struct disklabel *dl;\r
103         int dosdev = (int) inode.i_dev;\r
104         int i;\r
105         long di, sector;\r
106         \r
107         di = get_diskinfo(dosdev);\r
108         spc = (spt = (int)SPT(di)) * (int)HEADS(di);\r
109         if (dosdev == 2)\r
110         {\r
111                 boff = 0;\r
112                 part = (spt == 15 ? 3 : 1);\r
113         }\r
114         else\r
115         {\r
116 #ifdef  EMBEDDED_DISKLABEL\r
117                 dl = &disklabel;\r
118 #else   EMBEDDED_DISKLABEL\r
119                 Bread(dosdev, 0);\r
120                 dptr = (struct dos_partition *)(((char *)I_ADDR)+DOSPARTOFF);\r
121                 sector = LABELSECTOR;\r
122                 slice = WHOLE_DISK_SLICE;\r
123                 for (i = 0; i < NDOSPART; i++, dptr++)\r
124                         if (dptr->dp_typ == DOSPTYP_386BSD) {\r
125                                 slice = BASE_SLICE + i;\r
126                                 sector = dptr->dp_start + LABELSECTOR;\r
127                                 break;\r
128                         }\r
129                 Bread(dosdev, sector++);\r
130                 dl=((struct disklabel *)I_ADDR);\r
131                 disklabel = *dl;        /* structure copy (maybe useful later)*/\r
132 #endif  EMBEDDED_DISKLABEL\r
133                 if (dl->d_magic != DISKMAGIC) {\r
134                         printf("bad disklabel");\r
135                         return 1;\r
136                 }\r
137 \r
138                 if( (maj == 4) || (maj == 0) || (maj == 1)) {\r
139                         if (dl->d_type == DTYPE_SCSI)\r
140                                 maj = 4; /* use scsi as boot dev */\r
141                         else\r
142                                 maj = 0; /* must be ESDI/IDE */\r
143                 }\r
144 \r
145                 boff = dl->d_partitions[part].p_offset;\r
146         }\r
147         return 0;\r
148 }\r
149 \r
150 void devread(void)\r
151 {\r
152         long offset, sector = bnum;\r
153         int dosdev = (int) inode.i_dev;\r
154         for (offset = 0; offset < cnt; offset += BPS)\r
155         {\r
156                 Bread(dosdev, sector++);\r
157                 bcopy(I_ADDR, iodest+offset, BPS);\r
158         }\r
159 }\r
160 \r
161 /* Read ahead buffer large enough for one track on a 1440K floppy.  For\r
162  * reading from floppies, the bootstrap has to be loaded on a 64K boundary\r
163  * to ensure that this buffer doesn't cross a 64K DMA boundary.\r
164  */\r
165 #define RA_SECTORS      18\r
166 static char ra_buf[RA_SECTORS * BPS];\r
167 static int ra_dev;\r
168 static long ra_end;\r
169 static long ra_first;\r
170 \r
171 static void Bread(int dosdev, long sector)\r
172 {\r
173         if (dosdev != ra_dev || sector < ra_first || sector >= ra_end)\r
174         {\r
175                 int cyl, head, sec, nsec;\r
176 \r
177                 cyl = (int) (sector/(long)spc);\r
178                 head = (int) ((sector % (long) spc) / (long) spt);\r
179                 sec = (int) (sector % (long) spt);\r
180                 nsec = spt - sec;\r
181                 if (nsec > RA_SECTORS)\r
182                         nsec = RA_SECTORS;\r
183                 if (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0)\r
184                 {\r
185                     nsec = 1;\r
186                     while (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0)\r
187                                 printf("Error: C:%d H:%d S:%d\n", cyl, head, sec);\r
188                 }\r
189                 ra_dev = dosdev;\r
190                 ra_first = sector;\r
191                 ra_end = sector + nsec;\r
192         }\r
193         bcopy(ra_buf + (sector - ra_first) * BPS, I_ADDR, BPS);\r
194 }\r