Coherent4.2.10/tboot/gift.c
/*
* gift.c -- Prepare a gift of information for the program currently loaded.
*
* To pass a new data structure into the kernel:
*
* 1. Define your new data structure in typed.h. You will probably want
* to define some supporting routines for your data structure. These
* should go in a file by themselves. Be sure to add the file to the
* tboot Makefile.
*
* 2. Write a routine that takes at least an ffp, which will generate your
* data structure and write it into the ffp. The routine should return 0
* if it ran out of space in the FIFO. Other return values are permissible,
* but ignored. Add arguments to prepare_gift() as needed. It is called
* only from the end of execute() in execute.c.
*
* 3. Add a call to your routine to prepare_gift() in the section marked
* FILL THE BOX. This is an if statement with || seperated calls. The
* most important data structures should be called first, because later
* calls will be skipped if the FIFO fills.
*
* 4. In the kernel (probably in a driver) you will want to add a loop to
* look through the gift for your data structure:
*
* FIFO *ffp;
* typed_space *tp;
*
* ffp = fifo_open(&boot_gift, 0); -- Open gift for reading.
*
* if (F_NULL == ffp) {
* indicate_error("Could not open boot_gift.");
* } else {
* while (T_NULL != (tp = fifo_read(ffp))) { -- While not EOFIFO.
* if (T_MYTYPE == tp->ts_type) { -- Is this my type?
* my_handler(tp->ts_data); -- Process the data.
* }
* }
* }
*
* Be sure to include fifo.c and typed.h into your kernel.
*
*/
#include <string.h>
#include <sys/fdisk.h>
#include <sys/typed.h>
#include "tboot.h"
#define GIFTBOX 4096 /* Size of the gift box (maximum size of gift.) */
/* We have to build the gift in the local segment and then copy it in
* place. In a better world, the gift could be built in place.
*/
TYPED_SPACE(local_gift, GIFTBOX, T_FIFO_SIC); /* Static In-Core Fifo. */
/* Prepare a gift of information for the program currently loaded.
*
* The gift is a Static In-Core FIFO whose objects are typed spaces.
*
* argv is the command vector needed by gift_argf().
*
* It should be placed in memory at data_seg:offset.
*/
void
prepare_gift(data_seg, offset, argv)
uint16 data_seg;
uint16 offset;
char *argv[];
{
FIFO *ffp; /* Fifo pointer for a handle. */
typed_space gift_header; /* Header for destination box. */
char buff[sizeof("65536")]; /* For outputting base 10 integers. */
/* Value of ds register, initialized in Startup.s. */
extern uint16 myds;
/* Find out how big a gift we may offer. */
ffcopy(&gift_header, myds, offset, data_seg, sizeof(typed_space));
if (gift_header.ts_size > local_gift.ts_size) {
puts("WARNING: argument structures larger than ");
itobase((int) local_gift.ts_size, buff, 10);
puts(buff);
puts(" bytes are not currently supported.\r\n");
puts("Truncating down from ");
itobase((int) gift_header.ts_size, buff, 10);
puts(buff);
puts(".\r\n");
puts("This is probably harmless.\r\n");
} else {
/* Requested gift is smaller than what we can offer. */
local_gift.ts_size = gift_header.ts_size;
}
/* ASSERTION: local_gift is now no larger than boot_gift. */
/* Open the local gift box. */
if (F_NULL == (ffp = fifo_open(&local_gift, 1))) {
puts("prepare_gift(): Can't open local_gift for writing.\r\n");
puts("prepare_gift(): No information will be passed.\r\n");
return;
}
/* FILL THE BOX. */
/* Stop filling in if we run out of space. */
if ((0 == gift_drive_params(ffp)) ||
(0 == gift_rootdev(ffp)) ||
(0 == gift_argf(ffp, argv))
) {
puts("prepare_gift(): WARNING: not enough room for all arguments.\r\n");
puts("Only ");
itobase((int) ((char *)ffp->f_offset - (char *)ffp->f_space), buff, 10);
puts(buff);
puts(" bytes submitted.\r\n");
}
fifo_close(ffp);
/* Copy the gift into the loaded program. */
ffcopy(offset, data_seg, &local_gift, myds,
(uint16) local_gift.ts_size);
} /* prepare_gift() */
/* Load the BIOS parameters loaded up by the startup code. */
int
gift_drive_params(ffp)
FIFO *ffp;
{
int i;
int num_of_drives;
struct reg r;
BIOS_DISK diskparms;
num_of_drives = get_num_of_drives();
if (verbose_flag) {
puts("Found 0x");
print16(num_of_drives);
puts(" drives.\r\n");
}
for (i = 0; i < num_of_drives; ++i) {
r.r_ax = DISK_PARAMS;
r.r_dx = HARD_DRIVE + i;
intcall(&r, &r, DISKINT); /* Ask the BIOS. */
diskparms.dp_drive = i;
/* ch is the lower 8 bits of number of cylinders.
* The high two bits of cl are the top two bits of
* 10 bit number of cylinders.
*
* The cylinder count is actually 1 short.
*/
diskparms.dp_cylinders = (uint16) (
((LOW(r.r_cx) >> 6) * 256) + /* Top two bits... */
(HIGH(r.r_cx) + 1)
);
/* The head count is actually 1 short. */
diskparms.dp_heads = ((uint16) HIGH(r.r_dx)) + 1;
/* Only the lower 6 bits of cl are the sectors per track. */
diskparms.dp_sectors = (uint16) (SIXBITS & LOW(r.r_cx));
/* Store these parameters for delivery. */
if (T_NULL == fifo_write_untyped(ffp,
&diskparms,
(int32) sizeof(BIOS_DISK),
T_BIOS_DISK)
) {
puts("gift_drive_params() ran out of space.");
return(0);
}
} /* for i = 0 to num_of_drives - 1 */
return(1); /* We didn't run out of space. */
} /* gift_drive_params() */
/*
* We'd really rather have a dynamic in-core fifo, but they are not
* yet implimented. We'll have to settle for a fixed length argument list.
*/
TYPED_SPACE(argf, BLOCK, T_FIFO_SIC);
/*
* To read this item from bootgift, use the procedure outlined above in
* point 4 to find the entry marked T_STR_ARGF. You must then explicitly
* recast it with RETYPE(tp->ts_data, T_FIFO_SIC). Then you can open it
* as a FIFO, with code modeled on point 4 above. This scheme seemed
* the simplest for uniquely identifying the argument FIFO.
* Each element of the FIFO is a T_STR_STR, so ts_data for these is
* just a NUL terminated string.
*/
/*
* Write an argument fifo into ffp from the argument vector argv[].
* Returns 0 if it runs out of space, 1 on success, 2 if it could not
* open the local gift box for some reason.
*/
int
gift_argf(ffp, argv)
FIFO *ffp;
char *argv[];
{
FIFO *argfp; /* For the argument fifo we're going to build. */
char *current_token;
int i;
/* Open the local gift box. */
if (F_NULL == (argfp = fifo_open(&argf, 1))) {
puts("gift_argf(): Can't open local argument fifo for writing.\r\n");
puts("gift_argf(): No command line information will be passed.\r\n");
return(2);
}
current_token = argv[0];
/*
* Build the command fifo.
*/
for (i = 0; NULL != current_token; current_token = argv[++i]) {
if (T_NULL ==
fifo_write_untyped(argfp,
current_token,
(int32) (strlen(current_token) + 1),
T_STR_STR)
) {
puts("gift_argf(): WARNING: Command line too long.\r\n");
puts("Truncating.\r\n");
break;
}
}
/*
* Truncate argf to the minimum size needed.
*/
RESIZE(&argf, fifo_len(argfp));
/*
* Now that we've filled the FIFO, let's mark
* it as an argument fifo.
*/
RETYPE(&argf, T_STR_ARGF);
close(argfp);
/* Write it into ffp. */
if (T_NULL == fifo_write(ffp, &argf)) {
puts("gift_argf() ran out of space.");
return(0);
}
return(1);
} /* gift_argf() */
/*
* Write a structure describing the boot partition into a fifo.
* Returns 1 on success, 0 if it runs out of space, or 2 if it
* can't read the boot block.
*/
int
gift_rootdev(ffp)
FIFO *ffp;
{
#define NOPARTITION 255 /* Convenient illegal partition number. */
#define PART_PER_DRIVE 4 /* Number of partitions per drive. */
BIOS_ROOTDEV myrootdev; /* Build the data to be passed here. */
FDISK_S fp[NPARTN]; /* Room for a partition table from disk. */
int8 i;
extern uint8 drive; /* Drive number from secondary boot. */
extern uint32 first; /* Block number of start of partition. */
/* Fetch the partition table from disk. */
if (0 == fdisk(fp)) {
puts("gift_rootdev() WARNING: invalid boot block.\r\n");
return(2);
}
/* Mark an invalid partition. */
myrootdev.rd_partition = NOPARTITION;
/* Look for the current partition in the table. */
for (i=0; i < NPARTN; ++i) {
if (first == fp[i].p_base) {
myrootdev.rd_partition = i;
break;
}
}
if (NOPARTITION == myrootdev.rd_partition) {
puts("gift_rootdev() WARNING: Can't find my partition.\r\n");
return(2);
}
/* Adjust the partition for the drive number. */
myrootdev.rd_partition += (PART_PER_DRIVE * drive);
if (T_NULL == fifo_write_untyped(ffp,
&myrootdev,
(int32) sizeof(BIOS_ROOTDEV),
T_BIOS_ROOTDEV)
) {
puts("Ran out of space in gift_rootdev().\r\n");
return(0);
} else {
return(1);
}
} /* gift_rootdev() */
/* Dump the contents of boot_gift. */
void
dump_gift()
{
extern typed_space boot_gift;
puts("Dumping boot_gift.\r\n");
dump_fifo(&boot_gift);
}
/* Dump the contents of a fifo. */
void
dump_fifo(fifo)
typed_space *fifo;
{
FIFO *ffp;
typed_space *tp;
puts("Dumping a fifo.\r\n");
if (F_NULL == (ffp = fifo_open(fifo, 0))) { /* Open gift for reading. */
puts("Can't open fifo.\r\n");
return;
}
while (T_NULL != (tp = fifo_read(ffp))) { /* While not EOFIFO. */
switch(tp->ts_type) {
case T_BIOS_DISK:
dump_bios_disk(tp->ts_data);
break;
case T_BIOS_ROOTDEV:
dump_rootdev(tp->ts_data);
break;
case T_FIFO_SIC:
dump_fifo(tp);
break;
case T_STR_STR:
puts("String: ");
puts(tp->ts_data);
break;
case T_STR_ARGF:
RETYPE(tp, T_FIFO_SIC);
dump_fifo(tp);
break;
default:
puts("Unknown type: 0x");
print16(tp->ts_type);
break;
}
puts("\r\n");
}
puts("Nothing more to dump in this fifo.\r\n");
} /* dump_gift() */
/* Dump a T_BIOS_DISK typed_space. */
void
dump_bios_disk(a_disk)
BIOS_DISK *a_disk;
{
char buffer[BLOCK];
puts("Dumping a BIOS_DISK struct.\r\n");
puts("Drive ");
itobase((uint16) a_disk->dp_drive, buffer, 10);
puts(buffer);
puts(": Cylinders=");
itobase((uint16) a_disk->dp_cylinders, buffer, 10);
puts(buffer);
puts(" Heads=");
itobase((uint16) a_disk->dp_heads, buffer, 10);
puts(buffer);
puts(" Sectors per track=");
itobase((uint16) a_disk->dp_sectors, buffer, 10);
puts(buffer);
puts("\r\n");
} /* dump_bios_disk() */
/* Dump a T_BIOS_ROOTDEV typed_space. */
void
dump_rootdev(a_rootdev)
BIOS_ROOTDEV *a_rootdev;
{
puts("Dumping a BIOS_ROOTDEV struct.\r\n");
puts("partition: 0x");
print8(a_rootdev->rd_partition);
puts("\r\n");
} /* dump_rootdev() */