diff options
author | marcel <marcel@FreeBSD.org> | 2008-04-13 19:54:54 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2008-04-13 19:54:54 +0000 |
commit | ecdc3b6d8cb8fe43a5a096731e33c747f18b2c1c (patch) | |
tree | 25a3cecb6daae88c1853a0d3087628903e6d9f72 /sys/geom | |
parent | a3d2be176f396ea6c3fc51b7ca25b82d6680924a (diff) | |
download | FreeBSD-src-ecdc3b6d8cb8fe43a5a096731e33c747f18b2c1c.zip FreeBSD-src-ecdc3b6d8cb8fe43a5a096731e33c747f18b2c1c.tar.gz |
Add the bootcode verb for installing boot code. Boot code
is supported for the MBR, GPT and PC98 schemes, where GPT
installs boot code into the PMBR.
Diffstat (limited to 'sys/geom')
-rw-r--r-- | sys/geom/part/g_part.c | 68 | ||||
-rw-r--r-- | sys/geom/part/g_part.h | 4 | ||||
-rw-r--r-- | sys/geom/part/g_part_gpt.c | 66 | ||||
-rw-r--r-- | sys/geom/part/g_part_if.m | 6 | ||||
-rw-r--r-- | sys/geom/part/g_part_mbr.c | 13 | ||||
-rw-r--r-- | sys/geom/part/g_part_pc98.c | 13 |
6 files changed, 147 insertions, 23 deletions
diff --git a/sys/geom/part/g_part.c b/sys/geom/part/g_part.c index 0b715ac..f05d750 100644 --- a/sys/geom/part/g_part.c +++ b/sys/geom/part/g_part.c @@ -112,6 +112,7 @@ DECLARE_GEOM_CLASS(g_part_class, g_part); enum g_part_ctl { G_PART_CTL_NONE, G_PART_CTL_ADD, + G_PART_CTL_BOOTCODE, G_PART_CTL_COMMIT, G_PART_CTL_CREATE, G_PART_CTL_DELETE, @@ -514,6 +515,48 @@ g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp) } static int +g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp) +{ + struct g_geom *gp; + struct g_part_table *table; + struct sbuf *sb; + int error, sz; + + gp = gpp->gpp_geom; + G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); + g_topology_assert(); + + table = gp->softc; + sz = table->gpt_scheme->gps_bootcodesz; + if (sz == 0) { + error = ENODEV; + goto fail; + } + if (gpp->gpp_codesize != sz) { + error = EINVAL; + goto fail; + } + + error = G_PART_BOOTCODE(table, gpp); + if (error) + goto fail; + + /* Provide feedback if so requested. */ + if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + sbuf_printf(sb, "%s has bootcode\n", gp->name); + sbuf_finish(sb); + gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); + sbuf_delete(sb); + } + return (0); + + fail: + gctl_error(req, "%d", error); + return (error); +} + +static int g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp) { struct g_consumer *cp; @@ -1023,7 +1066,7 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) enum g_part_ctl ctlreq; unsigned int i, mparms, oparms, parm; int auto_commit, close_on_error; - int error, modifies; + int error, len, modifies; G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb)); g_topology_assert(); @@ -1041,6 +1084,12 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL; } break; + case 'b': + if (!strcmp(verb, "bootcode")) { + ctlreq = G_PART_CTL_BOOTCODE; + mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE; + } + break; case 'c': if (!strcmp(verb, "commit")) { ctlreq = G_PART_CTL_COMMIT; @@ -1098,6 +1147,10 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) ap = &req->arg[i]; parm = 0; switch (ap->name[0]) { + case 'b': + if (!strcmp(ap->name, "bootcode")) + parm = G_PART_PARM_BOOTCODE; + break; case 'c': if (!strcmp(ap->name, "class")) continue; @@ -1153,12 +1206,20 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) gctl_error(req, "%d param '%s'", EINVAL, ap->name); return; } - p = gctl_get_asciiparam(req, ap->name); + if (parm == G_PART_PARM_BOOTCODE) + p = gctl_get_param(req, ap->name, &len); + else + p = gctl_get_asciiparam(req, ap->name); if (p == NULL) { gctl_error(req, "%d param '%s'", ENOATTR, ap->name); return; } switch (parm) { + case G_PART_PARM_BOOTCODE: + gpp.gpp_codeptr = p; + gpp.gpp_codesize = len; + error = 0; + break; case G_PART_PARM_ENTRIES: error = g_part_parm_uint(p, &gpp.gpp_entries); break; @@ -1240,6 +1301,9 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) case G_PART_CTL_ADD: error = g_part_ctl_add(req, &gpp); break; + case G_PART_CTL_BOOTCODE: + error = g_part_ctl_bootcode(req, &gpp); + break; case G_PART_CTL_COMMIT: error = g_part_ctl_commit(req, &gpp); break; diff --git a/sys/geom/part/g_part.h b/sys/geom/part/g_part.h index 4ec54f5..196332a 100644 --- a/sys/geom/part/g_part.h +++ b/sys/geom/part/g_part.h @@ -56,6 +56,7 @@ struct g_part_scheme { size_t gps_entrysz; int gps_minent; int gps_maxent; + int gps_bootcodesz; TAILQ_ENTRY(g_part_scheme) scheme_list; }; @@ -134,6 +135,7 @@ struct g_part_entry *g_part_new_entry(struct g_part_table *, int, quad_t, #define G_PART_PARM_START 0x0200 #define G_PART_PARM_TYPE 0x0400 #define G_PART_PARM_VERSION 0x0800 +#define G_PART_PARM_BOOTCODE 0x1000 struct g_part_parms { unsigned int gpp_parms; @@ -148,6 +150,8 @@ struct g_part_parms { quad_t gpp_start; const char *gpp_type; unsigned int gpp_version; + const void *gpp_codeptr; + unsigned int gpp_codesize; }; void g_part_geometry_heads(off_t, u_int, off_t *, u_int *); diff --git a/sys/geom/part/g_part_gpt.c b/sys/geom/part/g_part_gpt.c index c6cd356..cc9cdfc 100644 --- a/sys/geom/part/g_part_gpt.c +++ b/sys/geom/part/g_part_gpt.c @@ -52,6 +52,8 @@ CTASSERT(sizeof(struct gpt_ent) == 128); #define EQUUID(a,b) (memcmp(a, b, sizeof(struct uuid)) == 0) +#define MBRSIZE 512 + enum gpt_elt { GPT_ELT_PRIHDR, GPT_ELT_PRITBL, @@ -70,6 +72,7 @@ enum gpt_state { struct g_part_gpt_table { struct g_part_table base; + u_char mbr[MBRSIZE]; struct gpt_hdr hdr; quad_t lba[GPT_ELT_COUNT]; enum gpt_state state[GPT_ELT_COUNT]; @@ -82,6 +85,7 @@ struct g_part_gpt_entry { static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); +static int g_part_gpt_bootcode(struct g_part_table *, struct g_part_parms *); static int g_part_gpt_create(struct g_part_table *, struct g_part_parms *); static int g_part_gpt_destroy(struct g_part_table *, struct g_part_parms *); static int g_part_gpt_dumpto(struct g_part_table *, struct g_part_entry *); @@ -97,6 +101,7 @@ static int g_part_gpt_write(struct g_part_table *, struct g_consumer *); static kobj_method_t g_part_gpt_methods[] = { KOBJMETHOD(g_part_add, g_part_gpt_add), + KOBJMETHOD(g_part_bootcode, g_part_gpt_bootcode), KOBJMETHOD(g_part_create, g_part_gpt_create), KOBJMETHOD(g_part_destroy, g_part_gpt_destroy), KOBJMETHOD(g_part_dumpto, g_part_gpt_dumpto), @@ -116,6 +121,7 @@ static struct g_part_scheme g_part_gpt_scheme = { .gps_entrysz = sizeof(struct g_part_gpt_entry), .gps_minent = 128, .gps_maxent = INT_MAX, + .gps_bootcodesz = MBRSIZE, }; G_PART_SCHEME_DECLARE(g_part_gpt); @@ -352,6 +358,16 @@ g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry, } static int +g_part_gpt_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) +{ + struct g_part_gpt_table *table; + + table = (struct g_part_gpt_table *)basetable; + bcopy(gpp->gpp_codeptr, table->mbr, DOSPARTOFF); + return (0); +} + +static int g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp) { struct g_provider *pp; @@ -363,13 +379,24 @@ g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp) pp = gpp->gpp_provider; tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) + pp->sectorsize - 1) / pp->sectorsize; - if (pp->sectorsize < 512 || + if (pp->sectorsize < MBRSIZE || pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) * pp->sectorsize) return (ENOSPC); last = (pp->mediasize / pp->sectorsize) - 1; + le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC); + table->mbr[DOSPARTOFF + 1] = 0xff; /* shd */ + table->mbr[DOSPARTOFF + 2] = 0xff; /* ssect */ + table->mbr[DOSPARTOFF + 3] = 0xff; /* scyl */ + table->mbr[DOSPARTOFF + 4] = 0xee; /* typ */ + table->mbr[DOSPARTOFF + 5] = 0xff; /* ehd */ + table->mbr[DOSPARTOFF + 6] = 0xff; /* esect */ + table->mbr[DOSPARTOFF + 7] = 0xff; /* ecyl */ + le32enc(table->mbr + DOSPARTOFF + 8, 1); /* start */ + le32enc(table->mbr + DOSPARTOFF + 12, MIN(last, 0xffffffffLL)); + table->lba[GPT_ELT_PRIHDR] = 1; table->lba[GPT_ELT_PRITBL] = 2; table->lba[GPT_ELT_SECHDR] = last; @@ -469,7 +496,7 @@ g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp) * It's better to catch this pathological case early than behaving * pathologically later on... */ - if (pp->sectorsize < 512 || pp->mediasize < 6 * pp->sectorsize) + if (pp->sectorsize < MBRSIZE || pp->mediasize < 6 * pp->sectorsize) return (ENOSPC); /* Check that there's a MBR. */ @@ -508,11 +535,19 @@ g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp) struct g_provider *pp; struct g_part_gpt_table *table; struct g_part_gpt_entry *entry; - int index; + u_char *buf; + int error, index; table = (struct g_part_gpt_table *)basetable; pp = cp->provider; + /* Read the PMBR */ + buf = g_read_data(cp, 0, pp->sectorsize, &error); + if (buf == NULL) + return (error); + bcopy(buf, table->mbr, MBRSIZE); + g_free(buf); + /* Read the primary header and table. */ gpt_read_hdr(table, cp, GPT_ELT_PRIHDR, &prihdr); if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) { @@ -640,24 +675,13 @@ g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp) tlbsz = (table->hdr.hdr_entries * table->hdr.hdr_entsz + pp->sectorsize - 1) / pp->sectorsize; - if (basetable->gpt_created) { - buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); - le16enc(buf + DOSMAGICOFFSET, DOSMAGIC); - buf[DOSPARTOFF + 1] = 0xff; /* shd */ - buf[DOSPARTOFF + 2] = 0xff; /* ssect */ - buf[DOSPARTOFF + 3] = 0xff; /* scyl */ - buf[DOSPARTOFF + 4] = 0xee; /* typ */ - buf[DOSPARTOFF + 5] = 0xff; /* ehd */ - buf[DOSPARTOFF + 6] = 0xff; /* esect */ - buf[DOSPARTOFF + 7] = 0xff; /* ecyl */ - le32enc(buf + DOSPARTOFF + 8, 1); /* start */ - le32enc(buf + DOSPARTOFF + 12, - MIN(pp->mediasize / pp->sectorsize - 1, 0xffffffffLL)); - error = g_write_data(cp, 0, buf, pp->sectorsize); - g_free(buf); - if (error) - return (error); - } + /* Write the PMBR */ + buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); + bcopy(table->mbr, buf, MBRSIZE); + error = g_write_data(cp, 0, buf, pp->sectorsize); + g_free(buf); + if (error) + return (error); /* Allocate space for the header and entries. */ buf = g_malloc((tlbsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO); diff --git a/sys/geom/part/g_part_if.m b/sys/geom/part/g_part_if.m index fa386d2..bd38854 100644 --- a/sys/geom/part/g_part_if.m +++ b/sys/geom/part/g_part_if.m @@ -47,6 +47,12 @@ METHOD int add { struct g_part_parms *gpp; }; +# bootcode() - scheme specific processing for the bootcode verb. +METHOD int bootcode { + struct g_part_table *table; + struct g_part_parms *gpp; +}; + # create() - scheme specific processing for the create verb. METHOD int create { struct g_part_table *table; diff --git a/sys/geom/part/g_part_mbr.c b/sys/geom/part/g_part_mbr.c index f1800ea..5741b15 100644 --- a/sys/geom/part/g_part_mbr.c +++ b/sys/geom/part/g_part_mbr.c @@ -59,6 +59,7 @@ struct g_part_mbr_entry { static int g_part_mbr_add(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); +static int g_part_mbr_bootcode(struct g_part_table *, struct g_part_parms *); static int g_part_mbr_create(struct g_part_table *, struct g_part_parms *); static int g_part_mbr_destroy(struct g_part_table *, struct g_part_parms *); static int g_part_mbr_dumpto(struct g_part_table *, struct g_part_entry *); @@ -74,6 +75,7 @@ static int g_part_mbr_write(struct g_part_table *, struct g_consumer *); static kobj_method_t g_part_mbr_methods[] = { KOBJMETHOD(g_part_add, g_part_mbr_add), + KOBJMETHOD(g_part_bootcode, g_part_mbr_bootcode), KOBJMETHOD(g_part_create, g_part_mbr_create), KOBJMETHOD(g_part_destroy, g_part_mbr_destroy), KOBJMETHOD(g_part_dumpto, g_part_mbr_dumpto), @@ -93,6 +95,7 @@ static struct g_part_scheme g_part_mbr_scheme = { .gps_entrysz = sizeof(struct g_part_mbr_entry), .gps_minent = NDOSPART, .gps_maxent = NDOSPART, + .gps_bootcodesz = MBRSIZE, }; G_PART_SCHEME_DECLARE(g_part_mbr); @@ -201,6 +204,16 @@ g_part_mbr_add(struct g_part_table *basetable, struct g_part_entry *baseentry, } static int +g_part_mbr_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) +{ + struct g_part_mbr_table *table; + + table = (struct g_part_mbr_table *)basetable; + bcopy(gpp->gpp_codeptr, table->mbr, DOSPARTOFF); + return (0); +} + +static int g_part_mbr_create(struct g_part_table *basetable, struct g_part_parms *gpp) { struct g_consumer *cp; diff --git a/sys/geom/part/g_part_pc98.c b/sys/geom/part/g_part_pc98.c index 9b499f3..05d56f3 100644 --- a/sys/geom/part/g_part_pc98.c +++ b/sys/geom/part/g_part_pc98.c @@ -60,6 +60,7 @@ struct g_part_pc98_entry { static int g_part_pc98_add(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); +static int g_part_pc98_bootcode(struct g_part_table *, struct g_part_parms *); static int g_part_pc98_create(struct g_part_table *, struct g_part_parms *); static int g_part_pc98_destroy(struct g_part_table *, struct g_part_parms *); static int g_part_pc98_dumpto(struct g_part_table *, struct g_part_entry *); @@ -75,6 +76,7 @@ static int g_part_pc98_write(struct g_part_table *, struct g_consumer *); static kobj_method_t g_part_pc98_methods[] = { KOBJMETHOD(g_part_add, g_part_pc98_add), + KOBJMETHOD(g_part_bootcode, g_part_pc98_bootcode), KOBJMETHOD(g_part_create, g_part_pc98_create), KOBJMETHOD(g_part_destroy, g_part_pc98_destroy), KOBJMETHOD(g_part_dumpto, g_part_pc98_dumpto), @@ -94,6 +96,7 @@ static struct g_part_scheme g_part_pc98_scheme = { .gps_entrysz = sizeof(struct g_part_pc98_entry), .gps_minent = NDOSPART, .gps_maxent = NDOSPART, + .gps_bootcodesz = SECSIZE, }; G_PART_SCHEME_DECLARE(g_part_pc98); @@ -184,6 +187,16 @@ g_part_pc98_add(struct g_part_table *basetable, struct g_part_entry *baseentry, } static int +g_part_pc98_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) +{ + struct g_part_pc98_table *table; + + table = (struct g_part_pc98_table *)basetable; + bcopy(gpp->gpp_codeptr, table->boot, DOSMAGICOFFSET); + return (0); +} + +static int g_part_pc98_create(struct g_part_table *basetable, struct g_part_parms *gpp) { struct g_consumer *cp; |