]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libdisk/write_amd64_disk.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libdisk / write_amd64_disk.c
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  */
9
10 #include <sys/cdefs.h>
11 __FBSDID("$FreeBSD$");
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/disklabel.h>
21 #include <sys/diskmbr.h>
22 #include <paths.h>
23 #include "libdisk.h"
24
25 /*
26  * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
27  *      I'm not sure which, so I leave it like it worked before. --schweikh
28  */
29 static int
30 Write_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
31 {
32         struct disklabel *dl;
33         int i;
34         void *p;
35         u_char buf[BBSIZE];
36
37         for (i = 0; i < BBSIZE/512; i++) {
38                 if (!(p = read_block(fd, i + c1->offset, 512)))
39                         return (1);
40                 memcpy(buf + 512 * i, p, 512);
41                 free(p);
42         }
43         if (new->boot1)
44                 memcpy(buf, new->boot1, 512);
45
46         if (new->boot2)
47                 memcpy(buf + 512, new->boot2, BBSIZE - 512);
48
49         dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
50         Fill_Disklabel(dl, new, c1);
51
52         for (i = 0; i < BBSIZE / 512; i++)
53                 write_block(fd, i + c1->offset, buf + 512 * i, 512);
54
55         return 0;
56 }
57
58 static void
59 Write_Int32(u_int32_t *p, u_int32_t v)
60 {
61         u_int8_t *bp = (u_int8_t *)p;
62
63         bp[0] = (v >> 0) & 0xff;
64         bp[1] = (v >> 8) & 0xff;
65         bp[2] = (v >> 16) & 0xff;
66         bp[3] = (v >> 24) & 0xff;
67 }
68
69 /*
70  * Special install-time configuration for the i386 boot0 boot manager.
71  */
72 static void
73 Cfg_Boot_Mgr(u_char *mbr, int edd)
74 {
75
76         if (mbr[0x1b0] == 0x66 && mbr[0x1b1] == 0xbb) {
77                 if (edd)
78                         mbr[0x1bb] |= 0x80;     /* Packet mode on */
79                 else
80                         mbr[0x1bb] &= 0x7f;     /* Packet mode off */
81         }
82 }
83
84 int
85 Write_Disk(const struct disk *d1)
86 {
87         int fd, j;
88         uint i;
89         struct chunk *c1;
90         int ret = 0;
91         char device[64];
92         u_char *mbr;
93         struct dos_partition *dp,work[NDOSPART];
94         int s[4];
95         int need_edd = 0;       /* Need EDD (packet interface) */
96
97         strcpy(device, _PATH_DEV);
98         strcat(device, d1->name);
99
100         fd = open(device, O_RDWR);
101         if (fd < 0)
102                 return 1;
103
104         memset(s, 0, sizeof s);
105         if (!(mbr = read_block(fd, 0, d1->sector_size))) {
106                 close (fd);
107                 return (1);
108         }
109         dp = (struct dos_partition *)(mbr + DOSPARTOFF);
110         memcpy(work, dp, sizeof work);
111         dp = work;
112         free(mbr);
113         for (c1 = d1->chunks->part; c1; c1 = c1->next) {
114                 if (c1->type == unused)
115                         continue;
116                 if (!strcmp(c1->name, "X"))
117                         continue;
118                 j = c1->name[strlen(d1->name) + 1] - '1';
119                 if (j < 0 || j > 3)
120                         continue;
121                 s[j]++;
122                 if (c1->type == freebsd)
123                         ret += Write_FreeBSD(fd, d1, c1);
124
125                 Write_Int32(&dp[j].dp_start, c1->offset);
126                 Write_Int32(&dp[j].dp_size, c1->size);
127
128                 i = c1->offset;
129                 if (i >= 1024 * d1->bios_sect * d1->bios_hd) {
130                         dp[j].dp_ssect = 0xff;
131                         dp[j].dp_shd = 0xff;
132                         dp[j].dp_scyl = 0xff;
133                         need_edd++;
134                 } else {
135                         dp[j].dp_ssect = i % d1->bios_sect;
136                         i -= dp[j].dp_ssect++;
137                         i /= d1->bios_sect;
138                         dp[j].dp_shd =  i % d1->bios_hd;
139                         i -= dp[j].dp_shd;
140                         i /= d1->bios_hd;
141                         dp[j].dp_scyl = i;
142                         i -= dp[j].dp_scyl;
143                         dp[j].dp_ssect |= i >> 2;
144                 }
145 #ifdef DEBUG
146                 printf("S:%lu = (%x/%x/%x)", c1->offset,
147                        dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
148 #endif
149
150                 i = c1->end;
151                 dp[j].dp_esect = i % d1->bios_sect;
152                 i -= dp[j].dp_esect++;
153                 i /= d1->bios_sect;
154                 dp[j].dp_ehd =  i % d1->bios_hd;
155                 i -= dp[j].dp_ehd;
156                 i /= d1->bios_hd;
157                 if (i > 1023)
158                         i = 1023;
159                 dp[j].dp_ecyl = i;
160                 i -= dp[j].dp_ecyl;
161                 dp[j].dp_esect |= i >> 2;
162 #ifdef DEBUG
163                 printf("  E:%lu = (%x/%x/%x)\n", c1->end,
164                        dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
165 #endif
166
167                 dp[j].dp_typ = c1->subtype;
168                 if (c1->flags & CHUNK_ACTIVE)
169                         dp[j].dp_flag = 0x80;
170                 else
171                         dp[j].dp_flag = 0;
172         }
173         j = 0;
174         for (i = 0; i < NDOSPART; i++) {
175                 if (!s[i])
176                         memset(dp + i, 0, sizeof *dp);
177                 if (dp[i].dp_flag)
178                         j++;
179         }
180         if (!j)
181                 for(i = 0; i < NDOSPART; i++)
182                         if (dp[i].dp_typ == 0xa5)
183                                 dp[i].dp_flag = 0x80;
184
185         if (!(mbr = read_block(fd, 0, d1->sector_size))) {
186                 close (fd);
187                 return (1);
188         }
189         if (d1->bootmgr) {
190                 memcpy(mbr, d1->bootmgr, DOSPARTOFF);
191                 Cfg_Boot_Mgr(mbr, need_edd);
192         }
193         memcpy(mbr + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
194         mbr[512-2] = 0x55;
195         mbr[512-1] = 0xaa;
196         write_block(fd, 0, mbr, d1->sector_size);
197         if (d1->bootmgr && d1->bootmgr_size > d1->sector_size)
198                 for (i = 1; i * d1->sector_size <= d1->bootmgr_size; i++)
199                         write_block(fd, i, &d1->bootmgr[i * d1->sector_size],
200                                     d1->sector_size);
201
202         close(fd);
203         return 0;
204 }