From 012d7999fe5d299e12003b43d80f56815768197f Mon Sep 17 00:00:00 2001 From: okuji Date: Thu, 2 Jan 2003 23:46:21 +0000 Subject: [PATCH] 2003-01-03 Yoshinori K. Okuji * util/i386/pc/pupa-setup.c (setup): Define the internal function find_first_partition_start at the top level, because GCC 3.0.x cannot compile internal functions in deeper scopes correctly. (find_root_device): Use lstat instead of stat. Don't follow symbolic links. Fix the path-constructing code. * util/i386/pc/biosdisk.c [__linux__] (BLKFLSBUF): New macro. (pupa_util_biosdisk_open) [__linux__]: Get the size of a device by a BLKGETSIZE ioctl first, because block devices don't fill the member st_mode of the structure stat on Linux. [__linux__] (linux_find_partition): Use a temporary buffer REAL_DEV for the working space. Copy it to DEV before returning. (open_device) [__linux__]: Call ioctl with BLKFLSBUF to make the buffer cache consistent. (get_os_disk) [__linux__]: Use the length 5 instead of 4 for strncmp. The previous value was merely wrong. (pupa_util_biosdisk_get_pupa_dev): Use stat instead of lstat. * fs/fat.c (pupa_fat_read_data): Shift 4 instead of 12 when the FAT size is 12. The previous value was merely wrong. * kern/main.c (pupa_main): Don't split the starting message from newlines. * kern/term.c (pupa_putchar): Put CR after LF instead of before LF, because BIOS goes crazy about character attributes in this case. --- ChangeLog | 32 ++++++++++++ NEWS | 3 ++ fs/fat.c | 12 +++-- kern/i386/pc/startup.S | 6 +-- kern/main.c | 3 +- kern/term.c | 7 +-- util/i386/pc/biosdisk.c | 107 +++++++++++++++++++++++++++++++------- util/i386/pc/grub-setup.c | 71 ++++++++++++++++++------- 8 files changed, 191 insertions(+), 50 deletions(-) diff --git a/ChangeLog b/ChangeLog index 04132a1e1..2b4e8264f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2003-01-03 Yoshinori K. Okuji + + * util/i386/pc/pupa-setup.c (setup): Define the internal + function find_first_partition_start at the top level, because GCC + 3.0.x cannot compile internal functions in deeper scopes + correctly. + (find_root_device): Use lstat instead of stat. + Don't follow symbolic links. + Fix the path-constructing code. + + * util/i386/pc/biosdisk.c [__linux__] (BLKFLSBUF): New macro. + (pupa_util_biosdisk_open) [__linux__]: Get the size of a device + by a BLKGETSIZE ioctl first, because block devices don't fill + the member st_mode of the structure stat on Linux. + [__linux__] (linux_find_partition): Use a temporary buffer + REAL_DEV for the working space. Copy it to DEV before returning. + (open_device) [__linux__]: Call ioctl with BLKFLSBUF to make the + buffer cache consistent. + (get_os_disk) [__linux__]: Use the length 5 instead of 4 for + strncmp. The previous value was merely wrong. + (pupa_util_biosdisk_get_pupa_dev): Use stat instead of lstat. + + * fs/fat.c (pupa_fat_read_data): Shift 4 instead of 12 when the + FAT size is 12. The previous value was merely wrong. + + * kern/main.c (pupa_main): Don't split the starting message from + newlines. + + * kern/term.c (pupa_putchar): Put CR after LF instead of before + LF, because BIOS goes crazy about character attributes in this + case. + 2003-01-03 Yoshinori K. Okuji * include/i386/pc/util/biosdisk.h: New file. diff --git a/NEWS b/NEWS index e026778a4..3944a66f0 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,9 @@ New in 0.7: care when writing assembly code. See the comments at the beginning of startup.S, for more details. +* New utility, ``pupa-setup''. This sets up PUPA to make it bootable + from a real disk. + New in 0.6 - 2002-12-27, Yoshinori K. Okuji: * The chainloader and the FAT filesystem are modularized. diff --git a/fs/fat.c b/fs/fat.c index 1c8a05738..045c04b6c 100644 --- a/fs/fat.c +++ b/fs/fat.c @@ -156,7 +156,7 @@ pupa_fat_mount (pupa_disk_t disk) data = (struct pupa_fat_data *) pupa_malloc (sizeof (*data)); if (! data) goto fail; - + /* Read the BPB. */ if (pupa_disk_read (disk, 0, 0, sizeof (bpb), (char *) &bpb)) goto fail; @@ -437,19 +437,25 @@ pupa_fat_read_data (pupa_disk_t disk, struct pupa_fat_data *data, break; case 12: if (data->cur_cluster & 1) - next_cluster >>= 12; + next_cluster >>= 4; next_cluster &= 0x0FFF; break; } +#if 0 + pupa_printf ("%s:%d: fat_size=%d, next_cluster=%u\n", + __FILE__, __LINE__, data->fat_size, next_cluster); +#endif + /* Check the end. */ if (next_cluster >= data->cluster_eof_mark) return ret; if (next_cluster < 2 || next_cluster >= data->num_clusters) { - pupa_error (PUPA_ERR_BAD_FS, "invalid cluster"); + pupa_error (PUPA_ERR_BAD_FS, "invalid cluster %u", + next_cluster); return -1; } diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index 5e6d55604..0fdc65681 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -991,8 +991,8 @@ FUNCTION(pupa_console_putchar) int $0x10 jmp 3f - -1: movb $0x7, %bl + +1: movw $1, %bx movb $0xe, %ah int $0x10 @@ -1001,7 +1001,7 @@ FUNCTION(pupa_console_putchar) popa ret - + /* * int pupa_console_getkey (void) diff --git a/kern/main.c b/kern/main.c index 2862e52cb..256a084d3 100644 --- a/kern/main.c +++ b/kern/main.c @@ -67,9 +67,8 @@ pupa_main (void) /* Hello. */ pupa_setcolorstate (PUPA_TERM_COLOR_HIGHLIGHT); - pupa_printf ("Welcome to PUPA!"); + pupa_printf ("Welcome to PUPA!\n\n"); pupa_setcolorstate (PUPA_TERM_COLOR_STANDARD); - pupa_printf ("\n\n"); pupa_register_exported_symbols (); pupa_load_modules (); diff --git a/kern/term.c b/kern/term.c index 509e5c8e1..6082e389a 100644 --- a/kern/term.c +++ b/kern/term.c @@ -73,9 +73,7 @@ pupa_term_get_current (void) void pupa_putchar (int c) { - if (c == '\n') - pupa_putchar ('\r'); - else if (c == '\t' && pupa_cur_term->getxy) + if (c == '\t' && pupa_cur_term->getxy) { int n; @@ -87,6 +85,9 @@ pupa_putchar (int c) } (pupa_cur_term->putchar) (c); + + if (c == '\n') + pupa_putchar ('\r'); } int diff --git a/util/i386/pc/biosdisk.c b/util/i386/pc/biosdisk.c index 59495bacd..9ad1e558b 100644 --- a/util/i386/pc/biosdisk.c +++ b/util/i386/pc/biosdisk.c @@ -66,6 +66,9 @@ struct hd_geometry unsigned long start; }; # endif /* ! HDIO_GETGEO */ +# ifndef BLKGETSIZE +# define BLKGETSIZE _IO(0x12,96) /* return device size */ +# endif /* ! BLKGETSIZE */ # ifndef MAJOR # ifndef MINORBITS # define MINORBITS 8 @@ -165,7 +168,34 @@ pupa_util_biosdisk_open (const char *name, pupa_disk_t disk) disk->id = drive; /* Get the size. */ - if (lstat (map[drive], &st) < 0) +#ifdef __linux__ + { + unsigned long nr; + int fd; + + fd = open (map[drive], O_RDONLY); + if (! fd) + return pupa_error (PUPA_ERR_BAD_DEVICE, "cannot open `%s'", map[drive]); + + if (ioctl (fd, BLKGETSIZE, &nr)) + { + close (fd); + goto fail; + } + + close (fd); + disk->total_sectors = nr; + + pupa_util_info ("the size of %s is %lu", name, disk->total_sectors); + + return PUPA_ERR_NONE; + } +#else +# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal." +#endif + + fail: + if (stat (map[drive], &st) < 0) return pupa_error (PUPA_ERR_BAD_DEVICE, "cannot stat `%s'", map[drive]); if (st.st_blocks) @@ -174,6 +204,8 @@ pupa_util_biosdisk_open (const char *name, pupa_disk_t disk) /* Hmm... Use st_size instead. */ disk->total_sectors = st.st_size >> PUPA_DISK_SECTOR_BITS; + pupa_util_info ("the size of %s is %lu", name, disk->total_sectors); + return PUPA_ERR_NONE; } @@ -185,22 +217,25 @@ linux_find_partition (char *dev, unsigned long sector) const char *format; char *p; int i; + char *real_dev; + + real_dev = xstrdup (dev); - if (have_devfs () && strcmp (dev + len - 5, "/disc") == 0) + if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0) { - p = dev + len - 4; + p = real_dev + len - 4; format = "part%d"; } - else if ((strncmp (dev + 5, "hd", 2) == 0 - || strncmp (dev + 5, "sd", 2) == 0) - && dev[7] >= 'a' && dev[7] <= 'z') + else if ((strncmp (real_dev + 5, "hd", 2) == 0 + || strncmp (real_dev + 5, "sd", 2) == 0) + && real_dev[7] >= 'a' && real_dev[7] <= 'z') { - p = dev + 8; + p = real_dev + 8; format = "%d"; } - else if (strncmp (dev + 5, "rd/c", 4) == 0) + else if (strncmp (real_dev + 5, "rd/c", 4) == 0) { - p = strchr (dev + 9, 'd'); + p = strchr (real_dev + 9, 'd'); if (! p) return 0; @@ -211,30 +246,42 @@ linux_find_partition (char *dev, unsigned long sector) format = "p%d"; } else - return 0; + { + free (real_dev); + return 0; + } - for (i = 0; i < 10000; i++) + for (i = 1; i < 10000; i++) { int fd; struct hd_geometry hdg; sprintf (p, format, i); - fd = open (dev, O_RDONLY); + fd = open (real_dev, O_RDONLY); if (! fd) - return 0; + { + free (real_dev); + return 0; + } if (ioctl (fd, HDIO_GETGEO, &hdg)) { close (fd); + free (real_dev); return 0; } close (fd); if (hdg.start == sector) - return 1; + { + strcpy (dev, real_dev); + free (real_dev); + return 1; + } } + free (real_dev); return 0; } #endif /* __linux__ */ @@ -266,12 +313,16 @@ open_device (const pupa_disk_t disk, unsigned long sector, int flags) is_partition = linux_find_partition (dev, disk->partition->start); /* Open the partition. */ + pupa_util_info ("opening the device `%s'", dev); fd = open (dev, flags); if (fd < 0) { pupa_error (PUPA_ERR_BAD_DEVICE, "cannot open `%s'", dev); return -1; } + + /* Make the buffer cache consistent with the physical disk. */ + ioctl (fd, BLKFLSBUF, 0); if (is_partition) sector -= disk->partition->start; @@ -560,9 +611,9 @@ get_os_disk (const char *os_dev) if (! realpath (os_dev, path)) return 0; - if (strncmp ("/dev/", path, 4) == 0) + if (strncmp ("/dev/", path, 5) == 0) { - p = path + 4; + p = path + 5; if (have_devfs ()) { @@ -653,8 +704,8 @@ pupa_util_biosdisk_get_pupa_dev (const char *os_dev) { struct stat st; int drive; - - if (lstat (os_dev, &st) < 0) + + if (stat (os_dev, &st) < 0) { pupa_error (PUPA_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev); return 0; @@ -687,6 +738,14 @@ pupa_util_biosdisk_get_pupa_dev (const char *os_dev) int find_partition (const pupa_partition_t partition) { + if (partition->bsd_part < 0) + pupa_util_info ("DOS partition %d starts from %lu", + partition->dos_part, partition->start); + else + pupa_util_info ("BSD partition %d,%c starts from %lu", + partition->dos_part, partition->bsd_part + 'a', + partition->start); + if (hdg.start == partition->start) { dos_part = partition->dos_part; @@ -720,17 +779,25 @@ pupa_util_biosdisk_get_pupa_dev (const char *os_dev) } close (fd); + + pupa_util_info ("%s starts from %lu", os_dev, hdg.start); if (hdg.start == 0) return name; - + + pupa_util_info ("opening the device %s", name); disk = pupa_disk_open (name); free (name); if (! disk) return 0; - pupa_partition_iterate (disk, find_partition); + if (pupa_partition_iterate (disk, find_partition) != PUPA_ERR_NONE) + { + pupa_disk_close (disk); + return 0; + } + if (dos_part < 0) { pupa_disk_close (disk); diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 7c4390b0c..b4b123c44 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -82,12 +82,25 @@ setup (const char *prefix, const char *dir, pupa_uint16_t last_length = PUPA_DISK_SECTOR_SIZE; pupa_file_t file; FILE *fp; + unsigned long first_start = ~0UL; auto void save_first_sector (unsigned long sector, unsigned offset, unsigned length); auto void save_blocklists (unsigned long sector, unsigned offset, unsigned length); + auto int find_first_partition_start (const pupa_partition_t p); + + int find_first_partition_start (const pupa_partition_t p) + { + if (! pupa_partition_is_empty (p->dos_type) + && ! pupa_partition_is_bsd (p->dos_type) + && first_start > p->start) + first_start = p->start; + + return 0; + } + void save_first_sector (unsigned long sector, unsigned offset, unsigned length) { @@ -195,23 +208,10 @@ setup (const char *prefix, const char *dir, try to embed the core image into after the MBR. */ if (dest_dev->disk->has_partitions && ! dest_dev->disk->partition) { - auto int find_first_partition_start (const pupa_partition_t p); - unsigned long first_sector = ~0UL; - - int find_first_partition_start (const pupa_partition_t p) - { - if (! pupa_partition_is_empty (p->dos_type) - && ! pupa_partition_is_bsd (p->dos_type) - && first_sector > p->start) - first_sector = p->start; - - return 0; - } - pupa_partition_iterate (dest_dev->disk, find_first_partition_start); /* If there is enough space... */ - if ((unsigned long) core_sectors + 1 <= first_sector) + if ((unsigned long) core_sectors + 1 <= first_start) { pupa_util_info ("will embed the core image into after the MBR"); @@ -277,7 +277,28 @@ setup (const char *prefix, const char *dir, pupa_util_info ("succeeded in opening the core image but cannot read %d bytes", (int) core_size); else if (memcmp (core_img, tmp_img, core_size) != 0) - pupa_util_info ("succeeded in opening the core image but the data is different"); + { +#if 0 + FILE *dump; + FILE *dump2; + + dump = fopen ("dump.img", "wb"); + if (dump) + { + fwrite (tmp_img, 1, core_size, dump); + fclose (dump); + } + + dump2 = fopen ("dump2.img", "wb"); + if (dump2) + { + fwrite (core_img, 1, core_size, dump2); + fclose (dump2); + } + +#endif + pupa_util_info ("succeeded in opening the core image but the data is different"); + } else { pupa_file_close (file); @@ -288,6 +309,9 @@ setup (const char *prefix, const char *dir, } else pupa_util_info ("couldn't open the core image"); + + if (pupa_errno) + pupa_util_info ("error message = %s", pupa_errmsg); pupa_errno = PUPA_ERR_NONE; sync (); @@ -530,6 +554,7 @@ find_root_device (const char *dir, dev_t dev) saved_cwd = xgetcwd (); + pupa_util_info ("changing current directory to %s", dir); if (chdir (dir) < 0) { free (saved_cwd); @@ -544,10 +569,14 @@ find_root_device (const char *dir, dev_t dev) if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) continue; - if (stat (ent->d_name, &st) < 0) + if (lstat (ent->d_name, &st) < 0) /* Ignore any error. */ continue; + if (S_ISLNK (st.st_mode)) + /* Don't follow symbolic links. */ + continue; + if (S_ISDIR (st.st_mode)) { /* Find it recursively. */ @@ -570,11 +599,13 @@ find_root_device (const char *dir, dev_t dev) { /* Found! */ char *res; + char *cwd; - res = xmalloc (strlen (saved_cwd) + strlen (dir) - + strlen (ent->d_name) + 3); - sprintf (res, "%s/%s/%s", saved_cwd, dir, ent->d_name); + cwd = xgetcwd (); + res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 2); + sprintf (res, "%s/%s", cwd, ent->d_name); strip_extra_slashes (res); + free (cwd); if (chdir (saved_cwd) < 0) pupa_util_error ("Cannot restore the original directory"); @@ -731,6 +762,8 @@ main (int argc, char *argv[]) root_dev = guess_root_device (dir ? : DEFAULT_DIRECTORY); if (! root_dev) { + pupa_util_info ("guessing the root device failed, because of `%s'", + pupa_errmsg); pupa_util_error ("Cannot guess the root device. Specify the option ``--root-device''."); } }