diff --git a/libemile/Makefile b/libemile/Makefile new file mode 100644 index 0000000..992df08 --- /dev/null +++ b/libemile/Makefile @@ -0,0 +1,20 @@ +LIBRARY = libemile.a + +OBJS = emile_first_get_param.o emile_first_set_param.o \ + emile_first_set_param_scsi.o emile_floppy_create_image.o \ + emile_scsi_create_container.o emile_second_get_cmdline.o \ + emile_second_get_kernel.o emile_second_get_output.o \ + emile_second_set_cmdline.o emile_second_set_kernel.o \ + emile_second_set_kernel_scsi.o emile_second_set_output.o + +HEADERS = emile.h libemile.h emile-first.h + +CFLAGS = -Wall + +all: $(LIBRARY) + +$(LIBRARY): $(OBJS) + $(AR) rc $@ $^ + +clean: + rm -f $(OBJS) $(LIBRARY) diff --git a/libemile/bootblock.h b/libemile/bootblock.h new file mode 100644 index 0000000..cdf2368 --- /dev/null +++ b/libemile/bootblock.h @@ -0,0 +1,69 @@ +/* + * + * (c) 2004 Laurent Vivier + * + */ + +/* + * WARNING: remember that m68k is big endian, like powerPC. + * i386 is little-endian + */ + +#ifndef _BOOTBLOCK_H +#define _BOOTBLOCK_H +static __attribute__((used)) char* bootblock_header = "$CVSHeader$"; +#include "../second/glue.h" + +/* first level structure */ + +/* BootBlkHdr Structure: "Inside Macintosh: Files", p. 2-57 */ + +typedef struct BootBlkHdr BootBlkHdr_t; + +struct BootBlkHdr { + u_int16_t ID; /* boot blocks signature */ + u_int32_t Entry; /* entry point to bootcode */ + u_int16_t Version; /* boot blocks version number */ + u_int16_t PageFlags; /* used internally */ + u_int8_t SysName[16]; /* System filename */ + u_int8_t ShellName[16]; /* Finder filename */ + u_int8_t Dbg1Name[16]; /* debugger filename */ + u_int8_t Dbg2Name[16]; /* debugger filename */ + u_int8_t ScreenName[16]; /* name of startup screen */ + u_int8_t HelloName[16]; /* name of startup program */ + u_int8_t ScrapName[16]; /* name of system scrap file */ + u_int16_t CntFCBs; /* number of FCBs to allocate */ + u_int16_t CntEvts; /* number of event queue elements */ + u_int32_t Heap128K; /* system heap size on 128K Mac */ + u_int32_t Heap256K; /* used internally */ + u_int32_t SysHeapSize; /* system heap size on all machines */ +} __attribute__((packed)); + +#define ASSERT_BBH(a) if ( sizeof(BootBlkHdr_t) != 138 ) { a } + +/* EMILE Boot block structure */ + +typedef struct eBootBlock eBootBlock_t; + +struct eBootBlock { + BootBlkHdr_t boot_block_header; + ParamBlockRec_t second_param_block; + u_int8_t boot_code[1024 - sizeof(BootBlkHdr_t) + - sizeof(ParamBlockRec_t)]; +} __attribute__((packed)); + +#define ASSERT_BB(a) if ( sizeof(eBootBlock_t) != 1024 ) { a } + +#define FLOPPY_SECTOR_SIZE 512 +#define FIRST_LEVEL_SIZE (FLOPPY_SECTOR_SIZE * 2) + +static inline unsigned long get_size(char* file) +{ + struct stat result; + + stat(file, &result); + + return (result.st_size + FLOPPY_SECTOR_SIZE - 1) + / FLOPPY_SECTOR_SIZE * FLOPPY_SECTOR_SIZE; +} +#endif diff --git a/libemile/emile.h b/libemile/emile.h new file mode 100644 index 0000000..0cd16df --- /dev/null +++ b/libemile/emile.h @@ -0,0 +1,71 @@ +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#ifndef _EMILE_H +#define _EMILE_H +static __attribute__((used)) char* emile_header = "$CVSHeader$"; +#include + +#if __BYTE_ORDER == __BIG_ENDIAN + +/* nothing to do, because m68k is big endian too */ + +static inline u_int16_t read_short(u_int16_t* addr) +{ + return *addr; +} + +static inline void write_short(u_int16_t* addr, u_int16_t value) +{ + *addr = value; +} + +static inline u_int32_t read_long(u_int32_t* addr) +{ + return *addr; +} + +static inline void write_long(u_int32_t* addr, u_int32_t value) +{ + *addr = value; +} + +#else /* __BYTE_ORDER == __LITTLE_ENDIAN */ + +/* little endian (or unknown), read byte by byte to get it in good order */ + +static inline u_int16_t read_short(u_int16_t* addr) +{ + unsigned char* baddr = (unsigned char*)addr; + + return ((u_int16_t)(*baddr) << 8) | (u_int16_t)*(baddr+1); +} + +static inline void write_short(u_int16_t* addr, u_int16_t value) +{ + unsigned char* baddr = (unsigned char*)addr; + + *baddr = (unsigned char)(value>>8); + *(baddr+1) = (unsigned char)value; +} + +static inline u_int32_t read_long(u_int32_t* addr) +{ + u_int16_t* saddr = (u_int16_t*)addr; + + return ((u_int32_t)read_short(saddr) << 16) | + (u_int32_t)read_short(saddr+1);; +} + +static inline void write_long(u_int32_t* addr, u_int32_t value) +{ + u_int16_t* saddr = (u_int16_t*)addr; + + write_short(saddr, (u_int16_t)(value>>16)); + write_short(saddr+1, (u_int16_t)value); +} +#endif +#endif diff --git a/libemile/emile_first_get_param.c b/libemile/emile_first_get_param.c new file mode 100644 index 0000000..a67b128 --- /dev/null +++ b/libemile/emile_first_get_param.c @@ -0,0 +1,39 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include +#include + +#include "libemile.h" +#include "emile.h" +#include "bootblock.h" + +int emile_first_get_param(int fd, int *drive_num, int *file_ref, + int *second_offset, int *second_size) +{ + eBootBlock_t firstBlock; + int ret; + + ret = read(fd, &firstBlock, sizeof(firstBlock)); + if (ret != sizeof(firstBlock)) + return -1; + + if ( strncmp( firstBlock.boot_block_header.SysName+1, + "Mac Bootloader", 14) == 0 ) + { + *drive_num = read_short(&firstBlock.second_param_block.ioVRefNum); + *file_ref = read_short(&firstBlock.second_param_block.ioRefNum); + *second_offset = read_long(&firstBlock.second_param_block.ioPosOffset); + *second_size = read_long(&firstBlock.second_param_block.ioReqCount); + } + else + return -1; + + return 0; +} diff --git a/libemile/emile_first_set_param.c b/libemile/emile_first_set_param.c new file mode 100644 index 0000000..c5ccc47 --- /dev/null +++ b/libemile/emile_first_set_param.c @@ -0,0 +1,59 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include +#include + +#include "libemile.h" +#include "emile.h" +#include "bootblock.h" + +int emile_first_set_param(int fd, unsigned short tune_mask, int drive_num, + int file_ref, int second_offset, int second_size) +{ + eBootBlock_t firstBlock; + int ret; + off_t location; + + location = lseek(fd, 0, SEEK_CUR); + if (location == -1) + return -1; + + ret = read(fd, &firstBlock, sizeof(firstBlock)); + if (ret != sizeof(firstBlock)) + return -1; + + if ( strncmp( firstBlock.boot_block_header.SysName+1, + "Mac Bootloader", 14) == 0 ) + { + if (tune_mask & EMILE_FIRST_TUNE_DRIVE) + write_short(&firstBlock.second_param_block.ioVRefNum, + drive_num); + + if (tune_mask & EMILE_FIRST_TUNE_OFFSET) + write_long(&firstBlock.second_param_block.ioPosOffset, + second_offset); + + if (tune_mask & EMILE_FIRST_TUNE_SIZE) + write_long(&firstBlock.second_param_block.ioReqCount, + second_size); + + ret = lseek(fd, location, SEEK_SET); + if (ret != 0) + return -1; + + ret = write(fd, &firstBlock, sizeof(firstBlock)); + if (ret != sizeof(firstBlock)) + return -1; + } + else + return -1; + + return 0; +} diff --git a/libemile/emile_first_set_param_scsi.c b/libemile/emile_first_set_param_scsi.c new file mode 100644 index 0000000..2f8bdbd --- /dev/null +++ b/libemile/emile_first_set_param_scsi.c @@ -0,0 +1,87 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include +#include +#include + +#include "libemile.h" + +int emile_first_set_param_scsi(int fd, char *second_name) +{ + int ret; + int fd_second; + char first[1024]; + int i; + int current; + struct emile_container *container; + unsigned short max_blocks; + unsigned short *first_max_blocks = (unsigned short*)&first[1022]; + unsigned long *second_size = (unsigned long*)&first[1018]; + unsigned short *unit_id = (unsigned short*)&first[1016]; + unsigned short *block_size = (unsigned short*)&first[1014]; + unsigned short *count; + unsigned long *offset; + + ret = read(fd, first, 1024); + if (ret == -1) + return 1; + + max_blocks = *first_max_blocks / 6; + + container = (struct emile_container*) + malloc(sizeof(struct emile_container) + + max_blocks * sizeof(struct emile_block)); + if (container == NULL) + return -1; + + container->max_blocks = max_blocks; + fd_second = open(second_name, O_RDONLY); + if (fd_second == -1) + return -1; + + ret = emile_scsi_create_container(fd_second, container); + if (ret != 0) + return -1; + close(fd_second); + + *unit_id = container->unit_id; + *block_size = container->block_size; + + *second_size = 0; + current = 1014; + for(i = 0; i < max_blocks - 1; i++) + { + current -= 2; + count = (short*)(&first[current]); + *count = container->blocks[i].count; + if (container->blocks[i].count == 0) + break; + current -= 4; + offset = (long*)(&first[current]); + *offset = container->blocks[i].offset; + (*second_size) += container->blocks[i].count; + } + /* mark end of blocks list */ + current -= 2; + count = (short*)(&first[current]); + *count = 0; + /* set second level size */ + (*second_size) *= container->block_size; + + ret = lseek(fd, 0, SEEK_SET); + if (ret != 0) + return -1; + + ret = write(fd, first, 1024); + if (ret == -1) + return 1; + + return ret; +} diff --git a/libemile/emile_floppy_create_image.c b/libemile/emile_floppy_create_image.c new file mode 100644 index 0000000..b9aeccf --- /dev/null +++ b/libemile/emile_floppy_create_image.c @@ -0,0 +1,205 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include +#include +#include +#include + +#include "libemile.h" +#include "emile.h" +#include "bootblock.h" + +static int copy_file(int fd, char* file) +{ + int source; + int size_read; + int size_written; + int total; + static char buffer[FLOPPY_SECTOR_SIZE]; + + if (fd < 0) + return -1; + + source = open(file, O_RDONLY); + if (source < 0) + { + close(source); + return -1; + } + + total = 0; + for(;;) + { + size_read = read(source, buffer, FLOPPY_SECTOR_SIZE); + if (size_read == FLOPPY_SECTOR_SIZE) + { + size_written = write(fd, buffer, FLOPPY_SECTOR_SIZE); + total += size_written; + if (size_written != FLOPPY_SECTOR_SIZE) + { + close(source); + return -1; + } + } + else + { + if (size_read == 0) + break; + + memset(buffer + size_read, 0, FLOPPY_SECTOR_SIZE - size_read); + size_written = write(fd, buffer, FLOPPY_SECTOR_SIZE); + total += size_written; + if (size_written != FLOPPY_SECTOR_SIZE) + { + close(source); + return -1; + } + break; + } + } + + close(source); + return total; +} + +static int pad_image(int fd, int size) +{ + static char buffer[FLOPPY_SECTOR_SIZE]; + int size_written; + int total; + + if (fd < 0) + return -1; + + if (size % FLOPPY_SECTOR_SIZE) { + fprintf(stderr, + "WARNING: pad size is not a multiple of sector size\n"); + } + + memset(buffer, 0, FLOPPY_SECTOR_SIZE); + total = 0; + while (size > 0) { + size_written = write(fd, buffer, FLOPPY_SECTOR_SIZE); + total += size_written; + if (size_written != FLOPPY_SECTOR_SIZE) { + return total; + } + size -= size_written; + } + return total; +} + +static int aggregate(int fd, char* first_level, char* second_level, char* kernel_image, char* ramdisk) +{ + int ret; + int total; + + ret = copy_file(fd, first_level); + if (ret < 0) + return 6; + total = ret; + + ret = copy_file(fd, second_level); + if (ret < 0) + return 6; + total += ret; + + if (kernel_image != NULL) + { + ret = copy_file(fd, kernel_image); + if (ret < 0) + return 6; + total += ret; + } + + if (ramdisk != NULL) + { + ret = copy_file(fd, ramdisk); + if (ret < 0) + return 6; + total += ret; + } + + ret = pad_image(fd, 1474560 - total); + if (ret < 0) + return 6; + + return 0; +} + +int emile_floppy_create_image(char* first_level, char* second_level, + char* kernel_image, char* ramdisk, + unsigned long buffer_size, char* image) +{ + int ret; + int fd; + unsigned int second_level_size; + + if (image == NULL) + return -1; + + fd = open(image, O_RDWR|O_CREAT|O_TRUNC, + S_IRUSR| S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + if (fd == -1) + return -1; + + /* aggregating files: first, second, kernel, ramdisk */ + + if (first_level == NULL) + { + close(fd); + return -1; + } + + if (second_level == NULL) + { + close(fd); + return -1; + } + + if (kernel_image == NULL) + fprintf(stderr, "WARNING: kernel image file not defined\n"); + + ret = aggregate(fd, first_level, second_level, kernel_image, ramdisk); + if (ret != 0) + { + close(fd); + return -1; + } + + /* set first level info */ + + ret = emile_first_set_param(fd, EMILE_FIRST_TUNE_DRIVE | + EMILE_FIRST_TUNE_OFFSET| + EMILE_FIRST_TUNE_SIZE, + 1, -5, + FIRST_LEVEL_SIZE, + second_level_size); + if (ret != 0) + { + close(fd); + return -1; + } + + /* set second level info */ + + ret = emile_second_set_kernel(fd, kernel_image, + FIRST_LEVEL_SIZE + get_size(second_level), + buffer_size, ramdisk); + if (ret != 0) + { + close(fd); + return -1; + } + + close(fd); + + return 0; +} diff --git a/libemile/emile_scsi_create_container.c b/libemile/emile_scsi_create_container.c new file mode 100644 index 0000000..a0f403e --- /dev/null +++ b/libemile/emile_scsi_create_container.c @@ -0,0 +1,199 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libemile.h" + +#define MAJOR_SD 8 /* SCSI disks */ + +struct scsi_id { + int dev; + int host_unique_id; +}; + +static int get_scsi_path(int fd, unsigned char *host, unsigned char *channel, + unsigned char *pun, unsigned char *lun) +{ + int ret; + struct scsi_id path; + + ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &path); + + *host = path.dev >> 24; + *channel = path.dev >> 16; + *lun = path.dev >> 8; + *pun = path.dev; + + return ret; +} + +static int get_device_info(int device, int *id, unsigned long *first_block, + int *block_size) +{ + int fd; + int ret; + char dev_name[16]; + int major; + int minor; + struct hd_geometry geom; + unsigned char host; + unsigned char channel; + unsigned char pun; + unsigned char lun; + + major = (device >> 8) & 0x0F; /* major number = driver id */ + minor = device & 0xFF; /* minor number = disk id */ + switch(major) + { + case MAJOR_SD: /* SCSI disks */ + sprintf(dev_name, "/dev/sd%c%d", 'a' + (minor >> 4), + minor & 0x0F); + break; + + default: + fprintf(stderr, "Unknown device major number %d\n", major); + return -1; + } + + fd = open(dev_name, O_RDONLY); + if (fd == 1) { + fprintf(stderr, "Cannot open device %s (%s)\n", dev_name, + strerror(errno)); + return -1; + } + ret = get_scsi_path(fd, &host, &channel, &pun, &lun); + *id = pun; + + ret = ioctl(fd, HDIO_GETGEO, &geom); + if (ret == -1) + { + fprintf(stderr, "%s: ioctl(HDIO_GETGEO) fails: %s", + dev_name, strerror(errno)); + return -1; + } +#if 0 /* BLKSSZGET is buggy on my m68k 2.2.27-pre2 kernel */ + ret = ioctl(fd, BLKSSZGET, block_size); + if (ret == -1) + { + fprintf(stderr, "%s: ioctl(BLKSSZGET) fails: %s", + dev_name, strerror(errno)); + return -1; + } +#else + *block_size = 512; +#endif + *first_block = geom.start; + close(fd); + + return 0; +} + +#define ADD_BLOCK(a, b) \ + container->blocks[current].offset = (a); \ + container->blocks[current].count = (b); \ + current++; \ + if (current > container->max_blocks) \ + { \ + fprintf(stderr, "Container overflow\n");\ + return -1; \ + } + +int emile_scsi_create_container(int fd, struct emile_container* container) +{ + int ret; + struct stat st; + int id; + unsigned long first_block; + int sector_size; + int block_size; + int sectors_per_block; + int current; + int logical; + int physical; + int last_physical; + int num_blocks; + int zone; + int aggregate; + int dev; + + ret = fstat(fd, &st); + if (ret == -1) { + perror("stat()"); + return -1; + } + + dev = S_ISREG(st.st_mode) ? st.st_dev : st.st_rdev; + + ret = get_device_info(dev, &id, &first_block, §or_size); + if (ret != 0) + return -1; + + container->unit_id = (u_int16_t)id; + container->block_size = (u_int16_t)sector_size; + + /* get filesystem block size */ + + ret = ioctl(fd, FIGETBSZ, &block_size); + if (ret != 0) { + perror("ioctl(FIGETBSZ)"); + return -1; + } + + sectors_per_block = block_size / sector_size; + + /* get first physical block */ + + last_physical = 0; + ret = ioctl(fd, FIBMAP, &last_physical); + if (ret != 0) { + perror("ioctl(FIBMAP)"); + return -1; + } + + zone = last_physical; + aggregate = 1; + + /* seek all physical blocks */ + + num_blocks = (st.st_size + st.st_blksize - 1) / st.st_blksize; + current = 0; + for (logical = 1; logical < num_blocks; logical++) { + physical = logical; + ret = ioctl(fd, FIBMAP, &physical); + if (ret != 0) + break; + if (physical == last_physical + 1) { + aggregate++; + } else { + ADD_BLOCK(first_block + zone * sectors_per_block, + aggregate * sectors_per_block); + zone = physical; + aggregate = 1; + } + last_physical = physical; + } + + ADD_BLOCK(first_block + zone * sectors_per_block, + aggregate * sectors_per_block); + + /* end of list */ + + ADD_BLOCK(0, 0); + + return 0; +} diff --git a/libemile/emile_second_get_cmdline.c b/libemile/emile_second_get_cmdline.c new file mode 100644 index 0000000..68ecd1f --- /dev/null +++ b/libemile/emile_second_get_cmdline.c @@ -0,0 +1,35 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include +#include + +#include "libemile.h" +#include "emile.h" +#include "../second/head.h" + +int emile_second_set_cmdline(int fd, char* cmdline) +{ + emile_l2_header_t header; + int ret; + + ret = read(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -1; + + if (!EMILE_COMPAT(EMILE_02_SIGNATURE, read_long(&header.signature))) + { + fprintf(stderr, "Bad Header signature\n"); + return -1; + } + + strncpy(cmdline, header.command_line, 256); + + return 0; +} diff --git a/libemile/emile_second_get_kernel.c b/libemile/emile_second_get_kernel.c new file mode 100644 index 0000000..c96ca87 --- /dev/null +++ b/libemile/emile_second_get_kernel.c @@ -0,0 +1,34 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include + +#include "libemile.h" +#include "emile.h" + +int emile_second_get_kernel(int fd, u_int32_t *kernel_offset, + u_int32_t *kernel_image_size, + u_int32_t *kernel_size, u_int32_t *ramdisk_offset, + u_int32_t *ramdisk_size) +{ + emile_l2_header_t header; + int ret; + + ret = read(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -1; + + *kernel_offset = read_long(&header.kernel_image_offset); + *kernel_image_size = read_long(&header.kernel_image_size); + *kernel_size = read_long(&header.kernel_size); + *ramdisk_offset = read_long(&header.ramdisk_offset); + *ramdisk_size = read_long(&header.ramdisk_size); + + return 0; +} diff --git a/libemile/emile_second_get_output.c b/libemile/emile_second_get_output.c new file mode 100644 index 0000000..90d7981 --- /dev/null +++ b/libemile/emile_second_get_output.c @@ -0,0 +1,50 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include + +#include "libemile.h" +#include "emile.h" +#include "../second/head.h" + +int emile_second_get_output(int fd, u_int32_t *console_mask, + u_int32_t *bitrate0, int *datasize0, + int *parity0, int *stopbits0, + u_int32_t *bitrate1, int *datasize1, + int *parity1, int *stopbits1, + int *gestaltid) +{ + emile_l2_header_t header; + int ret; + + ret = read(fd, &header, sizeof(header)); + + if (ret != sizeof(header)) + return -1; + + if (!EMILE_COMPAT(EMILE_03_SIGNATURE, read_long(&header.signature))) + { + fprintf(stderr, "Bad Header signature\n"); + return -1; + } + + *console_mask = read_long(&header.console_mask); + *bitrate0 = read_long(&header.serial0_bitrate); + *datasize0 = header.serial0_datasize; + *parity0 = header.serial0_parity; + *stopbits0 = header.serial0_stopbits; + *bitrate1 = read_long(&header.serial1_bitrate); + *datasize1 = header.serial1_datasize; + *parity1 = header.serial1_parity; + *stopbits1 = header.serial1_stopbits; + + *gestaltid = read_long(&header.gestaltID); + + return 0; +} diff --git a/libemile/emile_second_set_cmdline.c b/libemile/emile_second_set_cmdline.c new file mode 100644 index 0000000..66fde1a --- /dev/null +++ b/libemile/emile_second_set_cmdline.c @@ -0,0 +1,49 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include +#include + +#include "libemile.h" +#include "emile.h" +#include "../second/head.h" + +int emile_second_set_cmdline(int fd, char* cmdline) +{ + emile_l2_header_t header; + off_t location; + int ret; + + location = lseek(fd, 0, SEEK_CUR); + if (ret == -1) + return -1; + + ret = read(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -1; + + if (!EMILE_COMPAT(EMILE_02_SIGNATURE, read_long(&header.signature))) + { + fprintf(stderr, "Bad Header signature\n"); + return -1; + } + + strncpy(header.command_line, cmdline, 256); + header.command_line[255] = 0; + + ret = lseek(fd, location, SEEK_SET); + if (ret == -1) + return -1; + + ret = write(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -1; + + return 0; +} diff --git a/libemile/emile_second_set_kernel.c b/libemile/emile_second_set_kernel.c new file mode 100644 index 0000000..d2cd1ba --- /dev/null +++ b/libemile/emile_second_set_kernel.c @@ -0,0 +1,62 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include + +#include "libemile.h" +#include "emile.h" +#include "bootblock.h" + +int emile_second_set_kernel(int fd, char *kernel_image, + u_int32_t kernel_offset, + u_int32_t buffer_size, char* ramdisk) +{ + emile_l2_header_t header; + int ret; + off_t location; + + location = lseek(fd, 0, SEEK_CUR); + if (ret == -1) + return -1; + + ret = read(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -1; + + if (kernel_image != NULL) + { + write_long(&header.kernel_image_offset, kernel_offset); + write_long(&header.kernel_image_size, get_size(kernel_image)); + } + + write_long(&header.kernel_size, buffer_size); + + if (ramdisk == NULL) + { + write_long(&header.ramdisk_offset, 0); + write_long(&header.ramdisk_size, 0); + } + else + { + write_long(&header.ramdisk_offset, + read_long(&header.kernel_image_offset) + + read_long(&header.kernel_image_size)); + write_long(&header.ramdisk_size, get_size(ramdisk)); + } + + ret = lseek(fd, location, SEEK_SET); + if (ret == -1) + return -1; + + ret = write(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -1; + + return 0; +} diff --git a/libemile/emile_second_set_kernel_scsi.c b/libemile/emile_second_set_kernel_scsi.c new file mode 100644 index 0000000..6d2bcfc --- /dev/null +++ b/libemile/emile_second_set_kernel_scsi.c @@ -0,0 +1,102 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#include +#include +#include +#include +#include +#include + +#include "libemile.h" +#include "emile.h" + +int emile_second_set_kernel_scsi(int fd, char *kernel_name) +{ + int fd_kernel; + int ret; + emile_l2_header_t header; + off_t container_offset; + struct emile_container *container; + int max_blocks; + int i; + unsigned long kernel_image_size; + + ret = read(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -1; + + if (!EMILE_COMPAT(EMILE_04_SIGNATURE, read_long(&header.signature))) + return -1; + + container_offset = read_long(&header.kernel_image_offset); + if (container_offset == 0) + return -1; + + ret = lseek(fd, container_offset, SEEK_SET); + if (ret != container_offset) + return -1; + + container = (struct emile_container*) + malloc(sizeof(struct emile_container)); + if (container == NULL) + return -1; + + ret = read(fd, container, sizeof(struct emile_container)); + if (ret != sizeof(struct emile_container)) + return -1; + + max_blocks = container->max_blocks; + + free(container); + container = (struct emile_container*) + malloc(sizeof(struct emile_container) + + max_blocks * sizeof(struct emile_block)); + if (container == NULL) + return -1; + + container->max_blocks = max_blocks; + fd_kernel = open(kernel_name, O_RDONLY); + if (fd_kernel == -1) + return -1; + + ret = emile_scsi_create_container(fd_kernel, container); + if (ret != 0) + return 10; + close(fd_kernel); + + kernel_image_size = 0; + for(i = 0; i < max_blocks; i++) + { + if (container->blocks[i].count == 0) + break; + kernel_image_size += container->blocks[i].count; + } + kernel_image_size *= container->block_size; + + ret = lseek(fd, container_offset, SEEK_SET); + if (ret != container_offset) + return -1; + + ret = write(fd, container, sizeof(struct emile_container) + + max_blocks * sizeof(struct emile_block)); + if (ret != sizeof(struct emile_container) + + max_blocks * sizeof(struct emile_block)) + return -1; + + ret = lseek(fd, 0, SEEK_SET); + if (ret != 0) + return -1; + + header.kernel_image_size = kernel_image_size; + + ret = write(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -2; + + return 0; +} diff --git a/libemile/emile_second_set_output.c b/libemile/emile_second_set_output.c new file mode 100644 index 0000000..688cb54 --- /dev/null +++ b/libemile/emile_second_set_output.c @@ -0,0 +1,80 @@ +static __attribute__((used)) char* rcsid = "$CVSHeader$"; +/* + * + * (c) 2004 Laurent Vivier + * + */ + + +#include +#include +#include + +#include "libemile.h" +#include "emile.h" +#include "../second/head.h" + +int emile_second_set_output(int fd, + u_int32_t enable_mask, u_int32_t disable_mask, + u_int32_t bitrate0, int datasize0, + int parity0, int stopbits0, + u_int32_t bitrate1, int datasize1, + int parity1, int stopbits1, int gestaltid) +{ + emile_l2_header_t header; + off_t location; + int ret; + + location = lseek(fd, 0, SEEK_CUR); + if (location == -1) + return location; + + ret = read(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -1; + + if (!EMILE_COMPAT(EMILE_03_SIGNATURE, read_long(&header.signature))) + { + fprintf(stderr, "Bad Header signature\n"); + return -1; + } + + header.console_mask |= enable_mask; + header.console_mask &= ~disable_mask; + + if (bitrate0) + header.serial0_bitrate = bitrate0; + if (bitrate1) + header.serial1_bitrate = bitrate1; + + if (datasize0 != -1) + header.serial0_datasize = datasize0; + if (datasize1 != -1) + header.serial1_datasize = datasize1; + + if (stopbits0 != -1) + header.serial0_stopbits = stopbits0; + if (stopbits1 != -1) + header.serial1_stopbits = stopbits1; + + if (parity0 != -1) + header.serial0_parity = parity0; + if (parity1 != -1) + header.serial1_parity = parity1; + + header.gestaltID = gestaltid; /* 0 means unset ... */ + + ret = lseek(fd, location, SEEK_SET); + if (ret == -1) + { + perror("Cannot go to buffer offset"); + close(fd); + return 8; + } + + ret = write(fd, &header, sizeof(header)); + if (ret != sizeof(header)) + return -1; + + return 0; +} diff --git a/libemile/libemile.h b/libemile/libemile.h new file mode 100644 index 0000000..c97dab3 --- /dev/null +++ b/libemile/libemile.h @@ -0,0 +1,51 @@ +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#ifndef _LIBEMILE_H +#define _LIBEMILE_H + +static __attribute__((used)) char* libemile_header = "$CVSHeader$"; + +#define SCSI_SUPPORT + +#include "../second/head.h" + +#define EMILE_FIRST_TUNE_DRIVE 0x0001 +#define EMILE_FIRST_TUNE_OFFSET 0x0002 +#define EMILE_FIRST_TUNE_SIZE 0x0004 + +extern int emile_first_set_param(int fd, unsigned short tune_mask, + int drive_num, int file_ref, + int second_offset, int second_size); +extern int emile_first_get_param(int fd, int *drive_num, int *file_ref, + int *second_offset, int *second_size); +extern int emile_first_set_param_scsi(int fd, char *second_name); +extern int emile_second_get_output(int fd, unsigned int *console_mask, + unsigned int *bitrate0, int *datasize0, + int *parity0, int *stopbits0, + unsigned int *bitrate1, int *datasize1, + int *parity1, int *stopbits1, + int *gestaltid); +extern int emile_second_set_output(int fd, + unsigned int enable_mask, + unsigned int disable_mask, + unsigned int bitrate0, int datasize0, + int parity0, int stopbits0, + unsigned int bitrate1, int datasize1, + int parity1, int stopbits1, int gestaltid); +extern int emile_second_set_cmdline(int fd, char* cmdline); +extern int emile_second_get_cmdline(int fd, char* cmdline); +extern int emile_second_set_kernel(int fd, char *kernel_image, + unsigned int kernel_offset, + unsigned int buffer_size, char* ramdisk); +extern int emile_second_get_kernel(int fd, unsigned int *kernel_offset, + unsigned int *kernel_image_size, + unsigned int *buffer_size, + unsigned int *ramdisk_offset, + unsigned int *ramdisk_size); +extern int emile_scsi_create_container(int fd, + struct emile_container* container); +#endif diff --git a/libemile/partition.h b/libemile/partition.h new file mode 100644 index 0000000..9f5bbb9 --- /dev/null +++ b/libemile/partition.h @@ -0,0 +1,66 @@ +/* + * + * (c) 2004 Laurent Vivier + * + */ + +#ifndef _PARTITION_H +#define _PARTITION_H +static __attribute__((used)) char* partition_header = "$CVSHeader$"; + +enum { + kPartitionAUXIsValid= 0x00000001, + kPartitionAUXIsAllocated = 0x00000002, + kPartitionAUXIsInUse= 0x00000004, + kPartitionAUXIsBootValid = 0x00000008, + kPartitionAUXIsReadable = 0x00000010, + kPartitionAUXIsWriteable = 0x00000020, + kPartitionAUXIsBootCodePositionIndependent = 0x00000040, + + kPartitionIsMountedAtStartup = 0x40000000, + kPartitionIsStartup = 0x80000000, + + kPartitionIsChainCompatible = 0x00000100, + kPartitionIsRealDeviceDriver = 0x00000200, + kPartitionCanChainToNext = 0x00000400, +}; + +struct Block0 { + int16_t Sig; + int16_t BlkSize; + int32_t BlkCount; + int16_t DevType; + int16_t DevId; + int32_t Data; + int16_t DrvrCount; + int32_t Block; + int16_t Size; + int16_t Type; + int16_t Pad[243]; +} __attribute__((packed)); +#define ASSERT_B0(a) if ( sizeof(struct Block0) != 512 ) { a } + +struct Partition { + int16_t Sig; + int16_t SigPad; + int32_t MapBlkCnt; + int32_t PyPartStart; + int32_t PartBlkCnt; + char PartName[32]; + char PartType[32]; + int32_t LgDataStart; + int32_t DataCnt; + int32_t PartStatus; + int32_t LgBootStart; + int32_t BootSize; + int32_t BootAddr; + int32_t BootAddr2; + int32_t BootEntry; + int32_t BootEntry2; + int32_t BootCksum; + char Processor[16]; + int16_t Pad[188]; +} __attribute__((packed)); + +#define ASSERT_P(a) if ( sizeof(struct Partition) != 512 ) { a } +#endif