# # # delete "conf/common.mk" # # delete "conf/i386-efi.mk" # # delete "conf/i386-pc.mk" # # delete "conf/powerpc-ieee1275.mk" # # delete "conf/sparc64-ieee1275.mk" # # delete "config.h.in" # # delete "configure" # # add_dir "disk/i386/linuxbios" # # add_dir "include/grub/i386/linuxbios" # # add_dir "kern/i386/linuxbios" # # add_dir "util/i386/linuxbios" # # add_file ".mtn-ignore" # content [c7a2a26463a133ae8b1507272f0220a41a50755a] # # add_file "conf/i386-linuxbios.rmk" # content [653760bd41f10b6cc9cdf936b724c7b6023fa6d9] # # add_file "disk/i386/linuxbios/__udivdi3.c" # content [049b71123068dae4cdbe8bae8687b2b4486d0b24] # # add_file "disk/i386/linuxbios/__udivmoddi4.c" # content [135ef8d1b15348bce23b4833fd40388e4ed76d34] # # add_file "disk/i386/linuxbios/__umoddi3.c" # content [bccad7164ac05224e1fb40a4d8c999dec8ddf521] # # add_file "disk/i386/linuxbios/atadisk.c" # content [493e2e4e56f126eb67d6809d309143e770a96099] # # add_file "disk/i386/linuxbios/grubcompat.h" # content [d2b222e25ebecf07213e43047f0511bf5b8b47ae] # # add_file "disk/i386/linuxbios/hdreg.h" # content [2938d0b3bb63f7548f035f2ab663929c289707d9] # # add_file "disk/i386/linuxbios/ide.c" # content [4a68b2001201d3c1920c47f28aea1edc130b4bbe] # # add_file "disk/i386/linuxbios/ide.h" # content [8478f35af95718caaae47dafdbf387b64980c75e] # # add_file "disk/i386/linuxbios/io.h" # content [b96231c3a9c485ce0f573b11dc855abfeefac393] # # add_file "disk/i386/linuxbios/romdisk.c" # content [cebc3f4f13029470b9344e5554d3f53ea6a18503] # # add_file "disk/i386/linuxbios/timer.h" # content [e4a5373692f4e7f14f2484ae13a68ce7059e48a0] # # add_file "fs/lar.c" # content [b8c46ee854ee5f03d0115cb456d9595aabd2afda] # # add_file "include/grub/i386/linuxbios/console.h" # content [c2bb51e46226a8fa4d1cec997b881e688e2d3e86] # # add_file "include/grub/i386/linuxbios/init.h" # content [65fc3ab337376e39eeefce69119c7499999e7fdd] # # add_file "include/grub/i386/linuxbios/kernel.h" # content [ac5c2d95a3d02f58bd437101586db64d190b4274] # # add_file "include/grub/i386/linuxbios/loader.h" # content [a798b7b410aed11839883fdd29697d9ce7125a50] # # add_file "include/grub/i386/linuxbios/serial.h" # content [387a103ce2d3b9752a3bded41190234696c39c9f] # # add_file "include/grub/i386/linuxbios/time.h" # content [7f262727d1028e1cad6c63031dca50f2512d32d2] # # add_file "include/stdint.h" # content [872aaba8c1cadfdb97827e64916ff6ecb84a1cd6] # # add_file "kern/i386/linuxbios/cmain.c" # content [2b4330140725a1d422084356472646d32fdd137a] # # add_file "kern/i386/linuxbios/console.c" # content [5f357fde333283981d80f69ced284a12534687c4] # # add_file "kern/i386/linuxbios/crt0.S" # content [3b5acd225e07462ead18db1cff0815ef7efa8328] # # add_file "util/i386/linuxbios/grub-mkimage.c" # content [79ac860818d399a47eccca1efcd4adcd6793f478] # # patch "aclocal.m4" # from [b8c631c45402c8b4aab7fc36fa9df949c296e755] # to [7338868d83ce19c2ace4f5f3fea3b6eb83c0c735] # # patch "conf/common.rmk" # from [f8272f9ed80664a85a1b2ba66778bdde1c2c5497] # to [25d33b7ade2596be664d5965ed6d50a41211b344] # # patch "configure.ac" # from [e03be6dfd73f084b632103a9c3add874060d3d84] # to [6fa01a0bd36f4abe88d75a465b7b86651c97d5a1] # # patch "include/grub/disk.h" # from [2c6853faed5a4f7e8b65f69f3f79c0035ed2ca57] # to [0aee188f6926d78e2d1889bc56bab4f5f5266b95] # ============================================================ --- .mtn-ignore c7a2a26463a133ae8b1507272f0220a41a50755a +++ .mtn-ignore c7a2a26463a133ae8b1507272f0220a41a50755a @@ -0,0 +1,3 @@ +config.h.in +configure +conf/.*\.mk ============================================================ --- conf/i386-linuxbios.rmk 653760bd41f10b6cc9cdf936b724c7b6023fa6d9 +++ conf/i386-linuxbios.rmk 653760bd41f10b6cc9cdf936b724c7b6023fa6d9 @@ -0,0 +1,86 @@ + +# -*- makefile -*- + +COMMON_ASFLAGS = -nostdinc -fno-builtin -m32 +COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32 +COMMON_LDFLAGS = -m32 -nostdlib + +# Images. +pkgdata_PROGRAMS = kernel.elf + +MOSTLYCLEANFILES += kernel_elf_symlist.c kernel_syms.lst +DEFSYMFILES += kernel_syms.lst + +kernel_elf_SOURCES = kern/i386/linuxbios/crt0.S kern/i386/linuxbios/cmain.c \ + kern/main.c kern/device.c \ + kern/disk.c kern/dl.c kern/err.c kern/file.c kern/fs.c \ + kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \ + kern/parser.c kern/partition.c kern/env.c kern/i386/dl.c \ + kern/i386/linuxbios/console.c \ + kernel_elf_symlist.c +kernel_elf_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ + env.h err.h file.h fs.h kernel.h misc.h mm.h net.h parser.h rescue.h \ + symbol.h term.h types.h loader.h partition.h \ + pc_partition.h machine/time.h machine/init.h machine/loader.h +kernel_elf_CFLAGS = $(COMMON_CFLAGS) +kernel_elf_ASFLAGS = $(COMMON_ASFLAGS) +kernel_elf_LDFLAGS = $(COMMON_LDFLAGS) -static-libgcc -lgcc \ + -Wl,-N,-S,-Ttext,0x10000,-Bstatic + +kernel_elf_symlist.c: $(addprefix include/grub/,$(kernel_elf_HEADERS)) config.h gensymlist.sh + /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) + +kernel_syms.lst: $(addprefix include/grub/,$(kernel_elf_HEADERS)) config.h genkernsyms.sh + /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) + +# Utilities. +bin_UTILITIES = grub-mkimage + +# For grub-mkimage. +grub_mkimage_SOURCES = util/i386/linuxbios/grub-mkimage.c util/misc.c \ + util/resolve.c + +# Modules. +pkgdata_MODULES = normal.mod serial.mod _multiboot.mod multiboot.mod rom.mod atadisk.mod + +# For normal.mod. +normal_mod_DEPENDENCIES = grub_script.tab.c grub_script.tab.h +normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ + normal/completion.c normal/execute.c \ + normal/function.c normal/lexer.c normal/main.c normal/menu.c \ + normal/menu_entry.c normal/misc.c grub_script.tab.c \ + normal/script.c normal/i386/setjmp.S +normal_mod_CFLAGS = $(COMMON_CFLAGS) +normal_mod_LDFLAGS = $(COMMON_LDFLAGS) +normal_mod_ASFLAGS = $(COMMON_ASFLAGS) + +# For serial.mod. +serial_mod_SOURCES = term/i386/pc/serial.c +serial_mod_CFLAGS = $(COMMON_CFLAGS) +serial_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For _multiboot.mod. +_multiboot_mod_SOURCES = loader/i386/pc/multiboot.c \ + loader/i386/pc/multiboot2.c \ + loader/multiboot2.c \ + loader/multiboot_loader.c +_multiboot_mod_CFLAGS = $(COMMON_CFLAGS) +_multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For multiboot.mod. +multiboot_mod_SOURCES = loader/multiboot_loader_normal.c +multiboot_mod_CFLAGS = $(COMMON_CFLAGS) +multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For atadisk.mod. +atadisk_mod_SOURCES = disk/i386/linuxbios/ide.c disk/i386/linuxbios/atadisk.c disk/i386/linuxbios/__umoddi3.c disk/i386/linuxbios/__udivmoddi4.c disk/i386/linuxbios/__udivdi3.c +atadisk_mod_CFLAGS = $(COMMON_CFLAGS) +atadisk_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For rom.mod. +rom_mod_SOURCES = disk/i386/linuxbios/romdisk.c +rom_mod_CFLAGS = $(COMMON_CFLAGS) +rom_mod_LDFLAGS = $(COMMON_LDFLAGS) + +include $(srcdir)/conf/common.mk + ============================================================ --- disk/i386/linuxbios/__udivdi3.c 049b71123068dae4cdbe8bae8687b2b4486d0b24 +++ disk/i386/linuxbios/__udivdi3.c 049b71123068dae4cdbe8bae8687b2b4486d0b24 @@ -0,0 +1,13 @@ +/* + * arch/i386/libgcc/__divdi3.c + */ + +#include +#include + +extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem); + +uint64_t __udivdi3(uint64_t num, uint64_t den) +{ + return __udivmoddi4(num, den, NULL); +} ============================================================ --- disk/i386/linuxbios/__udivmoddi4.c 135ef8d1b15348bce23b4833fd40388e4ed76d34 +++ disk/i386/linuxbios/__udivmoddi4.c 135ef8d1b15348bce23b4833fd40388e4ed76d34 @@ -0,0 +1,31 @@ +#include + + +grub_uint64_t __udivmoddi4(grub_uint64_t num, grub_uint64_t den, grub_uint64_t *rem_p) +{ + grub_uint64_t quot = 0, qbit = 1; + + if ( den == 0 ) { + return 0; /* If trap returns... */ + } + + /* Left-justify denominator and count shift */ + while ( (grub_int64_t)den >= 0 ) { + den <<= 1; + qbit <<= 1; + } + + while ( qbit ) { + if ( den <= num ) { + num -= den; + quot += qbit; + } + den >>= 1; + qbit >>= 1; + } + + if ( rem_p ) + *rem_p = num; + + return quot; +} ============================================================ --- disk/i386/linuxbios/__umoddi3.c bccad7164ac05224e1fb40a4d8c999dec8ddf521 +++ disk/i386/linuxbios/__umoddi3.c bccad7164ac05224e1fb40a4d8c999dec8ddf521 @@ -0,0 +1,16 @@ +/* + * arch/i386/libgcc/__umoddi3.c + */ + +#include +#include + +extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem); + +uint64_t __umoddi3(uint64_t num, uint64_t den) +{ + uint64_t v; + + (void) __udivmoddi4(num, den, &v); + return v; +} ============================================================ --- disk/i386/linuxbios/atadisk.c 493e2e4e56f126eb67d6809d309143e770a96099 +++ disk/i386/linuxbios/atadisk.c 493e2e4e56f126eb67d6809d309143e770a96099 @@ -0,0 +1,96 @@ +#include +#include +#include +#include "ide.h" + +int (*hook) (const char *name); +int diskno=0; +struct ide_drive *drives[4]; + +static int +grub_ata_register_drive(struct ide_drive *d) +{ + char name[5]; + + grub_sprintf(name, "ata%d", diskno); + drives[diskno] = d; + diskno++; + return hook(name); +} + +static int +grub_ata_iterate (int (*h) (const char *name)) +{ + diskno = 0; + hook = h; + return ob_ide_init(grub_ata_register_drive); +} + +static grub_err_t +grub_ata_open (const char *name, grub_disk_t disk) +{ + if ((name[0]!='a') || (name[1]!='t') || (name[2]!='a') || (name[3]<'0') || + (name[3]>'3')) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device"); + struct ide_drive *drive = drives[name[3]-'0']; + disk->data=drive; + disk->total_sectors = drive->sectors; + if (drive->media == ide_media_disk) + { + disk->has_partitions = 1; + } else { + disk->has_partitions = 0; + } + return 0; +} + +static void +grub_ata_close (grub_disk_t disk __attribute ((unused))) +{ +} + +static grub_err_t +grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + if (((struct ide_drive*)(disk->data))->media == ide_media_cdrom) { + grub_dprintf("ata","cdrom: translate from 2048b sectors to 512b. before: size %d, sector %d\n",size, sector); + size /= 4; + sector /= 4; + } + grub_dprintf("ata","reading %d sectors, starting from %d\n",size, (int)sector); + if (ob_ide_read_blocks(disk->data, size, sector, buf) != size) + return GRUB_ERR_READ_ERROR; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_ata_write (grub_disk_t disk __attribute ((unused)), + grub_disk_addr_t sector __attribute ((unused)), + grub_size_t size __attribute ((unused)), + const char *buf __attribute ((unused))) +{ + return GRUB_ERR_NOT_IMPLEMENTED_YET; +} + +static struct grub_disk_dev grub_ata_dev = + { + .name = "ata", + .id = GRUB_DISK_DEVICE_ATA_ID, + .iterate = grub_ata_iterate, + .open = grub_ata_open, + .close = grub_ata_close, + .read = grub_ata_read, + .write = grub_ata_write, + .next = 0 + }; + +GRUB_MOD_INIT(ata) +{ + grub_disk_dev_register (&grub_ata_dev); +} + +GRUB_MOD_FINI(ata) +{ + grub_disk_dev_unregister (&grub_ata_dev); +} ============================================================ --- disk/i386/linuxbios/grubcompat.h d2b222e25ebecf07213e43047f0511bf5b8b47ae +++ disk/i386/linuxbios/grubcompat.h d2b222e25ebecf07213e43047f0511bf5b8b47ae @@ -0,0 +1,45 @@ +#ifndef GRUB_COMPAT +#define GRUB_COMPAT + +#define CONFIG_LITTLE_ENDIAN +#define CONFIG_IDE_LBA48 + +#include +#include + +#define u8 grub_uint8_t +#define u16 grub_uint16_t +#define u32 grub_uint32_t +#define u64 grub_uint64_t + +#define __be32_to_cpu grub_be_to_cpu32 +#define __be16_to_cpu grub_be_to_cpu16 +#define __le32_to_cpu grub_le_to_cpu32 +#define __le16_to_cpu grub_le_to_cpu16 + +#define printk grub_printf +#define strcpy grub_strcpy +#define memset grub_memset + +#define NULL 0 + +#include "io.h" +#include "timer.h" + +static void load_timer2(unsigned int ticks) +{ + /* Set up the timer gate, turn off the speaker */ + outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); + outb(TIMER2_SEL | WORD_ACCESS | MODE0 | BINARY_COUNT, + TIMER_MODE_PORT); + outb(ticks & 0xFF, TIMER2_PORT); + outb(ticks >> 8, TIMER2_PORT); +} + +void udelay(unsigned int usecs) +{ + load_timer2((usecs * TICKS_PER_MS) / 1000); + while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); +} + +#endif ============================================================ --- disk/i386/linuxbios/hdreg.h 2938d0b3bb63f7548f035f2ab663929c289707d9 +++ disk/i386/linuxbios/hdreg.h 2938d0b3bb63f7548f035f2ab663929c289707d9 @@ -0,0 +1,296 @@ +/* + * this header holds data structures as dictated by spec + */ +#ifndef HDREG_H +#define HDREG_H +#include +#include + +#define CONFIG_LITTLE_ENDIAN +#define u8 grub_uint8_t +#define u16 grub_uint16_t +#define u32 grub_uint32_t + +struct hd_driveid { + unsigned short config; /* lots of obsolete bit flags */ + unsigned short cyls; /* Obsolete, "physical" cyls */ + unsigned short reserved2; /* reserved (word 2) */ + unsigned short heads; /* Obsolete, "physical" heads */ + unsigned short track_bytes; /* unformatted bytes per track */ + unsigned short sector_bytes; /* unformatted bytes per sector */ + unsigned short sectors; /* Obsolete, "physical" sectors per track */ + unsigned short vendor0; /* vendor unique */ + unsigned short vendor1; /* vendor unique */ + unsigned short vendor2; /* Retired vendor unique */ + unsigned char serial_no[20]; /* 0 = not_specified */ + unsigned short buf_type; /* Retired */ + unsigned short buf_size; /* Retired, 512 byte increments + * 0 = not_specified + */ + unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */ + unsigned char fw_rev[8]; /* 0 = not_specified */ + unsigned char model[40]; /* 0 = not_specified */ + unsigned char max_multsect; /* 0=not_implemented */ + unsigned char vendor3; /* vendor unique */ + unsigned short dword_io; /* 0=not_implemented; 1=implemented */ + unsigned char vendor4; /* vendor unique */ + unsigned char capability; /* (upper byte of word 49) + * 3: IORDYsup + * 2: IORDYsw + * 1: LBA + * 0: DMA + */ + unsigned short reserved50; /* reserved (word 50) */ + unsigned char vendor5; /* Obsolete, vendor unique */ + unsigned char tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */ + unsigned char vendor6; /* Obsolete, vendor unique */ + unsigned char tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */ + unsigned short field_valid; /* (word 53) + * 2: ultra_ok word 88 + * 1: eide_ok words 64-70 + * 0: cur_ok words 54-58 + */ + unsigned short cur_cyls; /* Obsolete, logical cylinders */ + unsigned short cur_heads; /* Obsolete, l heads */ + unsigned short cur_sectors; /* Obsolete, l sectors per track */ + unsigned short cur_capacity0; /* Obsolete, l total sectors on drive */ + unsigned short cur_capacity1; /* Obsolete, (2 words, misaligned int) */ + unsigned char multsect; /* current multiple sector count */ + unsigned char multsect_valid; /* when (bit0==1) multsect is ok */ + unsigned int lba_capacity; /* Obsolete, total number of sectors */ + unsigned short dma_1word; /* Obsolete, single-word dma info */ + unsigned short dma_mword; /* multiple-word dma info */ + unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */ + unsigned short eide_dma_min; /* min mword dma cycle time (ns) */ + unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */ + unsigned short eide_pio; /* min cycle time (ns), no IORDY */ + unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */ + unsigned short words69_70[2]; /* reserved words 69-70 + * future command overlap and queuing + */ + /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */ + unsigned short words71_74[4]; /* reserved words 71-74 + * for IDENTIFY PACKET DEVICE command + */ + unsigned short queue_depth; /* (word 75) + * 15:5 reserved + * 4:0 Maximum queue depth -1 + */ + unsigned short words76_79[4]; /* reserved words 76-79 */ + unsigned short major_rev_num; /* (word 80) */ + unsigned short minor_rev_num; /* (word 81) */ + unsigned short command_set_1; /* (word 82) supported + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + unsigned short command_set_2; /* (word 83) + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + unsigned short cfsse; /* (word 84) + * cmd set-feature supported extensions + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:6 reserved + * 5: General Purpose Logging + * 4: Streaming Feature Set + * 3: Media Card Pass Through + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + unsigned short cfs_enable_1; /* (word 85) + * command set-feature enabled + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + unsigned short cfs_enable_2; /* (word 86) + * command set-feature enabled + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + unsigned short csf_default; /* (word 87) + * command set-feature default + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:6 reserved + * 5: General Purpose Logging enabled + * 4: Valid CONFIGURE STREAM executed + * 3: Media Card Pass Through enabled + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + unsigned short dma_ultra; /* (word 88) */ + unsigned short trseuc; /* time required for security erase */ + unsigned short trsEuc; /* time required for enhanced erase */ + unsigned short CurAPMvalues; /* current APM values */ + unsigned short mprc; /* master password revision code */ + unsigned short hw_config; /* hardware config (word 93) + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: + * 12: + * 11: + * 10: + * 9: + * 8: + * 7: + * 6: + * 5: + * 4: + * 3: + * 2: + * 1: + * 0: Shall be ONE + */ + unsigned short acoustic; /* (word 94) + * 15:8 Vendor's recommended value + * 7:0 current value + */ + unsigned short msrqs; /* min stream request size */ + unsigned short sxfert; /* stream transfer time */ + unsigned short sal; /* stream access latency */ + unsigned int spg; /* stream performance granularity */ + unsigned long long lba_capacity_2;/* 48-bit total number of sectors */ + unsigned short words104_125[22];/* reserved words 104-125 */ + unsigned short last_lun; /* (word 126) */ + unsigned short word127; /* (word 127) Feature Set + * Removable Media Notification + * 15:2 reserved + * 1:0 00 = not supported + * 01 = supported + * 10 = reserved + * 11 = reserved + */ + unsigned short dlf; /* (word 128) + * device lock function + * 15:9 reserved + * 8 security level 1:max 0:high + * 7:6 reserved + * 5 enhanced erase + * 4 expire + * 3 frozen + * 2 locked + * 1 en/disabled + * 0 capability + */ + unsigned short csfo; /* (word 129) + * current set features options + * 15:4 reserved + * 3: auto reassign + * 2: reverting + * 1: read-look-ahead + * 0: write cache + */ + unsigned short words130_155[26];/* reserved vendor words 130-155 */ + unsigned short word156; /* reserved vendor word 156 */ + unsigned short words157_159[3];/* reserved vendor words 157-159 */ + unsigned short cfa_power; /* (word 160) CFA Power Mode + * 15 word 160 supported + * 14 reserved + * 13 + * 12 + * 11:0 + */ + unsigned short words161_175[15];/* Reserved for CFA */ + unsigned short words176_205[30];/* Current Media Serial Number */ + unsigned short words206_254[49];/* reserved words 206-254 */ + unsigned short integrity_word; /* (word 255) + * 15:8 Checksum + * 7:0 Signature + */ +}; + +struct request_sense { +#if defined(CONFIG_BIG_ENDIAN) + u8 valid : 1; + u8 error_code : 7; +#elif defined(CONFIG_LITTLE_ENDIAN) + u8 error_code : 7; + u8 valid : 1; +#endif + u8 segment_number; +#if defined(CONFIG_BIG_ENDIAN) + u8 reserved1 : 2; + u8 ili : 1; + u8 reserved2 : 1; + u8 sense_key : 4; +#elif defined(CONFIG_LITTLE_ENDIAN) + u8 sense_key : 4; + u8 reserved2 : 1; + u8 ili : 1; + u8 reserved1 : 2; +#endif + u8 information[4]; + u8 add_sense_len; + u8 command_info[4]; + u8 asc; + u8 ascq; + u8 fruc; + u8 sks[3]; + u8 asb[46]; +}; + +struct atapi_capacity { + u32 lba; + u32 block_size; +}; + +#endif ============================================================ --- disk/i386/linuxbios/ide.c 4a68b2001201d3c1920c47f28aea1edc130b4bbe +++ disk/i386/linuxbios/ide.c 4a68b2001201d3c1920c47f28aea1edc130b4bbe @@ -0,0 +1,1198 @@ +/* + * OpenBIOS polled ide driver + * + * Copyright (C) 2004 Jens Axboe + * Copyright (C) 2005 Stefan Reinauer + * + * Credit goes to Hale Landis for his excellent ata demo software + * OF node handling and some fixes by Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +/* + * TODO: + * - Really probe for interfaces, don't just rely on legacy + */ + +#define GRUB + +#include "grubcompat.h" + +#include "ide.h" +#include "hdreg.h" + +/* + * define to 2 for the standard 2 channels only + */ +#ifndef CONFIG_IDE_NUM_CHANNELS +#define IDE_NUM_CHANNELS 4 +#else +#define IDE_NUM_CHANNELS CONFIG_IDE_NUM_CHANNELS +#endif +#define IDE_MAX_CHANNELS 4 + +static struct ide_channel ob_ide_channels[IDE_MAX_CHANNELS]; + +/* + * FIXME: probe, we just hardwire legacy ports for now + */ +static const int io_ports[IDE_MAX_CHANNELS] = { 0x1f0, 0x170, 0x1e8, 0x168 }; +static const int ctl_ports[IDE_MAX_CHANNELS] = { 0x3f6, 0x376, 0x3ee, 0x36e }; + +/* + * don't be pedantic + */ +#undef ATA_PEDANTIC + +static void dump_drive(struct ide_drive *drive) +{ +#ifdef CONFIG_DEBUG_IDE + printk("IDE DRIVE @%lx:\n", (unsigned long)drive); + printk("unit: %d\n",drive->unit); + printk("present: %d\n",drive->present); + printk("type: %d\n",drive->type); + printk("media: %d\n",drive->media); + printk("model: %s\n",drive->model); + printk("nr: %d\n",drive->nr); + printk("cyl: %d\n",drive->cyl); + printk("head: %d\n",drive->head); + printk("sect: %d\n",drive->sect); + printk("bs: %d\n",drive->bs); +#endif +} + +/* + * old style io port operations + */ +static unsigned char +ob_ide_inb(unsigned long port) +{ + return inb(port); +} + +static void +ob_ide_outb(unsigned char data, unsigned long port) +{ + outb(data, port); +} + +static void +ob_ide_insw(unsigned long port, unsigned char *addr, unsigned int count) +{ + insw(port, addr, count); +} + +static void +ob_ide_outsw(unsigned long port, unsigned char *addr, unsigned int count) +{ + outsw(port, addr, count); +} + +static inline unsigned char +ob_ide_pio_readb(struct ide_drive *drive, unsigned int offset) +{ + struct ide_channel *chan = drive->channel; + + return chan->obide_inb(chan->io_regs[offset]); +} + +static inline void +ob_ide_pio_writeb(struct ide_drive *drive, unsigned int offset, + unsigned char data) +{ + struct ide_channel *chan = drive->channel; + + chan->obide_outb(data, chan->io_regs[offset]); +} + +static inline void +ob_ide_pio_insw(struct ide_drive *drive, unsigned int offset, + unsigned char *addr, unsigned int len) +{ + struct ide_channel *chan = drive->channel; + + if (len & 1) { + printk("%d: command not word aligned\n", drive->nr); + return; + } + + chan->obide_insw(chan->io_regs[offset], addr, len / 2); +} + +static inline void +ob_ide_pio_outsw(struct ide_drive *drive, unsigned int offset, + unsigned char *addr, unsigned int len) +{ + struct ide_channel *chan = drive->channel; + + if (len & 1) { + printk("%d: command not word aligned\n", drive->nr); + return; + } + + chan->obide_outsw(chan->io_regs[offset], addr, len / 2); +} + +static void +ob_ide_400ns_delay(struct ide_drive *drive) +{ + (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS); + (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS); + (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS); + (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS); + + udelay(1); +} + +static void +ob_ide_error(struct ide_drive *drive, unsigned char stat, char *msg) +{ + struct ide_channel *chan = drive->channel; + unsigned char err; + + if (!stat) + stat = ob_ide_pio_readb(drive, IDEREG_STATUS); + + printk("ob_ide_error drive<%d>: %s:\n", drive->nr, msg); + printk(" cmd=%x, stat=%x", chan->ata_cmd.command, stat); + + if ((stat & (BUSY_STAT | ERR_STAT)) == ERR_STAT) { + err = ob_ide_pio_readb(drive, IDEREG_ERROR); + printk(", err=%x", err); + } + printk("\n"); + + /* + * see if sense is valid and dump that + */ + if (chan->ata_cmd.command == WIN_PACKET) { + struct atapi_command *cmd = &chan->atapi_cmd; + unsigned char old_cdb = cmd->cdb[0]; + + if (cmd->cdb[0] == ATAPI_REQ_SENSE) { + old_cdb = cmd->old_cdb; + + printk(" atapi opcode=%02x", old_cdb); + } else { + int i; + + printk(" cdb: "); + for (i = 0; i < sizeof(cmd->cdb); i++) + printk("%02x ", cmd->cdb[i]); + } + if (cmd->sense_valid) + printk(", sense: %02x/%02x/%02x", cmd->sense.sense_key, cmd->sense.asc, cmd->sense.ascq); + else + printk(", no sense"); + printk("\n"); + } +} + +/* + * wait for 'stat' to be set. returns 1 if failed, 0 if succesful + */ +static int +ob_ide_wait_stat(struct ide_drive *drive, unsigned char ok_stat, + unsigned char bad_stat, unsigned char *ret_stat) +{ + unsigned char stat; + int i; + + ob_ide_400ns_delay(drive); + + for (i = 0; i < 5000; i++) { + stat = ob_ide_pio_readb(drive, IDEREG_STATUS); + if (!(stat & BUSY_STAT)) + break; + + udelay(1000); + } + + if (ret_stat) + *ret_stat = stat; + + if (stat & bad_stat) + return 1; + + if ((stat & ok_stat) || !ok_stat) + return 0; + + return 1; +} + +static int +ob_ide_select_drive(struct ide_drive *drive) +{ + struct ide_channel *chan = drive->channel; + unsigned char control = IDEHEAD_DEV0; + + if (ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL)) { + printk("select_drive: timed out\n"); + return 1; + } + + /* + * don't select drive if already active. Note: we always + * wait for BUSY clear + */ + if (drive->unit == chan->selected) + return 0; + + if (drive->unit) + control = IDEHEAD_DEV1; + + ob_ide_pio_writeb(drive, IDEREG_CURRENT, control); + ob_ide_400ns_delay(drive); + + if (ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL)) { + printk("select_drive: timed out\n"); + return 1; + } + + chan->selected = drive->unit; + return 0; +} + +static void +ob_ide_write_tasklet(struct ide_drive *drive, struct ata_command *cmd) +{ + ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->task[1]); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->task[3]); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->task[7]); + ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->task[8]); + ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->task[9]); + + ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->task[0]); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->task[2]); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->task[4]); + ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->task[5]); + ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->task[6]); + + if (drive->unit) + cmd->device_head |= IDEHEAD_DEV1; + + ob_ide_pio_writeb(drive, IDEREG_CURRENT, cmd->device_head); + + ob_ide_pio_writeb(drive, IDEREG_COMMAND, cmd->command); + ob_ide_400ns_delay(drive); +} + +static void +ob_ide_write_registers(struct ide_drive *drive, struct ata_command *cmd) +{ + /* + * we are _always_ polled + */ + ob_ide_pio_writeb(drive, IDEREG_CONTROL, cmd->control | IDECON_NIEN); + + ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->feature); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->nsector); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->sector); + ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->lcyl); + ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->hcyl); + + if (drive->unit) + cmd->device_head |= IDEHEAD_DEV1; + + ob_ide_pio_writeb(drive, IDEREG_CURRENT, cmd->device_head); + + ob_ide_pio_writeb(drive, IDEREG_COMMAND, cmd->command); + ob_ide_400ns_delay(drive); +} + +/* + * execute given command with a pio data-in phase. + */ +static int +ob_ide_pio_data_in(struct ide_drive *drive, struct ata_command *cmd) +{ + unsigned char stat; + unsigned int bytes, timeout; + + if (ob_ide_select_drive(drive)) + return 1; + + /* + * ATA must set ready and seek stat, ATAPI need only clear busy + */ + timeout = 0; + do { + stat = ob_ide_pio_readb(drive, IDEREG_STATUS); + + if (drive->type == ide_type_ata) { + /* + * this is BIOS code, don't be too pedantic + */ +#ifdef ATA_PEDANTIC + if ((stat & (BUSY_STAT | READY_STAT | SEEK_STAT)) == + (READY_STAT | SEEK_STAT)) + break; +#else + if ((stat & (BUSY_STAT | READY_STAT)) == READY_STAT) + break; +#endif + } else { + if (!(stat & BUSY_STAT)) + break; + } + ob_ide_400ns_delay(drive); + } while (timeout++ < 1000); + + if (timeout >= 1000) { + ob_ide_error(drive, stat, "drive timed out"); + cmd->stat = stat; + return 1; + } + + ob_ide_write_registers(drive, cmd); + + /* + * now read the data + */ + bytes = cmd->buflen; + do { + unsigned count = cmd->buflen; + + if (count > drive->bs) + count = drive->bs; + + /* delay 100ms for ATAPI? */ + + /* + * wait for BUSY clear + */ + if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) { + ob_ide_error(drive, stat, "timed out waiting for BUSY clear"); + cmd->stat = stat; + break; + } + + /* + * transfer the data + */ + if ((stat & (BUSY_STAT | DRQ_STAT)) == DRQ_STAT) { + ob_ide_pio_insw(drive, IDEREG_DATA, cmd->buffer, count); + cmd->bytes -= count; + cmd->buffer += count; + bytes -= count; + + ob_ide_400ns_delay(drive); + } + + if (stat & (BUSY_STAT | WRERR_STAT | ERR_STAT)) { + cmd->stat = stat; + break; + } + + if (!(stat & DRQ_STAT)) { + cmd->stat = stat; + break; + } + } while (bytes); + + if (bytes) + printk("bytes=%d, stat=%x\n", bytes, stat); + + return bytes ? 1 : 0; +} + +/* + * execute ata command with pio packet protocol + */ +static int +ob_ide_pio_packet(struct ide_drive *drive, struct atapi_command *cmd) +{ + unsigned char stat, reason, lcyl, hcyl; + struct ata_command *acmd = &drive->channel->ata_cmd; + unsigned char *buffer; + unsigned int bytes; + + if (ob_ide_select_drive(drive)) + return 1; + + if (cmd->buflen && cmd->data_direction == atapi_ddir_none) + printk("non-zero buflen but no data direction\n"); + + memset(acmd, 0, sizeof(*acmd)); + acmd->lcyl = cmd->buflen & 0xff; + acmd->hcyl = (cmd->buflen >> 8) & 0xff; + acmd->command = WIN_PACKET; + ob_ide_write_registers(drive, acmd); + + /* + * BUSY must be set, _or_ DRQ | ERR + */ + stat = ob_ide_pio_readb(drive, IDEREG_ASTATUS); + if ((stat & BUSY_STAT) == 0) { + if (!(stat & (DRQ_STAT | ERR_STAT))) { + ob_ide_error(drive, stat, "bad stat in atapi cmd"); + cmd->stat = stat; + return 1; + } + } + + if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) { + ob_ide_error(drive, stat, "timeout, ATAPI BUSY clear"); + cmd->stat = stat; + return 1; + } + + if ((stat & (BUSY_STAT | DRQ_STAT | ERR_STAT)) != DRQ_STAT) { + /* + * if command isn't request sense, then we have a problem. if + * we are doing a sense, ERR_STAT == CHECK_CONDITION + */ + if (cmd->cdb[0] != ATAPI_REQ_SENSE) { + printk("odd, drive didn't want to transfer %x\n", stat); + return 1; + } + } + + /* + * transfer cdb + */ + ob_ide_pio_outsw(drive, IDEREG_DATA, cmd->cdb,sizeof(cmd->cdb)); + ob_ide_400ns_delay(drive); + + /* + * ok, cdb was sent to drive, now do data transfer (if any) + */ + bytes = cmd->buflen; + buffer = cmd->buffer; + do { + unsigned int bc; + + if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) { + ob_ide_error(drive, stat, "busy not clear after cdb"); + cmd->stat = stat; + break; + } + + /* + * transfer complete! + */ + if ((stat & (BUSY_STAT | DRQ_STAT)) == 0) + break; + + if ((stat & (BUSY_STAT | DRQ_STAT)) != DRQ_STAT) + break; + + reason = ob_ide_pio_readb(drive, IDEREG_NSECTOR); + lcyl = ob_ide_pio_readb(drive, IDEREG_LCYL); + hcyl = ob_ide_pio_readb(drive, IDEREG_HCYL); + + /* + * check if the drive wants to transfer data in the same + * direction as we do... + */ + if ((reason & IREASON_CD) && cmd->data_direction != atapi_ddir_read) { + ob_ide_error(drive, stat, "atapi, bad transfer ddir"); + break; + } + + bc = (hcyl << 8) | lcyl; + if (!bc) + break; + + if (bc > bytes) + bc = bytes; + + if (cmd->data_direction == atapi_ddir_read) + ob_ide_pio_insw(drive, IDEREG_DATA, buffer, bc); + else + ob_ide_pio_outsw(drive, IDEREG_DATA, buffer, bc); + + bytes -= bc; + buffer += bc; + + ob_ide_400ns_delay(drive); + } while (bytes); + + if (cmd->data_direction != atapi_ddir_none) + (void) ob_ide_wait_stat(drive, 0, BUSY_STAT, &stat); + + if (bytes) + printk("cdb failed, bytes=%d, stat=%x\n", bytes, stat); + + return (stat & ERR_STAT) || bytes; +} + +/* + * execute a packet command, with retries if appropriate + */ +static int +ob_ide_atapi_packet(struct ide_drive *drive, struct atapi_command *cmd) +{ + int retries = 5, ret; + + if (drive->type != ide_type_atapi) + return 1; + if (cmd->buflen > 0xffff) + return 1; + + /* + * retry loop + */ + do { + ret = ob_ide_pio_packet(drive, cmd); + if (!ret) + break; + + /* + * request sense failed, bummer + */ + if (cmd->cdb[0] == ATAPI_REQ_SENSE) + break; + + if (ob_ide_atapi_request_sense(drive)) + break; + + /* + * we know sense is valid. retry if the drive isn't ready, + * otherwise don't bother. + */ + if (cmd->sense.sense_key != ATAPI_SENSE_NOT_READY) + break; + /* + * ... except 'medium not present' + */ + if (cmd->sense.asc == 0x3a) + break; + + udelay(1000000); + } while (retries--); + + if (ret) + ob_ide_error(drive, 0, "atapi command"); + + return ret; +} + +static int +ob_ide_atapi_request_sense(struct ide_drive *drive) +{ + struct atapi_command *cmd = &drive->channel->atapi_cmd; + unsigned char old_cdb; + + /* + * save old cdb for debug error + */ + old_cdb = cmd->cdb[0]; + + memset(cmd, 0, sizeof(*cmd)); + cmd->cdb[0] = ATAPI_REQ_SENSE; + cmd->cdb[4] = 18; + cmd->buffer = (unsigned char *) &cmd->sense; + cmd->buflen = 18; + cmd->data_direction = atapi_ddir_read; + cmd->old_cdb = old_cdb; + + if (ob_ide_atapi_packet(drive, cmd)) + return 1; + + cmd->sense_valid = 1; + return 0; +} + +/* + * make sure drive is ready and media loaded + */ +static int +ob_ide_atapi_drive_ready(struct ide_drive *drive) +{ + struct atapi_command *cmd = &drive->channel->atapi_cmd; + struct atapi_capacity cap; + + /* + * Test Unit Ready is like a ping + */ + memset(cmd, 0, sizeof(*cmd)); + cmd->cdb[0] = ATAPI_TUR; + + if (ob_ide_atapi_packet(drive, cmd)) { + printk("%d: TUR failed\n", drive->nr); + return 1; + } + + /* + * don't force load of tray (bit 2 in byte 4 of cdb), it's + * annoying and we don't want to deal with errors from drives + * that cannot do it + */ + memset(cmd, 0, sizeof(*cmd)); + cmd->cdb[0] = ATAPI_START_STOP_UNIT; + cmd->cdb[4] = 0x01; + + if (ob_ide_atapi_packet(drive, cmd)) { + printk("%d: START_STOP unit failed\n", drive->nr); + return 1; + } + + /* + * finally, get capacity and block size + */ + memset(cmd, 0, sizeof(*cmd)); + memset(&cap, 0, sizeof(cap)); + + cmd->cdb[0] = ATAPI_READ_CAPACITY; + cmd->buffer = (unsigned char *) ∩ + cmd->buflen = sizeof(cap); + cmd->data_direction = atapi_ddir_read; + + if (ob_ide_atapi_packet(drive, cmd)) { + drive->sectors = 0x1fffff; + drive->bs = 2048; + return 1; + } + + drive->sectors = __be32_to_cpu(cap.lba) + 1; + drive->bs = __be32_to_cpu(cap.block_size); + return 0; +} + +/* + * read from an atapi device, using READ_10 + */ +static int +ob_ide_read_atapi(struct ide_drive *drive, unsigned long long block, char *buf, + unsigned int sectors) +{ + struct atapi_command *cmd = &drive->channel->atapi_cmd; + + if (ob_ide_atapi_drive_ready(drive)) + return 1; + + memset(cmd, 0, sizeof(*cmd)); + + /* + * READ_10 should work on generally any atapi device + */ + cmd->cdb[0] = ATAPI_READ_10; + cmd->cdb[2] = (block >> 24) & 0xff; + cmd->cdb[3] = (block >> 16) & 0xff; + cmd->cdb[4] = (block >> 8) & 0xff; + cmd->cdb[5] = block & 0xff; + cmd->cdb[7] = (sectors >> 8) & 0xff; + cmd->cdb[8] = sectors & 0xff; + + cmd->buffer = buf; + cmd->buflen = sectors * 2048; + cmd->data_direction = atapi_ddir_read; + + return ob_ide_atapi_packet(drive, cmd); +} + +static int +ob_ide_read_ata_chs(struct ide_drive *drive, unsigned long long block, + char *buf, unsigned int sectors) +{ + struct ata_command *cmd = &drive->channel->ata_cmd; + unsigned int track = (block / drive->sect); + unsigned int sect = (block % drive->sect) + 1; + unsigned int head = (track % drive->head); + unsigned int cyl = (track / drive->head); + struct ata_sector ata_sector; + + /* + * fill in chs command to read from disk at given location + */ + cmd->buffer = buf; + cmd->buflen = sectors * 512; + + ata_sector.all = sectors; + cmd->nsector = ata_sector.low; + cmd->sector = sect; + cmd->lcyl = cyl; + cmd->hcyl = cyl >> 8; + cmd->device_head = head; + + cmd->command = WIN_READ; + + return ob_ide_pio_data_in(drive, cmd); +} + +static int +ob_ide_read_ata_lba28(struct ide_drive *drive, unsigned long long block, + char *buf, unsigned int sectors) +{ + struct ata_command *cmd = &drive->channel->ata_cmd; + + memset(cmd, 0, sizeof(*cmd)); + + /* + * fill in 28-bit lba command to read from disk at given location + */ + cmd->buffer = buf; + cmd->buflen = sectors * 512; + + cmd->nsector = sectors; + cmd->sector = block; + cmd->lcyl = block >>= 8; + cmd->hcyl = block >>= 8; + cmd->device_head = ((block >> 8) & 0x0f); + cmd->device_head |= (1 << 6); + + cmd->command = WIN_READ; + + return ob_ide_pio_data_in(drive, cmd); +} + +static int +ob_ide_read_ata_lba48(struct ide_drive *drive, unsigned long long block, + char *buf, unsigned int sectors) +{ + struct ata_command *cmd = &drive->channel->ata_cmd; + struct ata_sector ata_sector; + + memset(cmd, 0, sizeof(*cmd)); + + cmd->buffer = buf; + cmd->buflen = sectors * 512; + ata_sector.all = sectors; + + /* + * we are using tasklet addressing here + */ + cmd->task[2] = ata_sector.low; + cmd->task[3] = ata_sector.high; + cmd->task[4] = block; + cmd->task[5] = block >> 8; + cmd->task[6] = block >> 16; + cmd->task[7] = block >> 24; + cmd->task[8] = (u64) block >> 32; + cmd->task[9] = (u64) block >> 40; + + cmd->command = WIN_READ_EXT; + + ob_ide_write_tasklet(drive, cmd); + + return ob_ide_pio_data_in(drive, cmd); +} +/* + * read 'sectors' sectors from ata device + */ +static int +ob_ide_read_ata(struct ide_drive *drive, unsigned long long block, char *buf, + unsigned int sectors) +{ + unsigned long long end_block = block + sectors; + const int need_lba48 = (end_block > (1ULL << 28)) || (sectors > 255); + + if (end_block > drive->sectors) + return 1; + if (need_lba48 && drive->addressing != ide_lba48) + return 1; + + /* + * use lba48 if we have to, otherwise use the faster lba28 + */ + if (need_lba48) + return ob_ide_read_ata_lba48(drive, block, buf, sectors); + else if (drive->addressing != ide_chs) + return ob_ide_read_ata_lba28(drive, block, buf, sectors); + + return ob_ide_read_ata_chs(drive, block, buf, sectors); +} + +static int +ob_ide_read_sectors(struct ide_drive *drive, unsigned long long block, + char *buf, unsigned int sectors) +{ + if (!sectors) + return 1; + if (block + sectors > drive->sectors) + return 1; + +#ifdef CONFIG_DEBUG_IDE + printk("ob_ide_read_sectors: block=%Ld sectors=%u\n", (unsigned long) block, sectors); +#endif + + if (drive->type == ide_type_ata) + return ob_ide_read_ata(drive, block, buf, sectors); + else + return ob_ide_read_atapi(drive, block, buf, sectors); +} + +/* + * byte swap the string if necessay, and strip leading/trailing blanks + */ +static void +ob_ide_fixup_string(unsigned char *s, unsigned int len) +{ + unsigned char *p = s, *end = &s[len & ~1]; + + /* + * if little endian arch, byte swap the string + */ +#ifdef CONFIG_LITTLE_ENDIAN + for (p = end ; p != s;) { + unsigned short *pp = (unsigned short *) (p -= 2); + *pp = __be16_to_cpu(*pp); + } +#endif + + while (s != end && *s == ' ') + ++s; + while (s != end && *s) + if (*s++ != ' ' || (s != end && *s && *s != ' ')) + *p++ = *(s-1); + while (p != end) + *p++ = '\0'; +} + +/* + * it's big endian, we need to swap (if on little endian) the items we use + */ +static int +ob_ide_fixup_id(struct hd_driveid *id) +{ + ob_ide_fixup_string(id->model, 40); + id->config = __le16_to_cpu(id->config); + id->lba_capacity = __le32_to_cpu(id->lba_capacity); + id->cyls = __le16_to_cpu(id->cyls); + id->heads = __le16_to_cpu(id->heads); + id->sectors = __le16_to_cpu(id->sectors); + id->command_set_2 = __le16_to_cpu(id->command_set_2); + id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2); + + return 0; +} + +static int +ob_ide_identify_drive(struct ide_drive *drive) +{ + struct ata_command *cmd = &drive->channel->ata_cmd; + struct hd_driveid id; + + memset(cmd, 0, sizeof(*cmd)); + cmd->buffer = (unsigned char *) &id; + cmd->buflen = 512; + + if (drive->type == ide_type_ata) + cmd->command = WIN_IDENTIFY; + else if (drive->type == ide_type_atapi) + cmd->command = WIN_IDENTIFY_PACKET; + else { + printk("%s: called with bad device type %d\n", __FUNCTION__, drive->type); + return 1; + } + + if (ob_ide_pio_data_in(drive, cmd)) + return 1; + + ob_ide_fixup_id(&id); + + if (drive->type == ide_type_atapi) { + drive->media = (id.config >> 8) & 0x1f; + drive->sectors = 0x7fffffff; + drive->bs = 2048; + drive->max_sectors = 31; + } else { + drive->media = ide_media_disk; + drive->sectors = id.lba_capacity; + drive->bs = 512; + drive->max_sectors = 255; + +#ifdef CONFIG_IDE_LBA48 + if ((id.command_set_2 & 0x0400) && (id.cfs_enable_2 & 0x0400)) { + drive->addressing = ide_lba48; + drive->max_sectors = 65535; + } else +#endif + if (id.capability & 2) + drive->addressing = ide_lba28; + else { + drive->addressing = ide_chs; + } + + /* only set these in chs mode? */ + drive->cyl = id.cyls; + drive->head = id.heads; + drive->sect = id.sectors; + } + + strcpy(drive->model, id.model); + return 0; +} + +/* + * identify type of devices on channel. must have already been probed. + */ +static void +ob_ide_identify_drives(struct ide_channel *chan) +{ + struct ide_drive *drive; + int i; + + for (i = 0; i < 2; i++) { + drive = &chan->drives[i]; + + if (!drive->present) + continue; + + ob_ide_identify_drive(drive); + } +} + +/* + * software reset (ATA-4, section 8.3) + */ +static void +ob_ide_software_reset(struct ide_drive *drive) +{ + struct ide_channel *chan = drive->channel; + + ob_ide_pio_writeb(drive, IDEREG_CONTROL, IDECON_NIEN | IDECON_SRST); + ob_ide_400ns_delay(drive); + ob_ide_pio_writeb(drive, IDEREG_CONTROL, IDECON_NIEN); + ob_ide_400ns_delay(drive); + + /* + * if master is present, wait for BUSY clear + */ + if (chan->drives[0].present) + ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL); + + /* + * if slave is present, wait until it allows register access + */ + if (chan->drives[1].present) { + unsigned char sectorn, sectorc; + int timeout = 1000; + + do { + /* + * select it + */ + ob_ide_pio_writeb(drive, IDEREG_CURRENT, IDEHEAD_DEV1); + ob_ide_400ns_delay(drive); + + sectorn = ob_ide_pio_readb(drive, IDEREG_SECTOR); + sectorc = ob_ide_pio_readb(drive, IDEREG_NSECTOR); + + if (sectorc == 0x01 && sectorn == 0x01) + break; + + } while (--timeout); + } + + /* + * reset done, reselect original device + */ + drive->channel->selected = -1; + ob_ide_select_drive(drive); +} + +/* + * this serves as both a device check, and also to verify that the drives + * we initially "found" are really there + */ +static void +ob_ide_device_type_check(struct ide_drive *drive) +{ + unsigned char sc, sn, cl, ch, st; + + if (ob_ide_select_drive(drive)) + return; + + sc = ob_ide_pio_readb(drive, IDEREG_NSECTOR); + sn = ob_ide_pio_readb(drive, IDEREG_SECTOR); + + if (sc == 0x01 && sn == 0x01) { + /* + * read device signature + */ + cl = ob_ide_pio_readb(drive, IDEREG_LCYL); + ch = ob_ide_pio_readb(drive, IDEREG_HCYL); + st = ob_ide_pio_readb(drive, IDEREG_STATUS); + if (cl == 0x14 && ch == 0xeb) + drive->type = ide_type_atapi; + else if (cl == 0x00 && ch == 0x00 && st != 0x00) + drive->type = ide_type_ata; + else + drive->present = 0; + } else + drive->present = 0; +} + +/* + * pure magic + */ +static void +ob_ide_device_check(struct ide_drive *drive) +{ + unsigned char sc, sn; + + /* + * non-existing io port should return 0xff, don't probe this + * channel at all then + */ + if (ob_ide_pio_readb(drive, IDEREG_STATUS) == 0xff) { + drive->channel->present = 0; + return; + } + + if (ob_ide_select_drive(drive)) + return; + + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0x55); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0xaa); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0xaa); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0x55); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0x55); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0xaa); + + sc = ob_ide_pio_readb(drive, IDEREG_NSECTOR); + sn = ob_ide_pio_readb(drive, IDEREG_SECTOR); + + /* + * we _think_ the device is there, we will make sure later + */ + if (sc == 0x55 && sn == 0xaa) { + drive->present = 1; + drive->type = ide_type_unknown; + } +} + +/* + * probe the legacy ide ports and find attached devices. + */ +static void +ob_ide_probe(struct ide_channel *chan) +{ + struct ide_drive *drive; + int i; + + for (i = 0; i < 2; i++) { + drive = &chan->drives[i]; + + ob_ide_device_check(drive); + + /* + * no point in continuing + */ + if (!chan->present) + break; + + if (!drive->present) + continue; + + /* + * select and reset device + */ + if (ob_ide_select_drive(drive)) + continue; + + ob_ide_software_reset(drive); + + ob_ide_device_type_check(drive); + } +} + +/* + * The following functions are interfacing with OpenBIOS. They + * are device node methods. Thus they have to do proper stack handling. + * + */ + +/* + * 255 sectors for ata lba28, 65535 for lba48, and 31 sectors for atapi + */ +static int +ob_ide_max_transfer(int *idx) +{ + struct ide_drive *drive=&ob_ide_channels[idx[1]].drives[idx[0]]; + + return (drive->max_sectors * drive->bs); +} + +int +ob_ide_read_blocks(struct ide_drive *drive, int n, grub_uint32_t blk, char* dest) +{ + int cnt = n; + while (n) { + int len = n; + if (len > drive->max_sectors) + len = drive->max_sectors; + + grub_dprintf("ob_ide", "reading %d sectors from blk %d\n",len, blk); + if (ob_ide_read_sectors(drive, blk, dest, len)) { + return n-1; + } + grub_dprintf("ob_ide", "done\n"); + + dest += len * drive->bs; + n -= len; + blk += len; + } + + return (cnt); +} + +static int +ob_ide_block_size(int *idx) +{ + struct ide_drive *drive=&ob_ide_channels[idx[1]].drives[idx[0]]; + return(drive->bs); +} + +int ob_ide_init(int (*func)(struct ide_drive*)) +{ + int i, j; + + for (i = 0; i < IDE_NUM_CHANNELS; i++) { + struct ide_channel *chan = &ob_ide_channels[i]; + + chan->mmio = 0; + + for (j = 0; j < 8; j++) + chan->io_regs[j] = io_ports[i] + j; + + chan->io_regs[8] = ctl_ports[i]; + chan->io_regs[9] = ctl_ports[i] + 1; + + chan->obide_inb = ob_ide_inb; + chan->obide_insw = ob_ide_insw; + chan->obide_outb = ob_ide_outb; + chan->obide_outsw = ob_ide_outsw; + + chan->selected = -1; + + /* + * assume it's there, if not io port dead check will clear + */ + chan->present = 1; + + for (j = 0; j < 2; j++) { + chan->drives[j].present = 0; + chan->drives[j].unit = j; + chan->drives[j].channel = chan; + /* init with a decent value */ + chan->drives[j].bs = 512; + + chan->drives[j].nr = i * 2 + j; + } + + ob_ide_probe(chan); + + if (!chan->present) + continue; + + ob_ide_identify_drives(chan); + + for (j = 0; j < 2; j++) { + struct ide_drive *drive = &chan->drives[j]; + + if (!drive->present) + continue; + + if (func(drive)!=0) return 1; + } + } + + return 0; +} ============================================================ --- disk/i386/linuxbios/ide.h 8478f35af95718caaae47dafdbf387b64980c75e +++ disk/i386/linuxbios/ide.h 8478f35af95718caaae47dafdbf387b64980c75e @@ -0,0 +1,221 @@ +#ifndef IDE_H +#define IDE_H + +#include "hdreg.h" + +/* + * legacy ide ports + */ +#define IDEREG_DATA 0x00 +#define IDEREG_ERROR 0x01 +#define IDEREG_FEATURE IDEREG_ERROR +#define IDEREG_NSECTOR 0x02 +#define IDEREG_SECTOR 0x03 +#define IDEREG_LCYL 0x04 +#define IDEREG_HCYL 0x05 +#define IDEREG_CURRENT 0x06 +#define IDEREG_STATUS 0x07 +#define IDEREG_COMMAND IDEREG_STATUS +#define IDEREG_CONTROL 0x08 +#define IDEREG_ASTATUS IDEREG_CONTROL + +/* + * device control bits + */ +#define IDECON_NIEN 0x02 +#define IDECON_SRST 0x04 + +/* + * device head bits + */ +#define IDEHEAD_LBA 0x40 +#define IDEHEAD_DEV0 0x00 +#define IDEHEAD_DEV1 0x10 + +/* + * status bytes + */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +#define IREASON_CD 0x01 +#define IREASON_IO 0x02 + +/* + * ATA opcodes + */ +#define WIN_READ 0x20 +#define WIN_READ_EXT 0x24 +#define WIN_IDENTIFY 0xEC +#define WIN_PACKET 0xA0 +#define WIN_IDENTIFY_PACKET 0xA1 + +/* + * ATAPI opcodes + */ +#define ATAPI_TUR 0x00 +#define ATAPI_READ_10 0x28 +#define ATAPI_REQ_SENSE 0x03 +#define ATAPI_START_STOP_UNIT 0x1b +#define ATAPI_READ_CAPACITY 0x25 + +/* + * atapi sense keys + */ +#define ATAPI_SENSE_NOT_READY 0x02 + +/* + * supported device types + */ +enum { + ide_type_unknown, + ide_type_ata, + ide_type_atapi, +}; + +enum { + ide_media_floppy = 0x00, + ide_media_cdrom = 0x05, + ide_media_optical = 0x07, + ide_media_disk = 0x20, +}; + +/* + * drive addressing + */ +enum { + ide_chs = 1, + ide_lba28, + ide_lba48, +}; + +/* + * simple ata command that works for everything (except 48-bit lba commands) + */ +struct ata_command { + char *buffer; + unsigned int buflen; + + /* + * data register + */ + unsigned char data; + unsigned char feature; + unsigned char nsector; + unsigned char sector; + unsigned char lcyl; + unsigned char hcyl; + unsigned char device_head; + unsigned char command; + unsigned char control; + + /* + * or tasklet, just for lba48 for now (above could be scrapped) + */ + unsigned char task[10]; + + /* + * output + */ + unsigned char stat; + unsigned int bytes; +}; + +struct atapi_command { + unsigned char cdb[12]; + unsigned char *buffer; + unsigned int buflen; + unsigned char data_direction; + + unsigned char stat; + unsigned char sense_valid; + struct request_sense sense; + unsigned char old_cdb; +}; + +struct ide_channel; + +struct ide_drive { + char unit; /* 0: master, 1: slave */ + char present; /* there or not */ + char type; /* ata or atapi */ + char media; /* disk, cdrom, etc */ + char addressing; /* chs/lba28/lba48 */ + + char model[40]; /* name */ + int nr; + + unsigned long sectors; + + unsigned int max_sectors; + + /* + * for legacy chs crap + */ + unsigned int cyl; + unsigned int head; + unsigned int sect; + + unsigned int bs; /* block size */ + + struct ide_channel *channel; +}; + +struct ide_channel { + /* + * either mmio or io_regs is set to indicate mmio or not + */ + int mmio; + int io_regs[10]; + + /* + * can be set to a mmio hook, default it legacy outb/inb + */ + void (*obide_outb)(unsigned char addr, unsigned long port); + unsigned char (*obide_inb)(unsigned long port); + void (*obide_insw)(unsigned long port, unsigned char *addr, unsigned int count); + void (*obide_outsw)(unsigned long port, unsigned char *addr, unsigned int count); + + struct ide_drive drives[2]; + char selected; + char present; + + /* + * only one can be busy per channel + */ + struct ata_command ata_cmd; + struct atapi_command atapi_cmd; + +}; + +enum { + atapi_ddir_none, + atapi_ddir_read, + atapi_ddir_write, +}; + +struct ata_sector { + u16 all; + union { +#ifdef CONFIG_BIG_ENDIAN + u8 high; + u8 low; +#endif +#ifdef CONFIG_LITTLE_ENDIAN + u8 low; + u8 high; +#endif + }; +}; + +int +ob_ide_read_blocks(struct ide_drive *drive, int n, grub_uint32_t blk, char* dest); +static int +ob_ide_atapi_request_sense(struct ide_drive *drive); +int ob_ide_init(int (*func)(struct ide_drive*)); + +#endif ============================================================ --- disk/i386/linuxbios/io.h b96231c3a9c485ce0f573b11dc855abfeefac393 +++ disk/i386/linuxbios/io.h b96231c3a9c485ce0f573b11dc855abfeefac393 @@ -0,0 +1,51 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +extern unsigned long virt_offset; + +#define phys_to_virt(phys) ((void *) ((unsigned long) (phys) - virt_offset)) +#define virt_to_phys(virt) ((unsigned long) (virt) + virt_offset) + +#define __SLOW_DOWN_IO "outb %%al,$0x80;" +static inline void slow_down_io(void) +{ + __asm__ __volatile__( + __SLOW_DOWN_IO +#ifdef REALLY_SLOW_IO + __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO +#endif + : : ); +} + +#define BUILDIO(bwl,bw,type) \ +static inline void out##bwl(unsigned type value, int port) { \ + __asm__ __volatile__("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port)); \ +} \ +static inline unsigned type in##bwl(int port) { \ + unsigned type value; \ + __asm__ __volatile__("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port)); \ + return value; \ +} \ +static inline void out##bwl##_p(unsigned type value, int port) { \ + out##bwl(value, port); \ + slow_down_io(); \ +} \ +static inline unsigned type in##bwl##_p(int port) { \ + unsigned type value = in##bwl(port); \ + slow_down_io(); \ + return value; \ +} \ +static inline void outs##bwl(int port, const void *addr, unsigned long count) { \ + __asm__ __volatile__("rep; outs" #bwl : "+S"(addr), "+c"(count) : "d"(port)); \ +} \ +static inline void ins##bwl(int port, void *addr, unsigned long count) { \ + __asm__ __volatile__("rep; ins" #bwl : "+D"(addr), "+c"(count) : "d"(port)); \ +} + +#ifndef BOOTSTRAP +BUILDIO(b,b,char) +BUILDIO(w,w,short) +BUILDIO(l,,int) +#endif + +#endif ============================================================ --- disk/i386/linuxbios/romdisk.c cebc3f4f13029470b9344e5554d3f53ea6a18503 +++ disk/i386/linuxbios/romdisk.c cebc3f4f13029470b9344e5554d3f53ea6a18503 @@ -0,0 +1,71 @@ +#include +#include +#include + +static int +grub_rom_iterate (int (*hook) (const char *name)) +{ + if (hook ("rom")) + return 1; + return 0; +} + +static grub_err_t +grub_rom_open (const char *name, grub_disk_t disk) +{ + grub_uint32_t romsize = 0; + grub_uint32_t romstart = 0; + if (grub_strcmp ("rom", name) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device"); + romsize = *(grub_uint32_t *)0xfffffff4; + romstart = 0UL-romsize; + disk->total_sectors = romsize / GRUB_DISK_SECTOR_SIZE + 1; + disk->data = (void*)romstart; + disk->has_partitions = 0; + return 0; +} + +static void +grub_rom_close (grub_disk_t disk __attribute ((unused))) +{ +} + +static grub_err_t +grub_rom_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + size *= GRUB_DISK_SECTOR_SIZE; + grub_memcpy(buf, disk->data + (sector * GRUB_DISK_SECTOR_SIZE), size); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_rom_write (grub_disk_t disk __attribute ((unused)), + grub_disk_addr_t sector __attribute ((unused)), + grub_size_t size __attribute ((unused)), + const char *buf __attribute ((unused))) +{ + return GRUB_ERR_NOT_IMPLEMENTED_YET; +} + +static struct grub_disk_dev grub_rom_dev = + { + .name = "rom", + .id = GRUB_DISK_DEVICE_ROM_ID, + .iterate = grub_rom_iterate, + .open = grub_rom_open, + .close = grub_rom_close, + .read = grub_rom_read, + .write = grub_rom_write, + .next = 0 + }; + +GRUB_MOD_INIT(rom) +{ + grub_disk_dev_register (&grub_rom_dev); +} + +GRUB_MOD_FINI(rom) +{ + grub_disk_dev_unregister (&grub_rom_dev); +} ============================================================ --- disk/i386/linuxbios/timer.h e4a5373692f4e7f14f2484ae13a68ce7059e48a0 +++ disk/i386/linuxbios/timer.h e4a5373692f4e7f14f2484ae13a68ce7059e48a0 @@ -0,0 +1,61 @@ +/* Taken from Etherboot */ +/* Defines for routines to implement a low-overhead timer for drivers */ + + /* + * This program 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, or (at + * your option) any later version. + */ + +#ifndef TIMER_H +#define TIMER_H + +/* Ports for the 8254 timer chip */ +#define TIMER2_PORT 0x42 +#define TIMER_MODE_PORT 0x43 + +/* Meaning of the mode bits */ +#define TIMER0_SEL 0x00 +#define TIMER1_SEL 0x40 +#define TIMER2_SEL 0x80 +#define READBACK_SEL 0xC0 + +#define LATCH_COUNT 0x00 +#define LOBYTE_ACCESS 0x10 +#define HIBYTE_ACCESS 0x20 +#define WORD_ACCESS 0x30 + +#define MODE0 0x00 +#define MODE1 0x02 +#define MODE2 0x04 +#define MODE3 0x06 +#define MODE4 0x08 +#define MODE5 0x0A + +#define BINARY_COUNT 0x00 +#define BCD_COUNT 0x01 + +/* Timers tick over at this rate */ +#define CLOCK_TICK_RATE 1193180U +#define TICKS_PER_MS (CLOCK_TICK_RATE/1000) + +/* Parallel Peripheral Controller Port B */ +#define PPC_PORTB 0x61 + +/* Meaning of the port bits */ +#define PPCB_T2OUT 0x20 /* Bit 5 */ +#define PPCB_SPKR 0x02 /* Bit 1 */ +#define PPCB_T2GATE 0x01 /* Bit 0 */ + +/* +extern void setup_timers(void); +extern void ndelay(unsigned int nsecs); +extern void udelay(unsigned int usecs); +extern void mdelay(unsigned int msecs); +extern unsigned long currticks(void); +extern unsigned long get_timer_freq(void); +*/ +#define TICKS_PER_SEC 1000 + +#endif /* TIMER_H */ ============================================================ --- fs/lar.c b8c46ee854ee5f03d0115cb456d9595aabd2afda +++ fs/lar.c b8c46ee854ee5f03d0115cb456d9595aabd2afda @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#include + +static int +grub_lar_check_signature(char* block) +{ + if ((block[0]=='L') && + (block[1]=='A') && + (block[2]=='R') && + (block[3]=='C') && + (block[4]=='H') && + (block[5]=='I') && + (block[6]=='V') && + (block[7]=='E')) return 0; + grub_dprintf("lar", "signature check failed\n"); + return 1; +} + +static grub_ssize_t +grub_lar_read_chunk (grub_device_t device, char *buf, + grub_uint32_t start, grub_uint32_t len) +{ + int offset = start % GRUB_DISK_SECTOR_SIZE; + int sector = start / GRUB_DISK_SECTOR_SIZE; + int l; + l = len; + while (len > 0) { + int rlen = GRUB_DISK_SECTOR_SIZE - offset; + if (rlen > len) rlen = len; + grub_disk_read (device->disk, sector, offset, + rlen, buf); + offset = 0; + sector ++; + buf+=rlen; + len -= rlen; + } + return l; +} + +static grub_err_t +grub_lar_mount (grub_disk_t disk) +{ + char block[8]; + + grub_disk_read (disk, 0, 0, 8, block); + if (grub_lar_check_signature (block) == 0) return GRUB_ERR_NONE; + grub_error (GRUB_ERR_BAD_FS, "not a lar filesystem"); + return GRUB_ERR_BAD_FS; +} + +static struct lar_file { + char signature[8]; + grub_uint32_t raw_file_size; + char pad1[12]; + grub_uint32_t header_size; /* includes filename */ + grub_uint32_t compression; + char filename[0]; +}; + +static grub_err_t +grub_lar_next_file (grub_device_t device, grub_uint32_t *offset) +{ + struct lar_file chunk; + grub_lar_read_chunk (device, (char*)&chunk, *offset, sizeof(chunk)); + if (grub_lar_check_signature (chunk.signature)) return GRUB_ERR_FILE_NOT_FOUND; + *offset = ALIGN_UP(*offset + grub_be_to_cpu32(chunk.header_size) + grub_be_to_cpu32(chunk.raw_file_size),16); + if ((*offset / GRUB_DISK_SECTOR_SIZE) > (device->disk->total_sectors)) + return GRUB_ERR_FILE_NOT_FOUND; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_lar_dir (grub_device_t device, const char* path, + int (*hook) (const char *filename, int dir)) +{ + char buffer[512]; + struct lar_file *chunk = &buffer; + int len; + grub_uint32_t offset = 0; + grub_disk_t disk = device->disk; + char *pathname = 0, *filename = 0; + + if (grub_lar_mount(disk)!= GRUB_ERR_NONE) return grub_errno; + path++; /* strip leading slash */ + + len = grub_strlen (path); + if ((len > 0) && (path[len - 1] == '/')) + /* strip trailing slash */ + { + int i = grub_strlen(path); + char* tmp = grub_malloc (i); + grub_memcpy (tmp, path, i); + tmp[i-1] = 0; + path = tmp; + } + grub_dprintf("lar", "requested files in %s\n", path); + len = grub_strlen(path); + + do + { + grub_lar_read_chunk (device, (char*)chunk, offset, sizeof(buffer)); + if (grub_lar_check_signature (chunk->signature)) return GRUB_ERR_FILE_NOT_FOUND; + if (chunk->compression != 0) continue; + if (len == 0) + { + if (pathname) grub_free (pathname); + pathname = grub_malloc (1); + pathname[0] = 0; + + if (filename) grub_free (filename); + filename = grub_malloc (grub_strlen (chunk->filename) + 1); + grub_strcpy (filename, chunk->filename); + } else { + if (chunk->filename[len]!='/') + continue; /* can't be the directory we search for */ + chunk->filename[len]=0; /* split filename from lar in path and filename */ + + if (pathname) grub_free (pathname); + pathname = grub_malloc (grub_strlen (chunk->filename) + 1); + grub_strcpy (pathname, chunk->filename); + + if (filename) grub_free (filename); + filename = grub_malloc (grub_strlen (chunk->filename + len + 1) + 1); + grub_strcpy (filename, chunk->filename+len+1); + } + if (grub_strcmp (path, pathname) == 0) + { + int is_dir = 0; + char* val; + if ((val = grub_strchr(filename, '/')) != 0) + { + /* is directory. mark as such and strip everything starting at the first slash */ + is_dir = 1; + val[0]=0; + } + grub_dprintf("lar", "calling back for %s, dir state: %d\n",filename, is_dir); + if (hook) hook (filename, is_dir); + } + } while (grub_lar_next_file(device, &offset) == GRUB_ERR_NONE); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_lar_open (grub_file_t file, const char *name) +{ + char buffer[512]; + struct lar_file *chunk = &buffer; + grub_uint32_t offset = 0; + + name++; /* strip leading slash */ + + file->size = -1; + if (grub_lar_mount(file->device->disk) != GRUB_ERR_NONE) return grub_errno; + grub_dprintf("lar", "attempting to open %s\n", name); + + do { + grub_lar_read_chunk (file->device, (char*)chunk, offset, sizeof(buffer)); + if (grub_lar_check_signature (chunk->signature)) return GRUB_ERR_FILE_NOT_FOUND; + if ((chunk->compression == 0) && (grub_strcmp (chunk->filename, name) == 0)) { + grub_dprintf("lar", "found %s\n", chunk->filename); + file->size = grub_be_to_cpu32 (chunk->raw_file_size); + file->data = offset + grub_be_to_cpu32 (chunk->header_size); + return GRUB_ERR_NONE; + } + } while (grub_lar_next_file(file->device, &offset) == GRUB_ERR_NONE); + + return GRUB_ERR_FILE_NOT_FOUND; +} + +static grub_ssize_t +grub_lar_read (grub_file_t file, char *buf, grub_size_t len) +{ + grub_dprintf("lar", "reading 0x%x bytes, starting at 0x%x\n",len, (grub_uint32_t)file->data); + if (len > file->size) len = file->size; + grub_lar_read_chunk (file->device, buf, (grub_uint32_t)file->data, len); +} + +static grub_err_t +grub_lar_close (grub_file_t file) +{ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_lar_label (grub_device_t device, char **label) +{ + *label="firmware"; + return GRUB_ERR_NONE; +} + +static struct grub_fs grub_lar_fs = + { + .name = "lar", + .dir = grub_lar_dir, + .open = grub_lar_open, + .read = grub_lar_read, + .close = grub_lar_close, + .label = grub_lar_label, + .next = 0 + }; + +GRUB_MOD_INIT(lar) +{ + grub_fs_register (&grub_lar_fs); +} + +GRUB_MOD_FINI(lar) +{ + grub_fs_unregister (&grub_lar_fs); +} ============================================================ --- include/grub/i386/linuxbios/console.h c2bb51e46226a8fa4d1cec997b881e688e2d3e86 +++ include/grub/i386/linuxbios/console.h c2bb51e46226a8fa4d1cec997b881e688e2d3e86 @@ -0,0 +1,59 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005 Free Software Foundation, Inc. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef GRUB_CONSOLE_MACHINE_HEADER +#define GRUB_CONSOLE_MACHINE_HEADER 1 + +/* Define scan codes. */ +#define GRUB_CONSOLE_KEY_LEFT 0x4B00 +#define GRUB_CONSOLE_KEY_RIGHT 0x4D00 +#define GRUB_CONSOLE_KEY_UP 0x4800 +#define GRUB_CONSOLE_KEY_DOWN 0x5000 +#define GRUB_CONSOLE_KEY_IC 0x5200 +#define GRUB_CONSOLE_KEY_DC 0x5300 +#define GRUB_CONSOLE_KEY_BACKSPACE 0x0008 +#define GRUB_CONSOLE_KEY_HOME 0x4700 +#define GRUB_CONSOLE_KEY_END 0x4F00 +#define GRUB_CONSOLE_KEY_NPAGE 0x4900 +#define GRUB_CONSOLE_KEY_PPAGE 0x5100 + +#ifndef ASM_FILE + +#include +#include + +/* These are global to share code between C and asm. */ +extern grub_uint8_t grub_console_cur_color; +void grub_console_real_putchar (int c); +int EXPORT_FUNC(grub_console_checkkey) (void); +int EXPORT_FUNC(grub_console_getkey) (void); +grub_uint16_t grub_console_getxy (void); +void grub_console_gotoxy (grub_uint8_t x, grub_uint8_t y); +void grub_console_cls (void); +void grub_console_setcursor (int on); + +/* Initialize the console system. */ +void grub_console_init (void); + +/* Finish the console system. */ +void grub_console_fini (void); + +#endif + +#endif /* ! GRUB_CONSOLE_MACHINE_HEADER */ ============================================================ --- include/grub/i386/linuxbios/init.h 65fc3ab337376e39eeefce69119c7499999e7fdd +++ include/grub/i386/linuxbios/init.h 65fc3ab337376e39eeefce69119c7499999e7fdd @@ -0,0 +1,56 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_INIT_MACHINE_HEADER +#define GRUB_INIT_MACHINE_HEADER 1 + +#include +#include + +/* FIXME: Should these be declared in memory.h? */ +extern grub_size_t EXPORT_VAR(grub_lower_mem); +extern grub_size_t EXPORT_VAR(grub_upper_mem); + +extern grub_addr_t EXPORT_VAR(grub_os_area_addr); +extern grub_size_t EXPORT_VAR(grub_os_area_size); + +/* Get the memory size in KB. If EXTENDED is zero, return conventional + memory, otherwise return extended memory. */ +grub_uint16_t grub_get_memsize (int extended); + +/* Get a packed EISA memory map. Lower 16 bits are between 1MB and 16MB + in 1KB parts, and upper 16 bits are above 16MB in 64KB parts. */ +grub_uint32_t grub_get_eisa_mmap (void); + +struct grub_machine_mmap_entry +{ + grub_uint32_t size; + grub_uint64_t addr; + grub_uint64_t len; + grub_uint32_t type; +}; + +/* Get a memory map entry. Return next continuation value. Zero means + the end. */ +grub_uint32_t grub_get_mmap_entry (struct grub_machine_mmap_entry *entry, + grub_uint32_t cont); + +/* Turn on/off Gate A20. */ +void grub_gate_a20 (int on); + +#endif /* ! GRUB_INIT_MACHINE_HEADER */ ============================================================ --- include/grub/i386/linuxbios/kernel.h ac5c2d95a3d02f58bd437101586db64d190b4274 +++ include/grub/i386/linuxbios/kernel.h ac5c2d95a3d02f58bd437101586db64d190b4274 @@ -0,0 +1,47 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003 Free Software Foundation, Inc. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef KERNEL_MACHINE_HEADER +#define KERNEL_MACHINE_HEADER 1 + +#ifndef ASM_FILE + +#include + +#define GRUB_MOD_ALIGN 0x1000 + +/* The DOS partition number of the installed partition. */ +extern grub_int32_t grub_install_dos_part; + +/* The BSD partition number of the installed partition. */ +extern grub_int32_t grub_install_bsd_part; + +/* The prefix which points to the directory where GRUB modules and its + configuration file are located. */ +extern char grub_prefix[]; + +/* The boot BIOS drive number. */ +extern grub_int32_t grub_boot_drive; + +/* The end address of the kernel. */ +extern grub_addr_t grub_end_addr; + +#endif /* ! ASM_FILE */ + +#endif /* ! KERNEL_MACHINE_HEADER */ ============================================================ --- include/grub/i386/linuxbios/loader.h a798b7b410aed11839883fdd29697d9ce7125a50 +++ include/grub/i386/linuxbios/loader.h a798b7b410aed11839883fdd29697d9ce7125a50 @@ -0,0 +1,42 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2007 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_LOADER_MACHINE_HEADER +#define GRUB_LOADER_MACHINE_HEADER 1 + +#include +#include +#include + +extern grub_addr_t EXPORT_VAR(grub_os_area_addr); +extern grub_size_t EXPORT_VAR(grub_os_area_size); + +/* The asm part of the multiboot loader. */ +void EXPORT_FUNC(grub_multiboot_real_boot) (grub_addr_t entry, + struct grub_multiboot_info *mbi) + __attribute__ ((noreturn)); +void EXPORT_FUNC(grub_multiboot2_real_boot) (grub_addr_t entry, + struct grub_multiboot_info *mbi) + __attribute__ ((noreturn)); + +/* It is necessary to export these functions, because normal mode commands + reuse rescue mode commands. */ +void grub_rescue_cmd_linux (int argc, char *argv[]); +void grub_rescue_cmd_initrd (int argc, char *argv[]); + +#endif /* ! GRUB_LOADER_MACHINE_HEADER */ ============================================================ --- include/grub/i386/linuxbios/serial.h 387a103ce2d3b9752a3bded41190234696c39c9f +++ include/grub/i386/linuxbios/serial.h 387a103ce2d3b9752a3bded41190234696c39c9f @@ -0,0 +1,67 @@ +/* serial.h - serial device interface */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000,2001,2002,2005,2007 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_SERIAL_MACHINE_HEADER +#define GRUB_SERIAL_MACHINE_HEADER 1 + +/* Macros. */ + +/* The offsets of UART registers. */ +#define UART_TX 0 +#define UART_RX 0 +#define UART_DLL 0 +#define UART_IER 1 +#define UART_DLH 1 +#define UART_IIR 2 +#define UART_FCR 2 +#define UART_LCR 3 +#define UART_MCR 4 +#define UART_LSR 5 +#define UART_MSR 6 +#define UART_SR 7 + +/* For LSR bits. */ +#define UART_DATA_READY 0x01 +#define UART_EMPTY_TRANSMITTER 0x20 + +/* The type of parity. */ +#define UART_NO_PARITY 0x00 +#define UART_ODD_PARITY 0x08 +#define UART_EVEN_PARITY 0x18 + +/* The type of word length. */ +#define UART_5BITS_WORD 0x00 +#define UART_6BITS_WORD 0x01 +#define UART_7BITS_WORD 0x02 +#define UART_8BITS_WORD 0x03 + +/* The type of the length of stop bit. */ +#define UART_1_STOP_BIT 0x00 +#define UART_2_STOP_BITS 0x04 + +/* the switch of DLAB. */ +#define UART_DLAB 0x80 + +/* Enable the FIFO. */ +#define UART_ENABLE_FIFO 0xC7 + +/* Turn on DTR, RTS, and OUT2. */ +#define UART_ENABLE_MODEM 0x0B + +#endif /* ! GRUB_SERIAL_MACHINE_HEADER */ ============================================================ --- include/grub/i386/linuxbios/time.h 7f262727d1028e1cad6c63031dca50f2512d32d2 +++ include/grub/i386/linuxbios/time.h 7f262727d1028e1cad6c63031dca50f2512d32d2 @@ -0,0 +1,30 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005 Free Software Foundation, Inc. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef KERNEL_TIME_HEADER +#define KERNEL_TIME_HEADER 1 + +#include + +#define GRUB_TICKS_PER_SECOND 18 + +/* Return the real time in ticks. */ +grub_uint32_t EXPORT_FUNC (grub_get_rtc) (void); + +#endif /* ! KERNEL_TIME_HEADER */ ============================================================ --- include/stdint.h 872aaba8c1cadfdb97827e64916ff6ecb84a1cd6 +++ include/stdint.h 872aaba8c1cadfdb97827e64916ff6ecb84a1cd6 @@ -0,0 +1,10 @@ +#ifndef GRUB_STDINT_HEADER +#define GRUB_STDINT_HEADER + +#include + +#define __WORDSIZE 32 +typedef grub_uint32_t uint32_t; +typedef grub_uint64_t uint64_t; + +#endif ============================================================ --- kern/i386/linuxbios/cmain.c 2b4330140725a1d422084356472646d32fdd137a +++ kern/i386/linuxbios/cmain.c 2b4330140725a1d422084356472646d32fdd137a @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char grub_prefix[50]="(rom)\0"; +extern char* _end; + +grub_size_t grub_lower_mem, grub_upper_mem; +grub_addr_t grub_os_area_addr; +grub_size_t grub_os_area_size; + +void +grub_machine_init (void) +{ + grub_int32_t* lbtable = (void*)0x500; + + grub_console_init(); + if (*lbtable != 'OIBL') + { + grub_fatal("LinuxBIOSv3 table not found!"); + } + lbtable += (lbtable[1]/sizeof(lbtable)); + for (;lbtable[1] != 0; lbtable += (lbtable[1]/sizeof(lbtable))) + { + if (*lbtable==1) + { + struct mem_range + { + grub_int32_t start; + grub_int32_t start_hi; + grub_int32_t size; + grub_int32_t size_hi; + grub_int32_t type; + }; + struct mem_range* mem; + grub_int32_t maxmem = 0; + grub_int32_t usablemem = 0; + grub_os_area_addr = 0; + grub_os_area_size = 0; + for (mem = (struct mem_range*)&lbtable[2]; mem < lbtable+lbtable[1]/sizeof(lbtable); mem++) + { + if ((mem->start_hi!=0) || (mem->size_hi!=0)) { + grub_fatal("memory range >32bit given in LBv3's memory table"); + } + if (mem->start + mem->size > maxmem) maxmem = mem->start + mem->size; + usablemem += mem->size; + } + for (mem = (struct mem_range*)&lbtable[2]; mem < lbtable+lbtable[1]/sizeof(lbtable); mem++) + { + if ((mem->type == 1) && (mem->size > 0)) { + if (mem->start + mem->size > 0x100000) { + if (mem->start < 0x100000) { + mem->size -= 0x100000 - mem->start; + mem->start = 0x100000; + } + if (mem->start = 0x100000) { + grub_os_area_addr = 0x100000; + grub_os_area_size = mem->size / 4; + mem->size = grub_os_area_size * 3; + mem->start += grub_os_area_size; + } + grub_mm_init_region((void*)mem->start,mem->size); + } + } + } + grub_lower_mem = 0x100000; + grub_upper_mem = maxmem - grub_lower_mem; + } + } +} + +void +grub_machine_fini (void) +{ +grub_console_fini(); +} + +void +grub_machine_set_prefix (void) +{ + grub_env_set ("prefix", grub_prefix); +} + +grub_addr_t +grub_arch_modules_addr (void) +{ + return ALIGN_UP(&_end, GRUB_MOD_ALIGN); +} + +void +grub_arch_sync_caches (void) +{} + +void +grub_get_rtc (void) +{} + +void +grub_exit (void) +{} + +void +grub_multiboot2_real_boot(grub_addr_t entry, struct grub_multiboot_info *mbi) +{ + void (*f)() = entry; + f(); + grub_fatal("the client is not supposed to come back!"); +} + +void +grub_multiboot_real_boot(grub_addr_t entry, struct grub_multiboot_info *mbi) +{ + grub_dl_unload_all(); + + asm( + "movl %0, %%ebx;" + "movl %2, %%eax;" + "jmp *%1" : + : "r"(mbi), "r"(entry), "i"(MULTIBOOT_MAGIC2) + : "eax", "ebx"); + grub_fatal("the client is not supposed to come back!"); +} ============================================================ --- kern/i386/linuxbios/console.c 5f357fde333283981d80f69ced284a12534687c4 +++ kern/i386/linuxbios/console.c 5f357fde333283981d80f69ced284a12534687c4 @@ -0,0 +1,357 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005 Free Software Foundation, Inc. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +grub_uint8_t grub_console_cur_color = 0x7; +static grub_uint8_t grub_console_standard_color = 0x7; +static grub_uint8_t grub_console_normal_color = 0x7; +static grub_uint8_t grub_console_highlight_color = 0x70; + +int consolex,consoley; +char* videomem=(char*)0xb8000; + +/* Read a byte from a port. */ +static inline unsigned char +inb (unsigned short port) +{ + unsigned char value; + + asm volatile ("inb %w1, %0" : "=a" (value) : "Nd" (port)); + + return value; +} + +/* Write a byte to a port. */ +static inline void +outb (unsigned short port, unsigned char value) +{ + asm volatile ("outb %b0, %w1" : : "a" (value), "Nd" (port)); +} + +static int normalkeycodemap[128] = { +/*0 1 2 3 4 5 6 7 8 9 a b c d e f*/ +-1,'\e','1','2','3','4','5','6','7','8','9','0','-','=','\b','\t', +'q','w','e','r','t','y','u','i','o','p','[',']','\n',-1,'a','s', +'d','f','g','h','j','k','l',';','\'',-1,-1,'\\','z','x','c','v', +'b','n','m',',','.','/', -1, -1, -1,' ', -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static int shiftedkeycodemap[128] = { +/*0 1 2 3 4 5 6 7 8 9 a b c d e f*/ +-1,'\e','!','@','#','$','%','^','&','*','(',')','_','+','\b','\t', +'Q','W','E','R','T','Y','U','I','O','P','{','}','\n',-1,'A','S', +'D','F','G','H','J','K','L',':','"', -1, -1,'|','Z','X','C','V', +'B','N','M','<','>','?', -1, -1, -1,' ', -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static int ctrlmap[128] = { +/*0 1 2 3 4 5 6 7 8 9 a b c d e f*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 17, 23, 5, 18, 20, 25, 21, 9, 15, 16, -1, -1, -1, -1, 1, 19, + 4, 6, 7, 8, 10, 11, 12, -1, -1, -1, -1, -1, 26, 24, 3, 22, + 2, 14, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static int* keycodemap=normalkeycodemap; +static int shiftkey=0; +static int ctrlkey=0; + +static int wait_for_keycode() { + while ((inb(0x64)&1)==0) ; + return inb(0x60); +} + +static int getkey() { + int keycode=inb(0x60); + switch (keycode) + { + case 0x2a: + case 0x36: + keycodemap=shiftedkeycodemap; + shiftkey++; + break; + case 0xaa: + case 0xb6: + shiftkey--; + if (shiftkey==0) keycodemap=normalkeycodemap; + break; + case 0x1d: + ctrlkey++; + break; + case 0x9d: + ctrlkey--; + break; + default: + break; + } + if (keycode == 0xe0) + { + int key = wait_for_keycode(); + switch (key) + { + case 0x1d: + ctrlkey++; + break; + case 0x9d: + ctrlkey--; + /* cases below this comment are adapted using i386/pc/startup.S's + translation_table */ + case 0x48: + return 16; + case 0x4b: + return 2; + case 0x4d: + return 6; + case 0x50: + return 14; + case 0x47: + return 1; + case 0x4f: + return 5; + case 0x49: + return 7; + case 0x51: + return 3; + case 0x53: + return 4; + default: + break; + } + } + if (keycode >= 0x80) + { + /* scancode set 1 encodes break as +0x80 */ + return -1; + } + if (ctrlkey>0) + { + return ctrlmap[keycode]; + } + return keycodemap[keycode]; +} + +int +grub_console_checkkey (void) +{ + if ((inb(0x64)&1)==0) return -1; + return getkey(); +} + +int grub_console_getkey(void) { + int key; + while ((key=grub_console_checkkey())==-1) {} + return key; +} + +grub_uint16_t grub_console_getxy (void) { + return (consolex<<8)+consoley; +} + +void grub_console_gotoxy (grub_uint8_t x, grub_uint8_t y) { + consolex=x; + consoley=y; +} + +void grub_console_cls (void) { + int i; + for (i=0;i<80*25*2;i+=2) { + videomem[i]=32; + videomem[i+1]=grub_console_cur_color; + } +} + +void grub_console_setcursor (int on) { +} + +static grub_uint32_t +map_char (grub_uint32_t c) +{ + if (c > 0x7f) + { + /* Map some unicode characters to the VGA font, if possible. */ + switch (c) + { + case 0x2190: /* left arrow */ + c = 0x1b; + break; + case 0x2191: /* up arrow */ + c = 0x18; + break; + case 0x2192: /* right arrow */ + c = 0x1a; + break; + case 0x2193: /* down arrow */ + c = 0x19; + break; + case 0x2501: /* horizontal line */ + c = 0xc4; + break; + case 0x2503: /* vertical line */ + c = 0xb3; + break; + case 0x250F: /* upper-left corner */ + c = 0xda; + break; + case 0x2513: /* upper-right corner */ + c = 0xbf; + break; + case 0x2517: /* lower-left corner */ + c = 0xc0; + break; + case 0x251B: /* lower-right corner */ + c = 0xd9; + break; + + default: + c = '?'; + break; + } + } + + return c; +} + +static void +grub_console_putchar (grub_uint32_t c) +{ + grub_uint8_t ch=map_char(c); + if (ch>=32) { + videomem[(consoley*80+consolex)*2]=ch; + videomem[(consoley*80+consolex)*2+1]=grub_console_cur_color; + consolex++; + } else if (ch=='\n') { + consolex=0; + consoley++; + } else if (ch=='\t') { + consolex=consolex-(consolex%8)+8; + } else if (ch=='\b') { + consolex--; + if (consolex==-1) consolex=0; + } + if (consolex>=80) { + consoley++; + consolex-=80; + } + if (consoley==25) { + int i; + consoley--; + for (i=0;i<80*24*2;i++) { + videomem[i]=videomem[i+80*2]; + } + for (i=80*24*2;i<80*25*2;i+=2) { + videomem[i]=' '; + videomem[i+1]=grub_console_cur_color; + } + } +} + +static grub_ssize_t +grub_console_getcharwidth (grub_uint32_t c __attribute__ ((unused))) +{ + /* For now, every printable character has the width 1. */ + return 1; +} + +static grub_uint16_t +grub_console_getwh (void) +{ + return (80 << 8) | 25; +} + +static void +grub_console_setcolorstate (grub_term_color_state state) +{ + switch (state) { + case GRUB_TERM_COLOR_STANDARD: + grub_console_cur_color = grub_console_standard_color; + break; + case GRUB_TERM_COLOR_NORMAL: + grub_console_cur_color = grub_console_normal_color; + break; + case GRUB_TERM_COLOR_HIGHLIGHT: + grub_console_cur_color = grub_console_highlight_color; + break; + default: + break; + } +} + +static void +grub_console_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color) +{ + grub_console_normal_color = normal_color; + grub_console_highlight_color = highlight_color; +} + +static struct grub_term grub_console_term = + { + .name = "console", + .init = 0, + .fini = 0, + .putchar = grub_console_putchar, + .getcharwidth = grub_console_getcharwidth, + .checkkey = grub_console_checkkey, + .getkey = grub_console_getkey, + .getwh = grub_console_getwh, + .getxy = grub_console_getxy, + .gotoxy = grub_console_gotoxy, + .cls = grub_console_cls, + .setcolorstate = grub_console_setcolorstate, + .setcolor = grub_console_setcolor, + .setcursor = grub_console_setcursor, + .flags = 0, + .next = 0 + }; + +void +grub_console_init (void) +{ + int tmp; + grub_term_register (&grub_console_term); + grub_term_set_current (&grub_console_term); + while (grub_console_checkkey()!=-1) { + inb(0x60); + } + outb(0x64,0x20); + tmp=inb(0x60)&~0x40; + outb(0x64,0x60); + outb(tmp,0x60); +} + +void +grub_console_fini (void) +{ + grub_term_set_current (&grub_console_term); + grub_term_unregister (&grub_console_term); +} ============================================================ --- kern/i386/linuxbios/crt0.S 3b5acd225e07462ead18db1cff0815ef7efa8328 +++ kern/i386/linuxbios/crt0.S 3b5acd225e07462ead18db1cff0815ef7efa8328 @@ -0,0 +1,68 @@ +/* boot.S - bootstrap the kernel */ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define ASM 1 +#define STACK_SIZE 0x10000 + + .text + + .code32 + .globl start, _start + + /* This entry is not used actually. */ +start: +_start: + jmp multiboot_entry + + /* Align 32 bits boundary. */ + .align 4 + + /* Multiboot header. */ +multiboot_header: + /* magic */ + .long 0x1BADB002 + /* flags */ + .long (1 << 16) + /* checksum */ + .long -0x1BADB002 - (1 << 16) + /* header_addr */ + .long multiboot_header + /* load_addr */ + .long _start + /* load_end_addr */ + .long _edata + /* bss_end_addr */ + .long _end + /* entry_addr */ + .long multiboot_entry + +multiboot_entry: + /* Initialize the stack pointer. */ + movl $(stack + STACK_SIZE), %esp + + /* Reset EFLAGS. */ + pushl $0 + popf + + /* Now enter the C main function... */ + call grub_main + +loop: hlt + jmp loop + + /* Our stack area. */ + .comm stack, STACK_SIZE ============================================================ --- util/i386/linuxbios/grub-mkimage.c 79ac860818d399a47eccca1efcd4adcd6793f478 +++ util/i386/linuxbios/grub-mkimage.c 79ac860818d399a47eccca1efcd4adcd6793f478 @@ -0,0 +1,279 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2005,2006,2007 Free Software Foundation, Inc. + * + * This program 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 this program; 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 + +void +load_modules (grub_addr_t modbase, Elf32_Phdr *phdr, const char *dir, + char *mods[], FILE *out) +{ + char *module_img; + struct grub_util_path_list *path_list; + struct grub_util_path_list *p; + struct grub_module_info *modinfo; + size_t offset; + size_t total_module_size; + + path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); + + offset = sizeof (struct grub_module_info); + total_module_size = sizeof (struct grub_module_info); + for (p = path_list; p; p = p->next) + { + total_module_size += (grub_util_get_image_size (p->name) + + sizeof (struct grub_module_header)); + } + + grub_util_info ("the total module size is 0x%x", total_module_size); + + module_img = xmalloc (total_module_size); + modinfo = (struct grub_module_info *) module_img; + modinfo->magic = grub_cpu_to_le32 (GRUB_MODULE_MAGIC); + modinfo->offset = grub_cpu_to_le32 (sizeof (struct grub_module_info)); + modinfo->size = grub_cpu_to_le32 (total_module_size); + + /* Load all the modules, with headers, into module_img. */ + for (p = path_list; p; p = p->next) + { + struct grub_module_header *header; + size_t mod_size; + + grub_util_info ("adding module %s", p->name); + + mod_size = grub_util_get_image_size (p->name); + + header = (struct grub_module_header *) (module_img + offset); + header->offset = grub_cpu_to_le32 (sizeof (*header)); + header->size = grub_cpu_to_le32 (mod_size + sizeof (*header)); + + grub_util_load_image (p->name, module_img + offset + sizeof (*header)); + + offset += sizeof (*header) + mod_size; + } + + /* Write the module data to the new segment. */ + grub_util_write_image_at (module_img, total_module_size, + grub_cpu_to_le32 (phdr->p_offset), out); + + /* Fill in the rest of the segment header. */ + phdr->p_type = grub_cpu_to_le32 (PT_LOAD); + phdr->p_flags = grub_cpu_to_le32 (PF_R | PF_W | PF_X); + phdr->p_align = grub_cpu_to_le32 (0x1000); + phdr->p_vaddr = grub_cpu_to_le32 (modbase); + phdr->p_paddr = grub_cpu_to_le32 (modbase); + phdr->p_filesz = grub_cpu_to_le32 (total_module_size); + phdr->p_memsz = grub_cpu_to_le32 (total_module_size); +} + +void +add_segments (char *dir, FILE *out, char *mods[]) +{ + Elf32_Ehdr ehdr; + Elf32_Phdr *phdrs = NULL; + Elf32_Phdr *phdr; + FILE *in; + char *kernel_path; + grub_addr_t grub_end = 0; + off_t phdroff; + int i; + + /* Read ELF header. */ + kernel_path = grub_util_get_path (dir, "kernel.elf"); + in = fopen (kernel_path, "rb"); + if (! in) + grub_util_error ("cannot open %s", kernel_path); + + grub_util_read_at (&ehdr, sizeof (ehdr), 0, in); + + phdrs = xmalloc (grub_le_to_cpu16 (ehdr.e_phentsize) + * (grub_le_to_cpu16 (ehdr.e_phnum) + 2)); + /* Copy all existing segments. */ + grub_util_info ("%u segments", grub_le_to_cpu16 (ehdr.e_phnum)); + for (i = 0; i < grub_le_to_cpu16 (ehdr.e_phnum); i++) + { + char *segment_img; + grub_size_t segment_end; + + phdr = phdrs + i; + + /* Read segment header. */ + grub_util_read_at (phdr, sizeof (Elf32_Phdr), + (grub_le_to_cpu32 (ehdr.e_phoff) + + (i * grub_le_to_cpu16 (ehdr.e_phentsize))), + in); + grub_util_info ("copying segment %d, type %d", i, + grub_le_to_cpu32 (phdr->p_type)); + + /* Locate _end. */ + segment_end = grub_le_to_cpu32 (phdr->p_paddr) + + grub_le_to_cpu32 (phdr->p_memsz); + grub_util_info ("segment %u end 0x%lx", i, segment_end); + if (segment_end > grub_end) + grub_end = segment_end; + + /* Read segment data and write it to new file. */ + segment_img = xmalloc (grub_le_to_cpu32 (phdr->p_filesz)); + + grub_util_read_at (segment_img, grub_le_to_cpu32 (phdr->p_filesz), + grub_le_to_cpu32 (phdr->p_offset), in); + grub_util_write_image_at (segment_img, grub_le_to_cpu32 (phdr->p_filesz), + grub_le_to_cpu32 (phdr->p_offset), out); + + free (segment_img); + } + + if (mods[0] != NULL) + { + grub_addr_t modbase; + + /* Place modules just after grub segment. */ + modbase = ALIGN_UP(grub_end, GRUB_MOD_ALIGN); + + /* Construct new segment header for modules. */ + phdr = phdrs + grub_le_to_cpu16 (ehdr.e_phnum); + ehdr.e_phnum = grub_cpu_to_le16 (grub_le_to_cpu16 (ehdr.e_phnum) + 1); + + /* Fill in p_offset so the callees know where to write. */ + phdr->p_offset = grub_cpu_to_le32 (ALIGN_UP (grub_util_get_fp_size (out), + sizeof (long))); + + load_modules (modbase, phdr, dir, mods, out); + } + + /* Don't bother preserving the section headers. */ + ehdr.e_shoff = 0; + ehdr.e_shnum = 0; + ehdr.e_shstrndx = 0; + + /* Append entire segment table to the file. */ + phdroff = ALIGN_UP (grub_util_get_fp_size (out), sizeof (long)); + grub_util_write_image_at (phdrs, grub_le_to_cpu16 (ehdr.e_phentsize) + * grub_le_to_cpu16 (ehdr.e_phnum), phdroff, + out); + + /* Write ELF header. */ + ehdr.e_phoff = grub_cpu_to_le32 (phdroff); + grub_util_write_image_at (&ehdr, sizeof (ehdr), 0, out); + + free (phdrs); + free (kernel_path); +} + +static struct option options[] = + { + {"directory", required_argument, 0, 'd'}, + {"output", required_argument, 0, 'o'}, + {"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 ``grub-mkimage --help'' for more information.\n"); + else + printf ("\ +Usage: grub-mkimage -o FILE [OPTION]... [MODULES]\n\ +\n\ +Make a bootable image of GRUB.\n\ +\n\ +-d, --directory=DIR use images and modules under DIR [default=%s]\n\ +-o, --output=FILE output a generated image to FILE\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 <%s>.\n\ +", GRUB_LIBDIR, PACKAGE_BUGREPORT); + + exit (status); +} + +int +main (int argc, char *argv[]) +{ + FILE *fp; + char *output = NULL; + char *dir = NULL; + + progname = "grub-mkimage"; + + while (1) + { + int c = getopt_long (argc, argv, "d:o:hVvn", options, 0); + if (c == -1) + break; + + switch (c) + { + case 'd': + if (dir) + free (dir); + dir = xstrdup (optarg); + break; + case 'h': + usage (0); + break; + case 'o': + if (output) + free (output); + output = xstrdup (optarg); + break; + case 'V': + printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); + return 0; + case 'v': + verbosity++; + break; + default: + usage (1); + break; + } + } + + if (!output) + usage (1); + + fp = fopen (output, "wb"); + if (! fp) + grub_util_error ("cannot open %s", output); + + add_segments (dir ? : GRUB_LIBDIR, fp, argv + optind); + + fclose (fp); + + return 0; +} ============================================================ --- aclocal.m4 b8c631c45402c8b4aab7fc36fa9df949c296e755 +++ aclocal.m4 7338868d83ce19c2ace4f5f3fea3b6eb83c0c735 @@ -188,10 +188,20 @@ AC_MSG_RESULT([$grub_cv_i386_asm_absolut AC_MSG_RESULT([$grub_cv_i386_asm_absolute_without_asterisk])]) +dnl Build wrapped code with different cflags, restore cflags at the end +dnl Written by Patrick Georgi +dnl grub_WRAP_FOR_CFLAGS([CFLAGS],[actual code]) +AC_DEFUN(grub_WRAP_FOR_CFLAGS, +[save_CFLAGS=$CFLAGS +CFLAGS="$1" +$2 +CFLAGS=$save_CFLAGS]) + dnl Check what symbol is defined as a start symbol. dnl Written by Yoshinori K. Okuji. AC_DEFUN(grub_CHECK_START_SYMBOL, [AC_REQUIRE([AC_PROG_CC]) +grub_WRAP_FOR_CFLAGS([-nostdlib -fno-builtin],[ AC_MSG_CHECKING([if start is defined by the compiler]) AC_CACHE_VAL(grub_cv_check_start_symbol, [AC_TRY_LINK([], [asm ("incl start")], @@ -215,14 +225,18 @@ else elif test "x$grub_cv_check_uscore_start_symbol" = xyes; then AC_DEFINE([START_SYMBOL], [_start]) else - AC_MSG_ERROR([neither start nor _start is defined]) + dnl assume some default in case none exists (eg. libc-less xcompiler) + dnl the code provides both of them + AC_DEFINE([START_SYMBOL], [_start]) fi ]) +]) dnl Check what symbol is defined as a bss start symbol. dnl Written by Michael Hohmoth and Yoshinori K. Okuji. AC_DEFUN(grub_CHECK_BSS_START_SYMBOL, [AC_REQUIRE([AC_PROG_CC]) +grub_WRAP_FOR_CFLAGS([-nostdlib -fno-builtin],[ AC_MSG_CHECKING([if __bss_start is defined by the compiler]) AC_CACHE_VAL(grub_cv_check_uscore_uscore_bss_start_symbol, [AC_TRY_LINK([], [asm ("incl __bss_start")], @@ -259,11 +273,13 @@ fi AC_MSG_ERROR([none of __bss_start, edata or _edata is defined]) fi ]) +]) dnl Check what symbol is defined as an end symbol. dnl Written by Yoshinori K. Okuji. AC_DEFUN(grub_CHECK_END_SYMBOL, [AC_REQUIRE([AC_PROG_CC]) +grub_WRAP_FOR_CFLAGS([-nostdlib -fno-builtin],[ AC_MSG_CHECKING([if end is defined by the compiler]) AC_CACHE_VAL(grub_cv_check_end_symbol, [AC_TRY_LINK([], [asm ("incl end")], @@ -290,6 +306,7 @@ fi AC_MSG_ERROR([neither end nor _end is defined]) fi ]) +]) dnl Check if the C compiler has a bug while using nested functions when dnl mregparm is used on the i386. Some gcc versions do not pass the third ============================================================ --- conf/common.rmk f8272f9ed80664a85a1b2ba66778bdde1c2c5497 +++ conf/common.rmk 25d33b7ade2596be664d5965ed6d50a41211b344 @@ -81,7 +81,7 @@ pkgdata_MODULES += fshelp.mod fat.mod uf # Filing systems. pkgdata_MODULES += fshelp.mod fat.mod ufs.mod ext2.mod ntfs.mod \ minix.mod hfs.mod jfs.mod iso9660.mod xfs.mod affs.mod \ - sfs.mod hfsplus.mod + sfs.mod hfsplus.mod lar.mod # For fshelp.mod. fshelp_mod_SOURCES = fs/fshelp.c @@ -148,6 +148,11 @@ hfsplus_mod_LDFLAGS = $(COMMON_LDFLAGS) hfsplus_mod_CFLAGS = $(COMMON_CFLAGS) hfsplus_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For lar.mod. +lar_mod_SOURCES = fs/lar.c +lar_mod_CFLAGS = $(COMMON_CFLAGS) +lar_mod_LDFLAGS = $(COMMON_LDFLAGS) + # Partition maps. pkgdata_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod ============================================================ --- configure.ac e03be6dfd73f084b632103a9c3add874060d3d84 +++ configure.ac 6fa01a0bd36f4abe88d75a465b7b86651c97d5a1 @@ -65,6 +65,7 @@ if test "x$with_platform" = x; then if test "x$with_platform" = x; then case "$target_cpu"-"$target_vendor" in i386-apple) platform=efi ;; + i386-linuxbios) platform=linuxbios ;; i386-*) platform=pc ;; powerpc-*) platform=ieee1275 ;; sparc64-*) platform=ieee1275 ;; @@ -77,6 +78,7 @@ case "$target_cpu"-"$platform" in # Sanity check. case "$target_cpu"-"$platform" in i386-efi) ;; + i386-linuxbios) ;; i386-pc) ;; powerpc-ieee1275) ;; sparc64-ieee1275) ;; ============================================================ --- include/grub/disk.h 2c6853faed5a4f7e8b65f69f3f79c0035ed2ca57 +++ include/grub/disk.h 0aee188f6926d78e2d1889bc56bab4f5f5266b95 @@ -33,6 +33,8 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_LOOPBACK_ID, GRUB_DISK_DEVICE_EFIDISK_ID, GRUB_DISK_DEVICE_RAID_ID, + GRUB_DISK_DEVICE_ROM_ID, + GRUB_DISK_DEVICE_ATA_ID, GRUB_DISK_DEVICE_LVM_ID, GRUB_DISK_DEVICE_HOST_ID };