2 * Copyright (c) 2014 Jiri Svoboda
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 /** @addtogroup sysinst
32 /** @file System installer.
34 * Install the operating system onto a disk device. Note that this only works
35 * on ia32/amd64 with Grub platform 'pc'.
39 #include <byteorder.h>
46 #include <str_error.h>
54 /** Device to install to
56 * Note that you cannot simply change this, because the installation
57 * device is hardcoded in core.img. If you wanted to install to another
58 * device, you must build your own core.img (e.g. using tools/grub/mkimage.sh
59 * and modifying tools/grub/load.cfg, supplying the device to boot from
62 #define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.0\\ata-c1\\d0"
63 //#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.2\\uhci_rh\\usb01_a1\\mass-storage0\\l0"
65 /** Filysystem type. Cannot be changed without building a custom core.img */
68 #define FS_SRV "/srv/mfs"
69 #define MOUNT_POINT "/inst"
71 /** Device containing HelenOS live CD */
72 #define CD_DEV "devices/\\hw\\pci0\\00:01.0\\ata-c2\\d0"
74 #define CD_FS_TYPE "cdfs"
75 #define CD_FS_SRV "/srv/cdfs"
76 #define CD_MOUNT_POINT "/cdrom"
78 #define BOOT_FILES_SRC "/cdrom"
79 #define BOOT_BLOCK_IDX 0 /* MBR */
81 /** Label the destination device.
83 * @param dev Disk device to label
84 * @param pdev Place to store partition device name
86 * @return EOK on success or an error code
88 static errno_t
sysinst_label_dev(const char *dev
, char **pdev
)
93 fdisk_part_spec_t pspec
;
98 printf("sysinst_label_dev(): get service ID '%s'\n", dev
);
99 rc
= loc_service_get_id(dev
, &sid
, 0);
103 printf("sysinst_label_dev(): open device\n");
105 rc
= fdisk_create(&fdisk
);
107 printf("Error initializing fdisk.\n");
111 rc
= fdisk_dev_open(fdisk
, sid
, &fdev
);
113 printf("Error opening device.\n");
117 printf("sysinst_label_dev(): create label\n");
119 rc
= fdisk_label_create(fdev
, lt_mbr
);
121 printf("Error creating label: %s.\n", str_error(rc
));
125 printf("sysinst_label_dev(): create partition\n");
127 rc
= fdisk_part_get_max_avail(fdev
, spc_pri
, &cap
);
129 printf("Error getting available capacity: %s.\n", str_error(rc
));
133 fdisk_pspec_init(&pspec
);
134 pspec
.capacity
= cap
;
135 pspec
.pkind
= lpk_primary
;
136 pspec
.fstype
= fs_minix
;
138 rc
= fdisk_part_create(fdev
, &pspec
, &part
);
140 printf("Error creating partition.\n");
144 /* XXX libfdisk should give us the service name */
145 if (asprintf(pdev
, "%sp1", dev
) < 0)
148 printf("sysinst_label_dev(): OK\n");
152 /** Mount target file system.
154 * @param dev Partition device
155 * @return EOK on success or an error code
157 static errno_t
sysinst_fs_mount(const char *dev
)
164 printf("sysinst_fs_mount(): start filesystem server\n");
165 rc
= task_spawnl(NULL
, &twait
, FS_SRV
, FS_SRV
, NULL
);
169 printf("sysinst_fs_mount(): wait for filesystem server\n");
170 rc
= task_wait(&twait
, &texit
, &trc
);
174 printf("sysinst_fs_mount(): verify filesystem server result\n");
175 if (texit
!= TASK_EXIT_NORMAL
|| trc
!= 0) {
176 printf("sysinst_fs_mount(): not successful, but could be already loaded.\n");
179 rc
= vfs_link_path(MOUNT_POINT
, KIND_DIRECTORY
, NULL
);
183 printf("sysinst_fs_mount(): mount filesystem\n");
184 rc
= vfs_mount_path(MOUNT_POINT
, FS_TYPE
, dev
, "", 0, 0);
188 printf("sysinst_fs_mount(): OK\n");
194 * @return EOK on success or an error code
196 static errno_t
sysinst_copy_boot_files(void)
203 printf("sysinst_copy_boot_files(): start filesystem server\n");
204 rc
= task_spawnl(NULL
, &twait
, CD_FS_SRV
, CD_FS_SRV
, NULL
);
208 printf("sysinst_copy_boot_files(): wait for filesystem server\n");
209 rc
= task_wait(&twait
, &texit
, &trc
);
213 printf("sysinst_copy_boot_files(): verify filesystem server result\n");
214 if (texit
!= TASK_EXIT_NORMAL
|| trc
!= 0) {
215 printf("sysinst_fs_mount(): not successful, but could be already loaded.\n");
218 printf("sysinst_copy_boot_files(): create CD mount point\n");
219 rc
= vfs_link_path(CD_MOUNT_POINT
, KIND_DIRECTORY
, NULL
);
223 printf("sysinst_copy_boot_files(): mount CD filesystem\n");
224 rc
= vfs_mount_path(CD_MOUNT_POINT
, CD_FS_TYPE
, CD_DEV
, "", 0, 0);
228 printf("sysinst_copy_boot_files(): copy bootloader files\n");
229 rc
= futil_rcopy_contents(BOOT_FILES_SRC
, MOUNT_POINT
);
233 printf("sysinst_copy_boot_files(): unmount %s\n", MOUNT_POINT
);
234 rc
= vfs_unmount_path(MOUNT_POINT
);
238 printf("sysinst_copy_boot_files(): OK\n");
242 /** Write unaligned 64-bit little-endian number.
244 * @param a Destination buffer
247 static void set_unaligned_u64le(uint8_t *a
, uint64_t data
)
251 for (i
= 0; i
< 8; i
++) {
252 a
[i
] = (data
>> (i
* 8)) & 0xff;
256 /** Copy boot blocks.
258 * Install Grub's boot blocks.
260 * @param devp Disk device
261 * @return EOK on success or an error code
263 static errno_t
sysinst_copy_boot_blocks(const char *devp
)
266 size_t boot_img_size
;
268 size_t core_img_size
;
273 aoff64_t core_blocks
;
274 grub_boot_blocklist_t
*first_bl
, *bl
;
277 printf("sysinst_copy_boot_blocks: Read boot block image.\n");
278 rc
= futil_get_file(BOOT_FILES_SRC
"/boot/grub/i386-pc/boot.img",
279 &boot_img
, &boot_img_size
);
280 if (rc
!= EOK
|| boot_img_size
!= 512)
283 printf("sysinst_copy_boot_blocks: Read GRUB core image.\n");
284 rc
= futil_get_file(BOOT_FILES_SRC
"/boot/grub/i386-pc/core.img",
285 &core_img
, &core_img_size
);
289 printf("sysinst_copy_boot_blocks: get service ID.\n");
290 rc
= loc_service_get_id(devp
, &sid
, 0);
294 printf("sysinst_copy_boot_blocks: block_init.\n");
295 rc
= block_init(sid
, 512);
299 printf("sysinst_copy_boot_blocks: get block size\n");
300 rc
= block_get_bsize(sid
, &bsize
);
305 printf("Device block size != 512.\n");
309 printf("sysinst_copy_boot_blocks: read boot block\n");
310 rc
= block_read_direct(sid
, BOOT_BLOCK_IDX
, 1, bbuf
);
315 core_blocks
= (core_img_size
+ 511) / 512;
317 /* Clean blocklists */
318 first_bl
= core_img
+ 512 - sizeof(*first_bl
);
320 while (bl
->len
!= 0) {
321 memset(bl
, 0, sizeof(*bl
));
323 if ((void *)bl
< core_img
) {
324 printf("No block terminator in core image.\n");
329 first_bl
->start
= host2uint64_t_le(core_start
+ 1);
330 first_bl
->len
= host2uint16_t_le(core_blocks
- 1);
331 first_bl
->segment
= grub_boot_i386_pc_kernel_seg
+ (512 >> 4);
333 /* Write boot code into boot block */
334 memcpy(bbuf
, boot_img
, 440); /* XXX 440 = sizeof(br_block_t.code_area) */
335 bbuf
[grub_boot_machine_boot_drive
] = 0xff;
336 set_unaligned_u64le(bbuf
+ grub_boot_machine_kernel_sector
, core_start
);
338 printf("sysinst_copy_boot_blocks: write boot block\n");
339 rc
= block_write_direct(sid
, BOOT_BLOCK_IDX
, 1, bbuf
);
343 printf("sysinst_copy_boot_blocks: write boot block\n");
344 /* XXX Must pad last block with zeros */
345 rc
= block_write_direct(sid
, core_start
, core_blocks
, core_img
);
349 printf("sysinst_copy_boot_blocks: OK.\n");
353 /** Install system to a device.
355 * @param dev Device to install to.
356 * @return EOK on success or an error code
358 static errno_t
sysinst_install(const char *dev
)
363 rc
= sysinst_label_dev(dev
, &pdev
);
367 printf("Partition '%s'. Mount it.\n", pdev
);
368 rc
= sysinst_fs_mount(pdev
);
374 printf("FS created and mounted. Copying boot files.\n");
375 rc
= sysinst_copy_boot_files();
379 printf("Boot files done. Installing boot blocks.\n");
380 rc
= sysinst_copy_boot_blocks(dev
);
387 int main(int argc
, char *argv
[])
389 const char *dev
= DEFAULT_DEV
;
390 return sysinst_install(dev
);