source: mainline/uspace/app/sysinst/sysinst.c@ 3cdd876

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3cdd876 was 3cdd876, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Sysinst needs updating.

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/*
2 * Copyright (c) 2014 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup sysinst
30 * @{
31 */
32/** @file System installer.
33 *
34 * Install the operating system onto a disk device. Note that this only works
35 * on ia32/amd64 with Grub platform 'pc'.
36 */
37
38#include <block.h>
39#include <byteorder.h>
40#include <cap.h>
41#include <errno.h>
42#include <fdisk.h>
43#include <loc.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <str.h>
47#include <str_error.h>
48#include <task.h>
49#include <vfs/vfs.h>
50#include <vol.h>
51
52#include "futil.h"
53#include "grub.h"
54
55/** Device to install to
56 *
57 * Note that you cannot simply change this, because the installation
58 * device is hardcoded in core.img. If you wanted to install to another
59 * device, you must build your own core.img (e.g. using tools/grub/mkimage.sh
60 * and modifying tools/grub/load.cfg, supplying the device to boot from
61 * in Grub notation).
62 */
63#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.0\\ata-c1\\d0"
64//#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.2\\uhci_rh\\usb01_a1\\mass-storage0\\l0"
65
66#define MOUNT_POINT "/inst"
67
68/** HelenOS live CD volume label */
69#define CD_VOL_LABEL "HelenOS-CD"
70#define CD_MOUNT_POINT "/vol/" CD_VOL_LABEL
71
72#define BOOT_FILES_SRC CD_MOUNT_POINT
73#define BOOT_BLOCK_IDX 0 /* MBR */
74
75/** Label the destination device.
76 *
77 * @param dev Disk device to label
78 * @param psvc_id Place to store service ID of the created partition
79 *
80 * @return EOK on success or an error code
81 */
82static errno_t sysinst_label_dev(const char *dev, service_id_t *psvc_id)
83{
84 fdisk_t *fdisk;
85 fdisk_dev_t *fdev;
86 fdisk_part_t *part;
87 fdisk_part_spec_t pspec;
88 fdisk_part_info_t pinfo;
89 cap_spec_t cap;
90 service_id_t sid;
91 errno_t rc;
92
93 printf("sysinst_label_dev(): get service ID '%s'\n", dev);
94 rc = loc_service_get_id(dev, &sid, 0);
95 if (rc != EOK)
96 return rc;
97
98 printf("sysinst_label_dev(): open device\n");
99
100 rc = fdisk_create(&fdisk);
101 if (rc != EOK) {
102 printf("Error initializing fdisk.\n");
103 return rc;
104 }
105
106 rc = fdisk_dev_open(fdisk, sid, &fdev);
107 if (rc != EOK) {
108 printf("Error opening device.\n");
109 return rc;
110 }
111
112 printf("sysinst_label_dev(): create mount directory\n");
113
114 rc = vfs_link_path(MOUNT_POINT, KIND_DIRECTORY, NULL);
115 if (rc != EOK)
116 return rc;
117
118 printf("sysinst_label_dev(): create label\n");
119
120 rc = fdisk_label_create(fdev, lt_mbr);
121 if (rc != EOK) {
122 printf("Error creating label: %s.\n", str_error(rc));
123 return rc;
124 }
125
126 printf("sysinst_label_dev(): create partition\n");
127
128 rc = fdisk_part_get_max_avail(fdev, spc_pri, &cap);
129 if (rc != EOK) {
130 printf("Error getting available capacity: %s.\n", str_error(rc));
131 return rc;
132 }
133
134 fdisk_pspec_init(&pspec);
135 pspec.capacity = cap;
136 pspec.pkind = lpk_primary;
137 pspec.fstype = fs_minix; /* Cannot be changed without modifying core.img */
138 pspec.mountp = MOUNT_POINT;
139
140 rc = fdisk_part_create(fdev, &pspec, &part);
141 if (rc != EOK) {
142 printf("Error creating partition.\n");
143 return rc;
144 }
145
146 rc = fdisk_part_get_info(part, &pinfo);
147 if (rc != EOK) {
148 printf("Error getting partition information.\n");
149 return rc;
150 }
151
152 printf("sysinst_label_dev(): OK\n");
153 *psvc_id = pinfo.svc_id;
154 return EOK;
155}
156
157/** Copy boot files.
158 *
159 * @return EOK on success or an error code
160 */
161static errno_t sysinst_copy_boot_files(void)
162{
163 errno_t rc;
164
165 printf("sysinst_copy_boot_files(): copy bootloader files\n");
166 rc = futil_rcopy_contents(BOOT_FILES_SRC, MOUNT_POINT);
167 if (rc != EOK)
168 return rc;
169
170 printf("sysinst_copy_boot_files(): OK\n");
171 return EOK;
172}
173
174/** Write unaligned 64-bit little-endian number.
175 *
176 * @param a Destination buffer
177 * @param data Number
178 */
179static void set_unaligned_u64le(uint8_t *a, uint64_t data)
180{
181 int i;
182
183 for (i = 0; i < 8; i++) {
184 a[i] = (data >> (i * 8)) & 0xff;
185 }
186}
187
188/** Copy boot blocks.
189 *
190 * Install Grub's boot blocks.
191 *
192 * @param devp Disk device
193 * @return EOK on success or an error code
194 */
195static errno_t sysinst_copy_boot_blocks(const char *devp)
196{
197 void *boot_img;
198 size_t boot_img_size;
199 void *core_img;
200 size_t core_img_size;
201 service_id_t sid;
202 size_t bsize;
203 uint8_t bbuf[512];
204 aoff64_t core_start;
205 aoff64_t core_blocks;
206 grub_boot_blocklist_t *first_bl, *bl;
207 errno_t rc;
208
209 printf("sysinst_copy_boot_blocks: Read boot block image.\n");
210 rc = futil_get_file(BOOT_FILES_SRC "/boot/grub/i386-pc/boot.img",
211 &boot_img, &boot_img_size);
212 if (rc != EOK || boot_img_size != 512)
213 return EIO;
214
215 printf("sysinst_copy_boot_blocks: Read GRUB core image.\n");
216 rc = futil_get_file(BOOT_FILES_SRC "/boot/grub/i386-pc/core.img",
217 &core_img, &core_img_size);
218 if (rc != EOK)
219 return EIO;
220
221 printf("sysinst_copy_boot_blocks: get service ID.\n");
222 rc = loc_service_get_id(devp, &sid, 0);
223 if (rc != EOK)
224 return rc;
225
226 printf("sysinst_copy_boot_blocks: block_init.\n");
227 rc = block_init(sid, 512);
228 if (rc != EOK)
229 return rc;
230
231 printf("sysinst_copy_boot_blocks: get block size\n");
232 rc = block_get_bsize(sid, &bsize);
233 if (rc != EOK)
234 return rc;
235
236 if (bsize != 512) {
237 printf("Device block size != 512.\n");
238 return EIO;
239 }
240
241 printf("sysinst_copy_boot_blocks: read boot block\n");
242 rc = block_read_direct(sid, BOOT_BLOCK_IDX, 1, bbuf);
243 if (rc != EOK)
244 return EIO;
245
246 core_start = 16;
247 core_blocks = (core_img_size + 511) / 512;
248
249 /* Clean blocklists */
250 first_bl = core_img + 512 - sizeof(*first_bl);
251 bl = first_bl;
252 while (bl->len != 0) {
253 memset(bl, 0, sizeof(*bl));
254 --bl;
255 if ((void *)bl < core_img) {
256 printf("No block terminator in core image.\n");
257 return EIO;
258 }
259 }
260
261 first_bl->start = host2uint64_t_le(core_start + 1);
262 first_bl->len = host2uint16_t_le(core_blocks - 1);
263 first_bl->segment = grub_boot_i386_pc_kernel_seg + (512 >> 4);
264
265 /* Write boot code into boot block */
266 memcpy(bbuf, boot_img, 440); /* XXX 440 = sizeof(br_block_t.code_area) */
267 bbuf[grub_boot_machine_boot_drive] = 0xff;
268 set_unaligned_u64le(bbuf + grub_boot_machine_kernel_sector, core_start);
269
270 printf("sysinst_copy_boot_blocks: write boot block\n");
271 rc = block_write_direct(sid, BOOT_BLOCK_IDX, 1, bbuf);
272 if (rc != EOK)
273 return EIO;
274
275 printf("sysinst_copy_boot_blocks: write boot block\n");
276 /* XXX Must pad last block with zeros */
277 rc = block_write_direct(sid, core_start, core_blocks, core_img);
278 if (rc != EOK)
279 return EIO;
280
281 printf("sysinst_copy_boot_blocks: OK.\n");
282 return EOK;
283}
284
285/** Eject installation volume.
286 *
287 * @param psvc_id Partition service ID
288 */
289static errno_t sysinst_eject_dev(service_id_t part_id)
290{
291 vol_t *vol = NULL;
292 errno_t rc;
293
294 rc = vol_create(&vol);
295 if (rc != EOK) {
296 printf("Error contacting volume service.\n");
297 goto out;
298 }
299
300 rc = vol_part_eject(vol, part_id);
301 if (rc != EOK) {
302 printf("Error ejecting volume.\n");
303 goto out;
304 }
305
306 rc = EOK;
307out:
308 vol_destroy(vol);
309 return rc;
310}
311
312/** Install system to a device.
313 *
314 * @param dev Device to install to.
315 * @return EOK on success or an error code
316 */
317static errno_t sysinst_install(const char *dev)
318{
319 errno_t rc;
320 service_id_t psvc_id;
321
322 rc = sysinst_label_dev(dev, &psvc_id);
323 if (rc != EOK)
324 return rc;
325
326 printf("FS created and mounted. Copying boot files.\n");
327 rc = sysinst_copy_boot_files();
328 if (rc != EOK)
329 return rc;
330
331 printf("Boot files done. Installing boot blocks.\n");
332 rc = sysinst_copy_boot_blocks(dev);
333 if (rc != EOK)
334 return rc;
335
336 printf("Ejecting device.\n");
337 rc = sysinst_eject_dev(psvc_id);
338 if (rc != EOK)
339 return rc;
340
341 return EOK;
342}
343
344int main(int argc, char *argv[])
345{
346 const char *dev = DEFAULT_DEV;
347 return sysinst_install(dev);
348}
349
350/** @}
351 */
Note: See TracBrowser for help on using the repository browser.