diff --git a/ChangeLog b/ChangeLog index 878037f2a..04132a1e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,51 @@ +2003-01-03 Yoshinori K. Okuji + + * include/i386/pc/util/biosdisk.h: New file. + * util/i386/pc/biosdisk.c: Likewise. + * util/i386/pc/pupa-setup.c: Likewise. + + * Makefile.in (INCLUDE_DISTFILES): Added + include/pupa/i386/pc/util/biosdisk.h. + (UTIL_DISTFILES): Added biosdisk.c and pupa-setup.c under the + directory util/i386/pc. + (install-local): Added a rule for sbin_UTILITIES. + (uninstall): Likewise. + + * util/i386/pc/pupa-mkimage.c (usage): Fix a typo in the doc. + + * util/misc.c (xrealloc): New function. + (pupa_malloc): Likewise. + (pupa_free): Likewise. + (pupa_realloc): Likewise. + (pupa_stop): Likewise. + (pupa_putchar): Likewise. + + * kern/disk.c (pupa_disk_read): Prevent L from underflowing. + + * include/pupa/util/misc.h (xrealloc): Declared. + + * include/pupa/i386/pc/boot.h (PUPA_BOOT_MACHINE_BPB_START): New + macro. + (PUPA_BOOT_MACHINE_BPBEND): Renamed to ... + (PUPA_BOOT_MACHINE_BPB_END): ... this. + + * include/pupa/fs.h [PUPA_UTIL] (pupa_fat_init): Declared. + [PUPA_UTIL] (pupa_fat_fini): Likewise. + + * fs/fat.c [PUPA_UTIL] (pupa_fat_init): Defined. Maybe a better + way should be implemented. + [PUPA_UTIL] (pupa_fat_fini): Likewise. + + * disk/i386/pc/biosdisk.c (pupa_biosdisk_call_hook): Increase + the size of NAME for safety. + (pupa_biosdisk_iterate): Search hard disks to 0x90 instead of + 0x88. + + * conf/i386-pc.rmk (sbin_UTILITIES): New variable. + (pupa_setup_SOURCES): Likewise. + + * genmk.rb (Utility#rule): Add $(BUILD_CFLAGS) into the rules. + 2002-12-28 Yoshinori K. Okuji * kern/i386/pc/startup.S (push_get_mmap_entry): Revert to a diff --git a/Makefile.in b/Makefile.in index 81eb3db4e..f1451cac7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -93,7 +93,8 @@ INCLUDE_DISTFILES = $(addprefix include/pupa/,boot.h device.h disk.h \ $(addprefix include/pupa/util/,misc.h resolve.h) \ include/pupa/i386/types.h \ $(addprefix include/pupa/i386/pc/,biosdisk.h boot.h \ - console.h init.h kernel.h loader.h memory.h partition.h) + console.h init.h kernel.h loader.h memory.h partition.h) \ + $(addprefix include/pupa/i386/pc/util/,biosdisk.h) KERN_DISTFILES = $(addprefix kern/,device.c disk.c dl.c err.c file.c \ fs.c loader.c main.c misc.c mm.c rescue.c term.c) \ @@ -105,7 +106,8 @@ LOADER_DISTFILES = $(addprefix loader/i386/pc/,chainloader.c) TERM_DISTFILES = $(addprefix term/i386/pc/,console.c) UTIL_DISTFILES = $(addprefix util/,genmoddep.c misc.c resolve.c) \ - util/i386/pc/pupa-mkimage.c + $(addprefix util/i386/pc/,biosdisk.c pupa-mkimage.c \ + pupa-setup.c) DISTFILES = $(COMMON_DISTFILES) $(BOOT_DISTFILES) $(CONF_DISTFILES) \ $(DISK_DISTFILES) $(FS_DISTFILES) $(INCLUDE_DISTFILES) \ @@ -154,6 +156,12 @@ install-local: all dest="`echo $$file | sed 's,.*/,,'`"; \ $(INSTALL_PROGRAM) $$dir$$file $(DESTDIR)$(bindir)/$$dest; \ done + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_UTILITIES)'; for file in $$list; do \ + if test -f "$$file"; then dir=; else dir="$(srcdir)"; fi; \ + dest="`echo $$file | sed 's,.*/,,'`"; \ + $(INSTALL_PROGRAM) $$dir$$file $(DESTDIR)$(sbindir)/$$dest; \ + done install-strip: $(MAKE) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" install @@ -163,10 +171,14 @@ uninstall: dest="`echo $$file | sed 's,.*/,,'`"; \ rm -f $(DESTDIR)$(pkgdatadir)/$$dest; \ done - @list = '$(bin_UTILITIES)'; for file in $$list; do \ + @list='$(bin_UTILITIES)'; for file in $$list; do \ dest="`echo $$file | sed 's,.*/,,'`"; \ rm -f $(DESTDIR)$(bindir)/$$dest; \ done + @list='$(sbin_UTILITIES)'; for file in $$list; do \ + dest="`echo $$file | sed 's,.*/,,'`"; \ + rm -f $(DESTDIR)$(sbindir)/$$dest; \ + done clean: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) diff --git a/boot/i386/pc/boot.S b/boot/i386/pc/boot.S index dd3c66796..570ff76c0 100644 --- a/boot/i386/pc/boot.S +++ b/boot/i386/pc/boot.S @@ -84,7 +84,7 @@ cylinder_start: .word 0 /* more space... */ - . = _start + PUPA_BOOT_MACHINE_BPBEND + . = _start + PUPA_BOOT_MACHINE_BPB_END /* * End of BIOS parameter block. diff --git a/conf/i386-pc.mk b/conf/i386-pc.mk index 0f0575457..3744d0894 100644 --- a/conf/i386-pc.mk +++ b/conf/i386-pc.mk @@ -239,6 +239,7 @@ kernel_syms.lst: $(addprefix include/pupa/,$(kernel_img_HEADERS)) genkernsyms.sh # Utilities. bin_UTILITIES = pupa-mkimage +sbin_UTILITIES = pupa-setup noinst_UTILITIES = genmoddep # For pupa-mkimage. @@ -251,30 +252,129 @@ pupa-mkimage: pupa_mkimage-util_i386_pc_pupa_mkimage.o pupa_mkimage-util_misc.o $(BUILD_CC) $(BUILD_LDFLAGS) $(pupa_mkimage_LDFLAGS) -o $@ $^ pupa_mkimage-util_i386_pc_pupa_mkimage.o: util/i386/pc/pupa-mkimage.c - $(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -c -o $@ $< + $(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -c -o $@ $< pupa_mkimage-util_i386_pc_pupa_mkimage.d: util/i386/pc/pupa-mkimage.c - set -e; $(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -M $< | sed 's,pupa\-mkimage\.o[ :]*,pupa_mkimage-util_i386_pc_pupa_mkimage.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + set -e; $(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -M $< | sed 's,pupa\-mkimage\.o[ :]*,pupa_mkimage-util_i386_pc_pupa_mkimage.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ -include pupa_mkimage-util_i386_pc_pupa_mkimage.d pupa_mkimage-util_misc.o: util/misc.c - $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -c -o $@ $< + $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -c -o $@ $< pupa_mkimage-util_misc.d: util/misc.c - set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -M $< | sed 's,misc\.o[ :]*,pupa_mkimage-util_misc.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -M $< | sed 's,misc\.o[ :]*,pupa_mkimage-util_misc.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ -include pupa_mkimage-util_misc.d pupa_mkimage-util_resolve.o: util/resolve.c - $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -c -o $@ $< + $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -c -o $@ $< pupa_mkimage-util_resolve.d: util/resolve.c - set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -M $< | sed 's,resolve\.o[ :]*,pupa_mkimage-util_resolve.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -M $< | sed 's,resolve\.o[ :]*,pupa_mkimage-util_resolve.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ -include pupa_mkimage-util_resolve.d +# For pupa-setup. +pupa_setup_SOURCES = util/i386/pc/pupa-setup.c util/i386/pc/biosdisk.c \ + util/misc.c kern/device.c kern/disk.c kern/file.c kern/fs.c \ + kern/err.c kern/misc.c disk/i386/pc/partition.c fs/fat.c +CLEANFILES += pupa-setup pupa_setup-util_i386_pc_pupa_setup.o pupa_setup-util_i386_pc_biosdisk.o pupa_setup-util_misc.o pupa_setup-kern_device.o pupa_setup-kern_disk.o pupa_setup-kern_file.o pupa_setup-kern_fs.o pupa_setup-kern_err.o pupa_setup-kern_misc.o pupa_setup-disk_i386_pc_partition.o pupa_setup-fs_fat.o +MOSTLYCLEANFILES += pupa_setup-util_i386_pc_pupa_setup.d pupa_setup-util_i386_pc_biosdisk.d pupa_setup-util_misc.d pupa_setup-kern_device.d pupa_setup-kern_disk.d pupa_setup-kern_file.d pupa_setup-kern_fs.d pupa_setup-kern_err.d pupa_setup-kern_misc.d pupa_setup-disk_i386_pc_partition.d pupa_setup-fs_fat.d + +pupa-setup: pupa_setup-util_i386_pc_pupa_setup.o pupa_setup-util_i386_pc_biosdisk.o pupa_setup-util_misc.o pupa_setup-kern_device.o pupa_setup-kern_disk.o pupa_setup-kern_file.o pupa_setup-kern_fs.o pupa_setup-kern_err.o pupa_setup-kern_misc.o pupa_setup-disk_i386_pc_partition.o pupa_setup-fs_fat.o + $(BUILD_CC) $(BUILD_LDFLAGS) $(pupa_setup_LDFLAGS) -o $@ $^ + +pupa_setup-util_i386_pc_pupa_setup.o: util/i386/pc/pupa-setup.c + $(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-util_i386_pc_pupa_setup.d: util/i386/pc/pupa-setup.c + set -e; $(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,pupa\-setup\.o[ :]*,pupa_setup-util_i386_pc_pupa_setup.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-util_i386_pc_pupa_setup.d + +pupa_setup-util_i386_pc_biosdisk.o: util/i386/pc/biosdisk.c + $(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-util_i386_pc_biosdisk.d: util/i386/pc/biosdisk.c + set -e; $(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,biosdisk\.o[ :]*,pupa_setup-util_i386_pc_biosdisk.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-util_i386_pc_biosdisk.d + +pupa_setup-util_misc.o: util/misc.c + $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-util_misc.d: util/misc.c + set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,misc\.o[ :]*,pupa_setup-util_misc.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-util_misc.d + +pupa_setup-kern_device.o: kern/device.c + $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-kern_device.d: kern/device.c + set -e; $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,device\.o[ :]*,pupa_setup-kern_device.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-kern_device.d + +pupa_setup-kern_disk.o: kern/disk.c + $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-kern_disk.d: kern/disk.c + set -e; $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,disk\.o[ :]*,pupa_setup-kern_disk.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-kern_disk.d + +pupa_setup-kern_file.o: kern/file.c + $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-kern_file.d: kern/file.c + set -e; $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,file\.o[ :]*,pupa_setup-kern_file.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-kern_file.d + +pupa_setup-kern_fs.o: kern/fs.c + $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-kern_fs.d: kern/fs.c + set -e; $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,fs\.o[ :]*,pupa_setup-kern_fs.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-kern_fs.d + +pupa_setup-kern_err.o: kern/err.c + $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-kern_err.d: kern/err.c + set -e; $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,err\.o[ :]*,pupa_setup-kern_err.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-kern_err.d + +pupa_setup-kern_misc.o: kern/misc.c + $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-kern_misc.d: kern/misc.c + set -e; $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,misc\.o[ :]*,pupa_setup-kern_misc.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-kern_misc.d + +pupa_setup-disk_i386_pc_partition.o: disk/i386/pc/partition.c + $(BUILD_CC) -Idisk/i386/pc -I$(srcdir)/disk/i386/pc $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-disk_i386_pc_partition.d: disk/i386/pc/partition.c + set -e; $(BUILD_CC) -Idisk/i386/pc -I$(srcdir)/disk/i386/pc $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,partition\.o[ :]*,pupa_setup-disk_i386_pc_partition.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-disk_i386_pc_partition.d + +pupa_setup-fs_fat.o: fs/fat.c + $(BUILD_CC) -Ifs -I$(srcdir)/fs $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -c -o $@ $< + +pupa_setup-fs_fat.d: fs/fat.c + set -e; $(BUILD_CC) -Ifs -I$(srcdir)/fs $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(pupa_setup_CFLAGS) -M $< | sed 's,fat\.o[ :]*,pupa_setup-fs_fat.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include pupa_setup-fs_fat.d + + # For genmoddep. genmoddep_SOURCES = util/genmoddep.c CLEANFILES += genmoddep genmoddep-util_genmoddep.o @@ -284,10 +384,10 @@ genmoddep: genmoddep-util_genmoddep.o $(BUILD_CC) $(BUILD_LDFLAGS) $(genmoddep_LDFLAGS) -o $@ $^ genmoddep-util_genmoddep.o: util/genmoddep.c - $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(genmoddep_CFLAGS) -c -o $@ $< + $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(genmoddep_CFLAGS) -c -o $@ $< genmoddep-util_genmoddep.d: util/genmoddep.c - set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(genmoddep_CFLAGS) -M $< | sed 's,genmoddep\.o[ :]*,genmoddep-util_genmoddep.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(genmoddep_CFLAGS) -M $< | sed 's,genmoddep\.o[ :]*,genmoddep-util_genmoddep.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ -include genmoddep-util_genmoddep.d diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index b5a503914..cfa6550d7 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -44,12 +44,18 @@ kernel_syms.lst: $(addprefix include/pupa/,$(kernel_img_HEADERS)) genkernsyms.sh # Utilities. bin_UTILITIES = pupa-mkimage +sbin_UTILITIES = pupa-setup noinst_UTILITIES = genmoddep # For pupa-mkimage. pupa_mkimage_SOURCES = util/i386/pc/pupa-mkimage.c util/misc.c \ util/resolve.c +# For pupa-setup. +pupa_setup_SOURCES = util/i386/pc/pupa-setup.c util/i386/pc/biosdisk.c \ + util/misc.c kern/device.c kern/disk.c kern/file.c kern/fs.c \ + kern/err.c kern/misc.c disk/i386/pc/partition.c fs/fat.c + # For genmoddep. genmoddep_SOURCES = util/genmoddep.c diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c index af14c10fa..a88248863 100644 --- a/disk/i386/pc/biosdisk.c +++ b/disk/i386/pc/biosdisk.c @@ -92,7 +92,7 @@ pupa_biosdisk_get_drive (const char *name) static int pupa_biosdisk_call_hook (int (*hook) (const char *name), int drive) { - char name[4]; + char name[10]; pupa_sprintf (name, (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); return hook (name); @@ -111,7 +111,7 @@ pupa_biosdisk_iterate (int (*hook) (const char *name)) return 1; /* For hard disks, attempt to read the MBR. */ - for (drive = 0x80; drive < 0x88; drive++) + for (drive = 0x80; drive < 0x90; drive++) { if (pupa_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1, PUPA_MEMORY_MACHINE_SCRATCH_SEG) != 0) diff --git a/fs/fat.c b/fs/fat.c index 70abadcdb..1c8a05738 100644 --- a/fs/fat.c +++ b/fs/fat.c @@ -745,12 +745,20 @@ static struct pupa_fs pupa_fat_fs = .next = 0 }; +#ifdef PUPA_UTIL +void pupa_fat_init (void) +#else PUPA_MOD_INIT +#endif { pupa_fs_register (&pupa_fat_fs); } +#ifdef PUPA_UTIL +void pupa_fat_fini (void) +#else PUPA_MOD_FINI +#endif { pupa_fs_unregister (&pupa_fat_fs); } diff --git a/genmk.rb b/genmk.rb index 96516e7ba..a48aa04bd 100644 --- a/genmk.rb +++ b/genmk.rb @@ -190,11 +190,11 @@ MOSTLYCLEANFILES += #{deps_str} dir = File.dirname(src) "#{obj}: #{src} - $(BUILD_CC) -I#{dir} -I$(srcdir)/#{dir} $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(#{prefix}_CFLAGS) -c -o $@ $< + $(BUILD_CC) -I#{dir} -I$(srcdir)/#{dir} $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(#{prefix}_CFLAGS) -c -o $@ $< #{dep}: #{src} set -e; \ - $(BUILD_CC) -I#{dir} -I$(srcdir)/#{dir} $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(#{prefix}_CFLAGS) -M $< \ + $(BUILD_CC) -I#{dir} -I$(srcdir)/#{dir} $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DPUPA_UTIL=1 $(#{prefix}_CFLAGS) -M $< \ | sed 's,#{Regexp.quote(fake_obj)}[ :]*,#{obj} $@ : ,g' > $@; \ [ -s $@ ] || rm -f $@ diff --git a/include/grub/fs.h b/include/grub/fs.h index 079bb68a9..406c21bb8 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -60,4 +60,9 @@ void EXPORT_FUNC(pupa_fs_unregister) (pupa_fs_t fs); void EXPORT_FUNC(pupa_fs_iterate) (int (*hook) (const pupa_fs_t fs)); pupa_fs_t EXPORT_FUNC(pupa_fs_probe) (pupa_device_t device); +#ifdef PUPA_UTIL +void pupa_fat_init (void); +void pupa_fat_fini (void); +#endif /* PUPA_UTIL */ + #endif /* ! PUPA_FS_HEADER */ diff --git a/include/grub/i386/pc/boot.h b/include/grub/i386/pc/boot.h index b269e72a0..6d08865f6 100644 --- a/include/grub/i386/pc/boot.h +++ b/include/grub/i386/pc/boot.h @@ -24,8 +24,11 @@ /* The signature for bootloader. */ #define PUPA_BOOT_MACHINE_SIGNATURE 0xaa55 +/* The offset of the start of BPB (BIOS Parameter Block). */ +#define PUPA_BOOT_MACHINE_BPB_START 0x3 + /* The offset of the end of BPB (BIOS Parameter Block). */ -#define PUPA_BOOT_MACHINE_BPBEND 0x3e +#define PUPA_BOOT_MACHINE_BPB_END 0x3e /* The offset of the major version. */ #define PUPA_BOOT_MACHINE_VER_MAJ 0x3e diff --git a/include/grub/i386/pc/util/biosdisk.h b/include/grub/i386/pc/util/biosdisk.h new file mode 100644 index 000000000..10d20ff23 --- /dev/null +++ b/include/grub/i386/pc/util/biosdisk.h @@ -0,0 +1,28 @@ +/* biosdisk.h - emulate biosdisk */ +/* + * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 2002 Yoshinori K. Okuji + * + * PUPA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PUPA; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef PUPA_BIOSDISK_MACHINE_UTIL_HEADER +#define PUPA_BIOSDISK_MACHINE_UTIL_HEADER 1 + +void pupa_util_biosdisk_init (const char *dev_map); +void pupa_util_biosdisk_fini (void); +char *pupa_util_biosdisk_get_pupa_dev (const char *os_dev); + +#endif /* ! PUPA_BIOSDISK_MACHINE_UTIL_HEADER */ diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h index 48bf0e961..10d0a47b2 100644 --- a/include/grub/util/misc.h +++ b/include/grub/util/misc.h @@ -30,6 +30,7 @@ void pupa_util_info (const char *fmt, ...); void pupa_util_error (const char *fmt, ...) __attribute__ ((noreturn)); void *xmalloc (size_t size); +void *xrealloc (void *ptr, size_t size); char *xstrdup (const char *str); char *pupa_util_get_path (const char *dir, const char *file); diff --git a/kern/disk.c b/kern/disk.c index 04e15432a..897e6a68e 100644 --- a/kern/disk.c +++ b/kern/disk.c @@ -396,6 +396,10 @@ pupa_disk_read (pupa_disk_t disk, unsigned long sector, ((l > PUPA_DISK_SECTOR_SIZE) ? PUPA_DISK_SECTOR_SIZE : l)); + + if (l < PUPA_DISK_SECTOR_SIZE - offset) + break; + s++; l -= PUPA_DISK_SECTOR_SIZE - offset; offset = 0; diff --git a/util/i386/pc/biosdisk.c b/util/i386/pc/biosdisk.c new file mode 100644 index 000000000..59495bacd --- /dev/null +++ b/util/i386/pc/biosdisk.c @@ -0,0 +1,776 @@ +/* biosdisk.c - emulate biosdisk */ +/* + * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. + * Copyright (C) 2002 Yoshinori K. Okuji + * + * PUPA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PUPA; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/* Try to use glibc's transparant LFS support. */ +#define _LARGEFILE_SOURCE 1 +/* lseek becomes synonymous with lseek64. */ +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +# include /* ioctl */ +# if !defined(__GLIBC__) || \ + ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) +/* Maybe libc doesn't have large file support. */ +# include /* _llseek */ +# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */ +# ifndef BLKFLSBUF +# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */ +# endif /* ! BLKFLSBUF */ +# include /* ioctl */ +# ifndef HDIO_GETGEO +# define HDIO_GETGEO 0x0301 /* get device geometry */ +/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is + defined. */ +struct hd_geometry +{ + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + unsigned long start; +}; +# endif /* ! HDIO_GETGEO */ +# ifndef MAJOR +# ifndef MINORBITS +# define MINORBITS 8 +# endif /* ! MINORBITS */ +# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS)) +# endif /* ! MAJOR */ +# ifndef FLOPPY_MAJOR +# define FLOPPY_MAJOR 2 +# endif /* ! FLOPPY_MAJOR */ +# ifndef LOOP_MAJOR +# define LOOP_MAJOR 7 +# endif /* ! LOOP_MAJOR */ +#endif /* __linux__ */ + +static char *map[256]; + +#ifdef __linux__ +/* Check if we have devfs support. */ +static int +have_devfs (void) +{ + static int dev_devfsd_exists = -1; + + if (dev_devfsd_exists < 0) + { + struct stat st; + + dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0; + } + + return dev_devfsd_exists; +} +#endif /* __linux__ */ + +static int +get_drive (const char *name) +{ + unsigned long drive; + char *p; + + if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd') + goto fail; + + drive = strtoul (name + 2, &p, 10); + if (p == name + 2) + goto fail; + + if (name[0] == 'h') + drive += 0x80; + + if (drive > sizeof (map) / sizeof (map[0])) + goto fail; + + return (int) drive; + + fail: + pupa_error (PUPA_ERR_UNKNOWN_DEVICE, "not a biosdisk"); + return -1; +} + +static int +call_hook (int (*hook) (const char *name), int drive) +{ + char name[10]; + + sprintf (name, (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); + return hook (name); +} + +static int +pupa_util_biosdisk_iterate (int (*hook) (const char *name)) +{ + unsigned i; + + for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) + if (map[i] && call_hook (hook, i)) + return 1; + + return 0; +} + +static pupa_err_t +pupa_util_biosdisk_open (const char *name, pupa_disk_t disk) +{ + int drive; + struct stat st; + + drive = get_drive (name); + if (drive < 0) + return pupa_errno; + + if (! map[drive]) + return pupa_error (PUPA_ERR_BAD_DEVICE, + "no mapping exists for `%s'", name); + + disk->has_partitions = (drive & 0x80); + disk->id = drive; + + /* Get the size. */ + if (lstat (map[drive], &st) < 0) + return pupa_error (PUPA_ERR_BAD_DEVICE, "cannot stat `%s'", map[drive]); + + if (st.st_blocks) + disk->total_sectors = st.st_blocks; + else + /* Hmm... Use st_size instead. */ + disk->total_sectors = st.st_size >> PUPA_DISK_SECTOR_BITS; + + return PUPA_ERR_NONE; +} + +#ifdef __linux__ +static int +linux_find_partition (char *dev, unsigned long sector) +{ + size_t len = strlen (dev); + const char *format; + char *p; + int i; + + if (have_devfs () && strcmp (dev + len - 5, "/disc") == 0) + { + p = 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') + { + p = dev + 8; + format = "%d"; + } + else if (strncmp (dev + 5, "rd/c", 4) == 0) + { + p = strchr (dev + 9, 'd'); + if (! p) + return 0; + + p++; + while (*p && isdigit (*p)) + p++; + + format = "p%d"; + } + else + return 0; + + for (i = 0; i < 10000; i++) + { + int fd; + struct hd_geometry hdg; + + sprintf (p, format, i); + fd = open (dev, O_RDONLY); + if (! fd) + return 0; + + if (ioctl (fd, HDIO_GETGEO, &hdg)) + { + close (fd); + return 0; + } + + close (fd); + + if (hdg.start == sector) + return 1; + } + + return 0; +} +#endif /* __linux__ */ + +static int +open_device (const pupa_disk_t disk, unsigned long sector, int flags) +{ + int fd; + +#ifdef O_LARGEFILE + flags |= O_LARGEFILE; +#endif +#ifdef O_SYNC + flags |= O_SYNC; +#endif +#ifdef O_FSYNC + flags |= O_FSYNC; +#endif + +#ifdef __linux__ + /* Linux has a bug that the disk cache for a whole disk is not consistent + with the one for a partition of the disk. */ + { + int is_partition = 0; + char dev[PATH_MAX]; + + strcpy (dev, map[disk->id]); + if (disk->partition && strncmp (map[disk->id], "/dev/", 5) == 0) + is_partition = linux_find_partition (dev, disk->partition->start); + + /* Open the partition. */ + fd = open (dev, flags); + if (fd < 0) + { + pupa_error (PUPA_ERR_BAD_DEVICE, "cannot open `%s'", dev); + return -1; + } + + if (is_partition) + sector -= disk->partition->start; + } +#else /* ! __linux__ */ + fd = open (map[disk->id], flags); + if (! fd) + { + pupa_error (PUPA_ERR_BAD_DEVICE, "cannot open `%s'", map[disk->id]); + return -1; + } +#endif /* ! __linux__ */ + +#if defined(__linux__) && (!defined(__GLIBC__) || \ + ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))) + /* Maybe libc doesn't have large file support. */ + { + loff_t offset, result; + static int _llseek (uint filedes, ulong hi, ulong lo, + loff_t *res, uint wh); + _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo, + loff_t *, res, uint, wh); + + offset = (loff_t) sector << PUPA_DISK_SECTOR_BITS; + if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET)) + { + pupa_error (PUPA_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id]); + close (fd); + return -1; + } + } +#else + { + off_t offset = (off_t) sector << PUPA_DISK_SECTOR_BITS; + + if (lseek (fd, offset, SEEK_SET) != offset) + { + pupa_error (PUPA_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id]); + close (fd); + return -1; + } + } +#endif + + return fd; +} + +/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an + error occurs, otherwise return LEN. */ +static ssize_t +nread (int fd, char *buf, size_t len) +{ + ssize_t size = len; + + while (len) + { + ssize_t ret = read (fd, buf, len); + + if (ret <= 0) + { + if (errno == EINTR) + continue; + else + return ret; + } + + len -= ret; + buf += ret; + } + + return size; +} + +/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an + error occurs, otherwise return LEN. */ +static ssize_t +nwrite (int fd, const char *buf, size_t len) +{ + ssize_t size = len; + + while (len) + { + ssize_t ret = write (fd, buf, len); + + if (ret <= 0) + { + if (errno == EINTR) + continue; + else + return ret; + } + + len -= ret; + buf += ret; + } + + return size; +} + +static pupa_err_t +pupa_util_biosdisk_read (pupa_disk_t disk, unsigned long sector, + unsigned long size, char *buf) +{ + int fd; + + fd = open_device (disk, sector, O_RDONLY); + if (fd < 0) + return pupa_errno; + +#ifdef __linux__ + if (sector == 0 && size > 1) + { + /* Work around a bug in linux's ez remapping. Linux remaps all + sectors that are read together with the MBR in one read. It + should only remap the MBR, so we split the read in two + parts. -jochen */ + if (nread (fd, buf, PUPA_DISK_SECTOR_SIZE) != PUPA_DISK_SECTOR_SIZE) + { + pupa_error (PUPA_ERR_READ_ERROR, "cannot read `%s'", map[disk->id]); + close (fd); + return pupa_errno; + } + + buf += PUPA_DISK_SECTOR_SIZE; + size--; + } +#endif /* __linux__ */ + + if (nread (fd, buf, size << PUPA_DISK_SECTOR_BITS) + != (ssize_t) (size << PUPA_DISK_SECTOR_BITS)) + pupa_error (PUPA_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id]); + + close (fd); + return pupa_errno; +} + +static pupa_err_t +pupa_util_biosdisk_write (pupa_disk_t disk, unsigned long sector, + unsigned long size, const char *buf) +{ + int fd; + + fd = open_device (disk, sector, O_WRONLY); + if (fd < 0) + return pupa_errno; + + if (nwrite (fd, buf, size << PUPA_DISK_SECTOR_BITS) + != (ssize_t) (size << PUPA_DISK_SECTOR_BITS)) + pupa_error (PUPA_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id]); + + close (fd); + return pupa_errno; +} + +static struct pupa_disk_dev pupa_util_biosdisk_dev = + { + .name = "biosdisk", + .iterate = pupa_util_biosdisk_iterate, + .open = pupa_util_biosdisk_open, + .close = 0, + .read = pupa_util_biosdisk_read, + .write = pupa_util_biosdisk_write, + .next = 0 + }; + +static void +read_device_map (const char *dev_map) +{ + FILE *fp; + char buf[1024]; /* XXX */ + int lineno = 0; + auto void show_error (const char *msg); + + void show_error (const char *msg) + { + pupa_util_error ("%s:%d: %s", dev_map, lineno, msg); + } + + fp = fopen (dev_map, "r"); + if (! fp) + pupa_util_error ("Cannot open `%s'", dev_map); + + while (fgets (buf, sizeof (buf), fp)) + { + char *p = buf; + char *e; + int drive; + + lineno++; + + /* Skip leading spaces. */ + while (*p && isspace (*p)) + p++; + + /* If the first character is `#' or NUL, skip this line. */ + if (*p == '\0' || *p == '#') + continue; + + if (*p != '(') + show_error ("No open parenthesis found"); + + p++; + drive = get_drive (p); + if (drive < 0 || drive >= (int) (sizeof (map) / sizeof (map[0]))) + show_error ("Bad device name"); + + p = strchr (p, ')'); + if (! p) + show_error ("No close parenthesis found"); + + p++; + /* Skip leading spaces. */ + while (*p && isspace (*p)) + p++; + + if (*p == '\0') + show_error ("No filename found"); + + /* NUL-terminate the filename. */ + e = p; + while (*e && ! isspace (*e)) + e++; + *e = '\0'; + + /* Multiple entries for a given drive is not allowed. */ + if (map[drive]) + show_error ("Duplicated entry found"); + +#ifdef __linux__ + /* On Linux, the devfs uses symbolic links horribly, and that + confuses the interface very much, so use realpath to expand + symbolic links. */ + map[drive] = xmalloc (PATH_MAX); + if (! realpath (p, map[drive])) + pupa_util_error ("Cannot get the real path of `%s'", p); +#else + map[drive] = xstrdup (p); +#endif + } + + fclose (fp); +} + +void +pupa_util_biosdisk_init (const char *dev_map) +{ + read_device_map (dev_map); + pupa_disk_dev_register (&pupa_util_biosdisk_dev); +} + +void +pupa_util_biosdisk_fini (void) +{ + unsigned i; + + for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) + free (map[i]); + + pupa_disk_dev_unregister (&pupa_util_biosdisk_dev); +} + +static char * +make_device_name (int drive, int dos_part, int bsd_part) +{ + char *p; + + p = xmalloc (30); + sprintf (p, (drive & 0x80) ? "hd%d" : "fd%d", drive & ~0x80); + + if (dos_part >= 0) + sprintf (p + strlen (p), ",%d", dos_part); + + if (bsd_part >= 0) + sprintf (p + strlen (p), ",%c", bsd_part + 'a'); + + return p; +} + +static char * +get_os_disk (const char *os_dev) +{ + char *path, *p; + +#if defined(__linux__) + path = xmalloc (PATH_MAX); + if (! realpath (os_dev, path)) + return 0; + + if (strncmp ("/dev/", path, 4) == 0) + { + p = path + 4; + + if (have_devfs ()) + { + /* If this is an IDE disk. */ + if (strncmp ("/dev/ide/", p, 9) == 0) + { + p = strstr (p, "part"); + if (p) + strcpy (p, "disc"); + + return path; + } + + /* If this is a SCSI disk. */ + if (strncmp ("/dev/scsi/", p, 10) == 0) + { + p = strstr (p, "part"); + if (p) + strcpy (p, "disc"); + + return path; + } + } + + /* If this is a DAC960 disk. */ + if (strncmp ("rd/c", p, 4) == 0) + { + /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + + /* If this is an IDE disk or a SCSI disk. */ + if ((strncmp ("hd", p, 2) == 0 + || strncmp ("sd", p, 2) == 0) + && p[2] >= 'a' && p[2] <= 'z') + { + /* /dev/[hs]d[a-z][0-9]* */ + p[3] = '\0'; + return path; + } + } + + return path; + +#elif defined(__GNU__) + path = xstrdup (os_dev); + if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0) + { + p = strchr (path, 's'); + if (p) + *p = '\0'; + } + return path; + +#else +# warning "The function `get_os_disk' might not work on your OS correctly." + return xstrdup (os_dev); +#endif +} + +static int +find_drive (const char *os_dev) +{ + int i; + char *os_disk; + + os_disk = get_os_disk (os_dev); + if (! os_disk) + return -1; + + for (i = 0; i < (int) (sizeof (map) / sizeof (map[0])); i++) + if (map[i] && strcmp (map[i], os_disk) == 0) + { + free (os_disk); + return i; + } + + free (os_disk); + return -1; +} + +char * +pupa_util_biosdisk_get_pupa_dev (const char *os_dev) +{ + struct stat st; + int drive; + + if (lstat (os_dev, &st) < 0) + { + pupa_error (PUPA_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev); + return 0; + } + + drive = find_drive (os_dev); + if (drive < 0) + { + pupa_error (PUPA_ERR_BAD_DEVICE, + "no mapping exists for `%s'", os_dev); + return 0; + } + + if (! S_ISBLK (st.st_mode)) + return make_device_name (drive, -1, -1); + +#if defined(__linux__) + /* Linux counts partitions uniformly, whether a BSD partition or a DOS + partition, so mapping them to PUPA devices is not trivial. + Here, get the start sector of a partition by HDIO_GETGEO, and + compare it with each partition PUPA recognizes. */ + { + char *name; + pupa_disk_t disk; + int fd; + struct hd_geometry hdg; + int dos_part = -1; + int bsd_part = -1; + auto int find_partition (const pupa_partition_t partition); + + int find_partition (const pupa_partition_t partition) + { + if (hdg.start == partition->start) + { + dos_part = partition->dos_part; + bsd_part = partition->bsd_part; + return 1; + } + + return 0; + } + + name = make_device_name (drive, -1, -1); + + if (MAJOR (st.st_rdev) == FLOPPY_MAJOR) + return name; + + fd = open (os_dev, O_RDONLY); + if (! fd) + { + pupa_error (PUPA_ERR_BAD_DEVICE, "cannot open `%s'", os_dev); + free (name); + return 0; + } + + if (ioctl (fd, HDIO_GETGEO, &hdg)) + { + pupa_error (PUPA_ERR_BAD_DEVICE, + "cannot get geometry of `%s'", os_dev); + close (fd); + free (name); + return 0; + } + + close (fd); + + if (hdg.start == 0) + return name; + + disk = pupa_disk_open (name); + free (name); + + if (! disk) + return 0; + + pupa_partition_iterate (disk, find_partition); + if (dos_part < 0) + { + pupa_disk_close (disk); + pupa_error (PUPA_ERR_BAD_DEVICE, + "cannot find the partition of `%s'", os_dev); + return 0; + } + + return make_device_name (drive, dos_part, bsd_part); + } + +#elif defined(__GNU__) + /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */ + { + char *p; + int dos_part = -1; + int bsd_part = -1; + + p = strrchr (os_dev, 's'); + if (p) + { + unsigned long n; + char *q; + + p++; + n = strtoul (p, &q, 10); + if (p != q && n != LONG_MIN && n != LONG_MAX) + { + dos_part = (int) n; + + if (*q >= 'a' && *q <= 'g') + bsd_part = *q - 'a'; + } + } + + return make_device_name (drive, dos_part, bsd_part); + } + +#else +# warning "The function `pupa_util_biosdisk_get_pupa_dev' might not work on your OS correctly." + return make_device_name (drive, -1, -1); +#endif +} diff --git a/util/i386/pc/grub-mkimage.c b/util/i386/pc/grub-mkimage.c index 68a28c510..0713a6647 100644 --- a/util/i386/pc/grub-mkimage.c +++ b/util/i386/pc/grub-mkimage.c @@ -145,7 +145,7 @@ Make a bootable image of PUPA.\n\ \n\ -d, --directory=DIR use images and modules under DIR [default=%s]\n\ -o, --output=FILE output a generated image to FILE [default=stdout]\n\ - -h, --help display this image and exit\n\ + -h, --help display this message and exit\n\ -V, --version print version information and exit\n\ -v, --verbose print verbose messages\n\ \n\ diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c new file mode 100644 index 000000000..7c4390b0c --- /dev/null +++ b/util/i386/pc/grub-setup.c @@ -0,0 +1,759 @@ +/* pupa-setup.c - make PUPA usable */ +/* + * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. + * Copyright (C) 2002 Yoshinori K. Okuji + * + * PUPA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PUPA; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define _GNU_SOURCE 1 +#include + +#define DEFAULT_BOOT_FILE "boot.img" +#define DEFAULT_CORE_FILE "core.img" + +#ifdef __NetBSD__ +/* NetBSD uses /boot for its boot block. */ +# define DEFAULT_DIRECTORY "/pupa" +#else +# define DEFAULT_DIRECTORY "/boot/pupa" +#endif + +#define DEFAULT_DEVICE_MAP DEFAULT_DIRECTORY "/device.map" + +/* This is the blocklist used in the diskboot image. */ +struct boot_blocklist +{ + pupa_uint32_t start; + pupa_uint16_t len; + pupa_uint16_t segment; +} __attribute__ ((packed)); + +static void +setup (const char *prefix, const char *dir, + const char *boot_file, const char *core_file, + const char *root, const char *dest) +{ + char *boot_path, *core_path; + char *boot_img, *core_img; + size_t boot_size, core_size; + pupa_uint16_t core_sectors; + pupa_device_t root_dev, dest_dev; + pupa_uint8_t *boot_drive; + pupa_uint32_t *kernel_sector; + struct boot_blocklist *first_block, *block; + char *tmp_img; + int i; + unsigned long first_sector; + pupa_uint16_t current_segment + = PUPA_BOOT_MACHINE_KERNEL_SEG + (PUPA_DISK_SECTOR_SIZE >> 4); + pupa_uint16_t last_length = PUPA_DISK_SECTOR_SIZE; + pupa_file_t file; + FILE *fp; + + auto void save_first_sector (unsigned long sector, unsigned offset, + unsigned length); + auto void save_blocklists (unsigned long sector, unsigned offset, + unsigned length); + + void save_first_sector (unsigned long sector, unsigned offset, + unsigned length) + { + pupa_util_info ("the fist sector is <%lu,%u,%u>", + sector, offset, length); + + if (offset != 0 || length != PUPA_DISK_SECTOR_SIZE) + pupa_util_error ("The first sector of the core file is not sector-aligned"); + + first_sector = sector; + } + + void save_blocklists (unsigned long sector, unsigned offset, unsigned length) + { + struct boot_blocklist *prev = block + 1; + + pupa_util_info ("saving <%lu,%u,%u> with the segment 0x%x", + sector, offset, length, (unsigned) current_segment); + + if (offset != 0 || last_length != PUPA_DISK_SECTOR_SIZE) + pupa_util_error ("Non-sector-aligned data is found in the core file"); + + if (block != first_block + && (pupa_le_to_cpu32 (prev->start) + + pupa_le_to_cpu16 (prev->len)) == sector) + prev->len = pupa_le_to_cpu16 (prev->len) + 1; + else + { + block->start = pupa_cpu_to_le32 (sector); + block->len = pupa_cpu_to_le16 (1); + block->segment = pupa_cpu_to_le16 (current_segment); + + block--; + if (block->len) + pupa_util_error ("The sectors of the core file are too fragmented"); + } + + last_length = length; + current_segment += PUPA_DISK_SECTOR_SIZE >> 4; + } + + /* Read the boot image by the OS service. */ + boot_path = pupa_util_get_path (dir, boot_file); + boot_size = pupa_util_get_image_size (boot_path); + if (boot_size != PUPA_DISK_SECTOR_SIZE) + pupa_util_error ("The size of `%s' is not %d", + boot_path, PUPA_DISK_SECTOR_SIZE); + boot_img = pupa_util_read_image (boot_path); + free (boot_path); + + /* Set the addresses of BOOT_DRIVE and KERNEL_SECTOR. */ + boot_drive = (pupa_uint8_t *) (boot_img + PUPA_BOOT_MACHINE_BOOT_DRIVE); + kernel_sector = (pupa_uint32_t *) (boot_img + + PUPA_BOOT_MACHINE_KERNEL_SECTOR); + + core_path = pupa_util_get_path (dir, core_file); + core_size = pupa_util_get_image_size (core_path); + core_sectors = ((core_size + PUPA_DISK_SECTOR_SIZE - 1) + >> PUPA_DISK_SECTOR_BITS); + if (core_size < PUPA_DISK_SECTOR_SIZE) + pupa_util_error ("The size of `%s' is too small", core_path); + else if (core_size > 0xFFFF * PUPA_DISK_SECTOR_SIZE) + pupa_util_error ("The size of `%s' is too large", core_path); + + core_img = pupa_util_read_image (core_path); + free (core_path); + + /* Have FIRST_BLOCK to point to the first blocklist. */ + first_block = (struct boot_blocklist *) (core_img + + PUPA_DISK_SECTOR_SIZE + - sizeof (*block)); + + /* Open the root device and the destination device. */ + root_dev = pupa_device_open (root); + if (! root_dev) + pupa_util_error ("%s", pupa_errmsg); + + dest_dev = pupa_device_open (dest); + if (! dest_dev) + pupa_util_error ("%s", pupa_errmsg); + + pupa_util_info ("setting the root device to `%s'", root); + if (pupa_device_set_root (root) != PUPA_ERR_NONE) + pupa_util_error ("%s", pupa_errmsg); + + /* Read the original sector from the disk. */ + tmp_img = xmalloc (PUPA_DISK_SECTOR_SIZE); + if (pupa_disk_read (dest_dev->disk, 0, 0, PUPA_DISK_SECTOR_SIZE, tmp_img)) + pupa_util_error ("%s", pupa_errmsg); + + /* Copy the possible DOS BPB. */ + memcpy (boot_img + PUPA_BOOT_MACHINE_BPB_START, + tmp_img + PUPA_BOOT_MACHINE_BPB_START, + PUPA_BOOT_MACHINE_BPB_END - PUPA_BOOT_MACHINE_BPB_START); + + /* Copy the possible partition table. */ + if (dest_dev->disk->has_partitions) + memcpy (boot_img + PUPA_BOOT_MACHINE_WINDOWS_NT_MAGIC, + tmp_img + PUPA_BOOT_MACHINE_WINDOWS_NT_MAGIC, + PUPA_BOOT_MACHINE_PART_END - PUPA_BOOT_MACHINE_WINDOWS_NT_MAGIC); + + free (tmp_img); + + /* If the destination device can have partitions and it is the MBR, + 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) + { + pupa_util_info ("will embed the core image into after the MBR"); + + /* The first blocklist contains the whole sectors. */ + first_block->start = pupa_cpu_to_le32 (2); + first_block->len = pupa_cpu_to_le16 (core_sectors - 1); + first_block->segment + = pupa_cpu_to_le16 (PUPA_BOOT_MACHINE_KERNEL_SEG + + (PUPA_DISK_SECTOR_SIZE >> 4)); + + /* Make sure that the second blocklist is a terminator. */ + block = first_block - 1; + block->start = 0; + block->len = 0; + block->segment = 0; + + /* Write the core image onto the disk. */ + if (pupa_disk_write (dest_dev->disk, 1, 0, core_size, core_img)) + pupa_util_error ("%s", pupa_errmsg); + + /* The boot image and the core image are on the same drive, + so there is no need to specify the boot drive explicitly. */ + *boot_drive = 0xff; + *kernel_sector = pupa_cpu_to_le32 (1); + + /* Write the boot image onto the disk. */ + if (pupa_disk_write (dest_dev->disk, 0, 0, PUPA_DISK_SECTOR_SIZE, + boot_img)) + pupa_util_error ("%s", pupa_errmsg); + + goto finish; + } + } + + /* The core image must be put on a filesystem unfortunately. */ + pupa_util_info ("will leave the core image on the filesystem"); + + /* Make sure that PUPA reads the identical image as the OS. */ + tmp_img = xmalloc (core_size); + core_path = pupa_util_get_path (prefix, core_file); + + /* It is a Good Thing to sync two times. */ + sync (); + sync (); + +#define MAX_TRIES 5 + + for (i = 0; i < MAX_TRIES; i++) + { + pupa_util_info ("attempting to read the core image `%s' from PUPA%s", + core_path, (i == 0) ? "" : " again"); + + pupa_disk_cache_invalidate_all (); + + file = pupa_file_open (core_path); + if (file) + { + if (pupa_file_size (file) != (pupa_ssize_t) core_size) + pupa_util_info ("succeeded in opening the core image but the size is different (%d != %d)", + (int) pupa_file_size (file), (int) core_size); + else if (pupa_file_read (file, tmp_img, core_size) + != (pupa_ssize_t) core_size) + 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"); + else + { + pupa_file_close (file); + break; + } + + pupa_file_close (file); + } + else + pupa_util_info ("couldn't open the core image"); + + pupa_errno = PUPA_ERR_NONE; + sync (); + sleep (1); + } + + if (i == MAX_TRIES) + pupa_util_error ("Cannot read `%s' correctly", core_path); + + /* Clean out the blocklists. */ + block = first_block; + while (block->len) + { + block->start = 0; + block->len = 0; + block->segment = 0; + + block--; + + if ((char *) block <= core_img) + pupa_util_error ("No terminator in the core image"); + } + + /* Now read the core image to determine where the sectors are. */ + file = pupa_file_open (core_path); + if (! file) + pupa_util_error ("%s", pupa_errmsg); + + file->read_hook = save_first_sector; + if (pupa_file_read (file, tmp_img, PUPA_DISK_SECTOR_SIZE) + != PUPA_DISK_SECTOR_SIZE) + pupa_util_error ("Failed to read the first sector of the core image"); + + block = first_block; + file->read_hook = save_blocklists; + if (pupa_file_read (file, tmp_img, core_size - PUPA_DISK_SECTOR_SIZE) + != (pupa_ssize_t) core_size - PUPA_DISK_SECTOR_SIZE) + pupa_util_error ("Failed to read the rest sectors of the core image"); + + free (core_path); + free (tmp_img); + + *kernel_sector = pupa_cpu_to_le32 (first_sector); + + /* If the destination device is different from the root device, + it is necessary to embed the boot drive explicitly. */ + if (root_dev->disk->id != dest_dev->disk->id) + *boot_drive = (pupa_uint8_t) root_dev->disk->id; + else + *boot_drive = 0xFF; + + /* Write the first sector of the core image onto the disk. */ + core_path = pupa_util_get_path (dir, core_file); + pupa_util_info ("opening the core image `%s'", core_path); + fp = fopen (core_path, "r+b"); + if (! fp) + pupa_util_error ("Cannot open `%s'", core_path); + + pupa_util_write_image (core_img, PUPA_DISK_SECTOR_SIZE, fp); + fclose (fp); + free (core_path); + + /* Write the boot image onto the disk. */ + if (pupa_disk_write (dest_dev->disk, 0, 0, PUPA_DISK_SECTOR_SIZE, boot_img)) + pupa_util_error ("%s", pupa_errmsg); + + finish: + + /* Sync is a Good Thing. */ + sync (); + + free (core_img); + free (boot_img); + pupa_device_close (dest_dev); + pupa_device_close (root_dev); +} + +static struct option options[] = + { + {"boot-image", required_argument, 0, 'b'}, + {"core-image", required_argument, 0, 'c'}, + {"directory", required_argument, 0, 'd'}, + {"device-map", required_argument, 0, 'm'}, + {"root-device", required_argument, 0, 'r'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``pupa-setup --help'' for more information.\n"); + else + printf ("\ +Usage: pupa-setup [OPTION]... DEVICE\n\ +\n\ +Set up images to boot from DEVICE.\n\ +DEVICE must be a PUPA device (e.g. ``(hd0,0)'').\n\ +\n\ + -b, --boot-file=FILE use FILE as the boot file [default=%s]\n\ + -c, --core-file=FILE use FILE as the core file [default=%s]\n\ + -d, --directory=DIR use PUPA files in the directory DIR [default=%s]\n\ + -m, --device-map=FILE use FILE as the device map [default=%s]\n\ + -r, --root-device=DEV use DEV as the root device [default=guessed]\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to .\n\ +", + DEFAULT_BOOT_FILE, DEFAULT_CORE_FILE, + DEFAULT_DIRECTORY, DEFAULT_DEVICE_MAP); + + exit (status); +} + +static char * +get_device_name (char *dev) +{ + size_t len = strlen (dev); + + if (dev[0] != '(' || dev[len - 1] != ')') + return 0; + + dev[len - 1] = '\0'; + return dev + 1; +} + +static char * +xgetcwd (void) +{ + size_t size = 10; + char *path; + + path = xmalloc (size); + while (! getcwd (path, size)) + { + size <<= 1; + path = xrealloc (path, size); + } + + return path; +} + +static void +strip_extra_slashes (char *dir) +{ + char *p = dir; + + while ((p = strchr (p, '/')) != 0) + { + if (p[1] == '/') + { + memmove (p, p + 1, strlen (p)); + continue; + } + else if (p[1] == '\0') + { + p[0] = '\0'; + break; + } + + p++; + } +} + +static char * +get_prefix (const char *dir) +{ + char *saved_cwd; + char *abs_dir, *prev_dir; + char *prefix; + struct stat st, prev_st; + + /* Save the current directory. */ + saved_cwd = xgetcwd (); + + if (chdir (dir) < 0) + pupa_util_error ("Cannot change directory to `%s'", dir); + + abs_dir = xgetcwd (); + strip_extra_slashes (abs_dir); + prev_dir = xstrdup (abs_dir); + + if (stat (".", &prev_st) < 0) + pupa_util_error ("Cannot stat `%s'", dir); + + if (! S_ISDIR (prev_st.st_mode)) + pupa_util_error ("`%s' is not a directory", dir); + + while (1) + { + if (chdir ("..") < 0) + pupa_util_error ("Cannot change directory to the parent"); + + if (stat (".", &st) < 0) + pupa_util_error ("Cannot stat current directory"); + + if (! S_ISDIR (st.st_mode)) + pupa_util_error ("Current directory is not a directory???"); + + if (prev_st.st_dev != st.st_dev || prev_st.st_ino == st.st_ino) + break; + + free (prev_dir); + prev_dir = xgetcwd (); + prev_st = st; + } + + strip_extra_slashes (prev_dir); + prefix = xmalloc (strlen (abs_dir) - strlen (prev_dir) + 2); + prefix[0] = '/'; + strcpy (prefix + 1, abs_dir + strlen (prev_dir)); + strip_extra_slashes (prefix); + + if (chdir (saved_cwd) < 0) + pupa_util_error ("Cannot change directory to `%s'", dir); + + free (saved_cwd); + free (abs_dir); + free (prev_dir); + + pupa_util_info ("prefix = %s", prefix); + return prefix; +} + +static char * +find_root_device (const char *dir, dev_t dev) +{ + DIR *dp; + char *saved_cwd; + struct dirent *ent; + + dp = opendir (dir); + if (! dp) + return 0; + + saved_cwd = xgetcwd (); + + if (chdir (dir) < 0) + { + free (saved_cwd); + closedir (dp); + return 0; + } + + while ((ent = readdir (dp)) != 0) + { + struct stat st; + + if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) + continue; + + if (stat (ent->d_name, &st) < 0) + /* Ignore any error. */ + continue; + + if (S_ISDIR (st.st_mode)) + { + /* Find it recursively. */ + char *res; + + res = find_root_device (ent->d_name, dev); + + if (res) + { + if (chdir (saved_cwd) < 0) + pupa_util_error ("Cannot restore the original directory"); + + free (saved_cwd); + closedir (dp); + return res; + } + } + + if (S_ISBLK (st.st_mode) && st.st_rdev == dev) + { + /* Found! */ + char *res; + + res = xmalloc (strlen (saved_cwd) + strlen (dir) + + strlen (ent->d_name) + 3); + sprintf (res, "%s/%s/%s", saved_cwd, dir, ent->d_name); + strip_extra_slashes (res); + + if (chdir (saved_cwd) < 0) + pupa_util_error ("Cannot restore the original directory"); + + free (saved_cwd); + closedir (dp); + return res; + } + } + + if (chdir (saved_cwd) < 0) + pupa_util_error ("Cannot restore the original directory"); + + free (saved_cwd); + closedir (dp); + return 0; +} + +static char * +guess_root_device (const char *dir) +{ + struct stat st; + char *os_dev; + + if (stat (dir, &st) < 0) + pupa_util_error ("Cannot stat `%s'", dir); + + /* This might be truly slow, but is there any better way? */ + os_dev = find_root_device ("/dev", st.st_dev); + if (! os_dev) + return 0; + + return pupa_util_biosdisk_get_pupa_dev (os_dev); +} + +int +main (int argc, char *argv[]) +{ + char *boot_file = 0; + char *core_file = 0; + char *dir = 0; + char *dev_map = 0; + char *root_dev = 0; + char *prefix; + char *dest_dev; + + progname = "pupa-setup"; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "b:c:d:m:r:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'b': + if (boot_file) + free (boot_file); + + boot_file = xstrdup (optarg); + break; + + case 'c': + if (core_file) + free (core_file); + + core_file = xstrdup (optarg); + break; + + case 'd': + if (dir) + free (dir); + + dir = xstrdup (optarg); + break; + + case 'm': + if (dev_map) + free (dev_map); + + dev_map = xstrdup (optarg); + break; + + case 'r': + if (root_dev) + free (root_dev); + + root_dev = xstrdup (optarg); + break; + + case 'h': + usage (0); + break; + + case 'V': + printf ("pupa-setup (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + /* Obtain DEST_DEV. */ + if (optind >= argc) + { + fprintf (stderr, "No device is specified.\n"); + usage (1); + } + + if (optind + 1 != argc) + { + fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); + usage (1); + } + + dest_dev = get_device_name (argv[optind]); + + if (! dest_dev) + { + fprintf (stderr, "Invalid device `%s'.\n", argv[optind]); + usage (1); + } + + prefix = get_prefix (dir ? : DEFAULT_DIRECTORY); + + /* Initialize the emulated biosdisk driver. */ + pupa_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP); + + /* Initialize filesystems. */ + pupa_fat_init (); + + if (root_dev) + { + char *tmp = get_device_name (root_dev); + + if (! tmp) + pupa_util_error ("Invalid root device `%s'", root_dev); + + tmp = xstrdup (tmp); + free (root_dev); + root_dev = tmp; + } + else + { + root_dev = guess_root_device (dir ? : DEFAULT_DIRECTORY); + if (! root_dev) + { + pupa_util_error ("Cannot guess the root device. Specify the option ``--root-device''."); + } + } + + /* Do the real work. */ + setup (prefix, + dir ? : DEFAULT_DIRECTORY, + boot_file ? : DEFAULT_BOOT_FILE, + core_file ? : DEFAULT_CORE_FILE, + root_dev, dest_dev); + + /* Free resources. */ + pupa_fat_fini (); + + pupa_util_biosdisk_fini (); + + free (boot_file); + free (core_file); + free (prefix); + free (dir); + free (dev_map); + free (root_dev); + free (prefix); + + return 0; +} diff --git a/util/misc.c b/util/misc.c index 6f65eb151..95b10e36e 100644 --- a/util/misc.c +++ b/util/misc.c @@ -25,6 +25,8 @@ #include #include +#include +#include char *progname = 0; int verbosity = 0; @@ -69,6 +71,16 @@ xmalloc (size_t size) return p; } +void * +xrealloc (void *ptr, size_t size) +{ + ptr = realloc (ptr, size); + if (! ptr) + pupa_util_error ("out of memory"); + + return ptr; +} + char * xstrdup (const char *str) { @@ -135,3 +147,32 @@ pupa_util_write_image (const char *img, size_t size, FILE *out) pupa_util_error ("write failed"); } +void * +pupa_malloc (unsigned size) +{ + return malloc (size); +} + +void +pupa_free (void *ptr) +{ + free (ptr); +} + +void * +pupa_realloc (void *ptr, unsigned size) +{ + return realloc (ptr, size); +} + +void +pupa_stop (void) +{ + exit (1); +} + +void +pupa_putchar (int c) +{ + putchar (c); +}