GRUB on DOC: 2Mb issues
David,
since the only DiskOnChip I have is a 2 Mb one, I had to solve some issues with makecsum.c and doc_stage1.S before being able to load/run GRUB as a replacement firmware. The ROM IPL of the 2Mb DOC (or any DOC with page256==1, I guess) loads the first 0x2000 bytes sequentially instead of loading half of the first 0x4000 bytes, as you describe in mtd/grub/README. This requires some modifications to makecsum.c in order to build a valid firmware image. Also, doc_stage1.S doesn't support the addressing scheme needed for 2Mb DOCs, so I had to make a few modifications to make it load GRUB-stage2.
The relevant cvs diffs follow. Notice: these mods make doc_stage1.S and makecsum.c work _only_ for 2Mb DOCs! I'd like to merge this functionality into the existing code, but I'll wait for your feedback. I'd use a simple "#ifdef DOC_PAGE256" both in doc_stage1.S and makecsum.c, but in the long run it would be nice to be able to access the page256 flag (mtd->priv->page256) from userland (page256 in mtd_info_user?).
Cheers,
Ciro
Index: doc_stage1.S
===================================================================
RCS file: /home/cvs/mtd/grub/doc_stage1.S,v
retrieving revision 1.8
diff -r1.8 doc_stage1.S
166c166
< /* Send new READ command - is it READ0 or READ1? */
---
Quoted 1 line
/* Send new READ0 command */
169c169
< andb $1,%ah
---
Quoted 1 line
xorb %ah,%ah
176,177c176
< /* We sent bits 0-7, then 9-16, then 17-23 */
< /* Yes bit 8 is missing. Read the NAND flash specs */
---
Quoted 1 line
/* We sent bits 0-7, then 8-15, then 16-23 */
182,186c181
< /* Bits 9-16 */
< shrw $1,%dx
< .byte 0x80, 0xce /* orb adrbit16, %dh */
< adrbit16:
< .byte 0
---
Quoted 1 line
/* Bits 8-15 */
189c184
< /* Bits 17-23 are also zero */
---
Quoted 1 line
/* Bits 16-23 */
216,217d210
< addb $0x80, %cs:adrbit16 /* Increase bit 16 */
< jnc endloop /* Did it overflow? */
Index: makecsum.c
===================================================================
RCS file: /home/cvs/mtd/grub/makecsum.c,v
retrieving revision 1.1
diff -r1.1 makecsum.c
5c5
< unsigned char buf[16384];
---
Quoted 1 line
unsigned char buf[8192];
12c12
< memset(buf, 0xff, 16384);
---
Quoted 1 line
memset(buf, 0xff, 8192);
61c61
< len = read(st2fd, buf+512, 16384-512);
---
Quoted 1 line
len = read(st2fd, buf+512, 8192-512);
73,74c73
< i=0;
< while (i<16384) {
---
Quoted 1 line
for (i=0 ; i<8192 ; i++)
76,79d74
< i++;
< if ((i >> 8)&1)
< i += 256;
< }
85c80
< len = write(outfd, buf, 16384);
---
Quoted 1 line
len = write(outfd, buf, 8192);
94,95c89,90
< if (len < 16384) {
< fprintf(stderr, "short write of output file (%d bytes < 16384)\n",
---
Quoted 2 lines
if (len < 8192) {
fprintf(stderr, "short write of output file (%d bytes < 8192)\n",105c100
< len = read(st2fd, buf, 16384);
---
Quoted 1 line
len = read(st2fd, buf, 8192);
Signature · 10 lines
Ciro Cattuto, Open Source Developer, Linuxcare Italia SpA Tel. +39.338.3002140 Fax +39.049.8036484 [email protected] http://www.linuxcare.com/ [email protected] http://www.prosa.it/ Linuxcare. Support for the revolution. To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 3 lines · Ciro Cattuto
Also,
doc_stage1.Sdoesn't support the
addressing scheme needed for 2Mb DOCs, so I had to make a few modifications to make it load GRUB-stage2.
I haven't tried your modifications yet, but IMHO it looks right. Thedoc_stage1 should work on both 256 and 512 paged devices without any conditionals. The loop will send a READ0 command, set address such as column(byte)=0 and page(word)=counter++ and read 256 bytes. Of course stage2 needs to be written as described in mtd/grub/README.
It may also be a good idea to send an additional address byte
zero for compatibility with >= 64Mb chips. Datasheet of 2MB says this additional byte would be ignored, but I need to check for all other chips.
Quoted 6 lines
The relevant cvs diffs follow. Notice: these mods make
doc_stage1.Sandmakecsum.cwork _only_ for 2Mb DOCs! I'd like to merge this functionality into the existing code, but I'll wait for your feedback. I'd use a simple "#ifdefDOC_PAGE256" both indoc_stage1.Sandmakecsum.c, but in the long run it would be nice to be able to access the page256 flag (mtd->priv->page256) from userland (page256 inmtd_info_user?).
I don't really like userland tools (eg. makecsum or doc_loadbios)
taking care of such details as addressing mechanism of nand chips. I guess it would be better to create an ioctl called "loadbios" and handle that odditys inside the kernel driver. If page256==1, just write the 8kb image. If page256==0, write 512 byte pages padding with 0xff the unused bytes.
Regards,
Miguel Freitas
To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 2 lines · [email protected] said:
The relevant cvs diffs follow. Notice: these mods make
doc_stage1.Sandmakecsum.cwork _only_ for 2Mb DOCs!
doc_stage1.S could be hacked to work with both. See the existing loader code in the DiskOnChip firmware for inspiration.
There's no real reason to waste the second half of the pages either - and we could easily make the checksums work in _both_ types of device at once.
--
dwmw2
To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 5 lines · David Woodhouse
doc_stage1.Scould be hacked to work with both. See the existing loader code in the DiskOnChip firmware for inspiration.There's no real reason to waste the second half of the pages either - and we could easily make the checksums work in _both_ types of device at once.
Yes, but to not waste the second half of pages AND makedoc_stage1.S work for all devices we would need to add code to identify the nand chip. I don't know how much bigger doc_stage1 would be, but it will be probably more than 256 bytes.
Suppose that we can fit that smart doc_stage1 in 512 bytes, so it
will have 2 halfs of 256 bytes. Output of makecsum could be made as follow:
- First half of stage1, with a checksum byte for 512 paged device,
ie, we should only sum half each 512-page of the first 16Kb.
- Second half of stage2 (this will NOT be loaded by IPL on 512-
page devices). checksum will be generated by summing all the first 8Kb.
- Second half of stage2. checksum = 0.
- Unused 256 bytes, just to simplify stage1 (so it won't have to deal
with READ0 / READ1 commands)
- Stage2 from grub.
BTW, forgot my suggestion for "loadbios" ioctl...
Regards,
Miguel Freitas
To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 4 lines · [email protected] said:
Yes, but to not waste the second half of pages AND make
doc_stage1.Swork for all devices we would need to add code to identify the nand chip. I don't know how much biggerdoc_stage1would be, but it will be probably more than 256 bytes.
That's not a problem. We don't currently start the grub stage2 until byte 512 anyway, do we?
You don't even need to write the code to probe - if you set it up right it'll just happen for you.
Use 768 bytes at the beginning of the flash for doc_stage1.S.
0x000 - 0x0ff holds generic register setup code. 0x100 - 0x1ff holds code specific to the 256-byte-page devices. 0x200 - 0x2ff holds code specific to the 512-byte-page devices.
Now because the IPL ROM only loads the first half of the page on 512-byte devices, you'll find that whatever type of device you have, you magically get the 'correct' second half of the loader put into offset 256 when it's loaded into memory.
Start your grub stage2 at 0x300.
Calculate the checksum over the left-hand-sides of the pages and put it into the code for 512-byte-page devices.
Now, calculate the checksum for the 256-byte-page devices and put it into the code for the 256-byte-page devices - where the IPL won't see it if we're on a 512-byte-page device.
I can hack this up and get it to work on the 512-byte devices if you like.
Quoted 1 line · [email protected] said:
BTW, forgot my suggestion for "loadbios" ioctl...
I didn't forget it. You don't like handling it in userspace - I agree. I just don't like handling it in the mtd character device _either_ :)
--
dwmw2
To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 4 lines · David Woodhouse
Now because the IPL ROM only loads the first half of the page on 512-byte devices, you'll find that whatever type of device you have, you magically get the 'correct' second half of the loader put into offset 256 when it's loaded into memory.
Yes! That's an even better idea!
Quoted 1 line
I can hack this up and get it to work on the 512-byte devices if you like.
Well, I will not have time to do it in the next few days anyway. But
maybe Ciro will want to implement it.
Quoted 4 lines
Quoted 1 line
BTW, forgot my suggestion for "loadbios" ioctl...
I didn't forget it. You don't like handling it in userspace - I agree. I just don't like handling it in the mtd character device _either_ :)
Oh, I expressed myself badly...I just want to say: - please, forget
the loadbios ioctl idea! :) I realized it's not necessary.
Regards,
Miguel Freitas
To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 4 lines · [email protected] said:
Well, I will not have time to do it in the next few days anyway.
But maybe Ciro will want to implement it.
I just committed it - it's working on 512-byte devices. I see no reason why it shouldn't work on 256-byte devices if I copied Ciro's code correctly.
--
dwmw2
To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 2 lines · David Woodhouse
I just committed it - it's working on 512-byte devices. I see no reason why it shouldn't work on 256-byte devices if I copied Ciro's code correctly.
I tried it after your last commit and it works fine on my 2 Mb DOC. I only needed to fix makecsum.c (reset checksum to zero - committed).
Ciro
Signature · 10 lines
Ciro Cattuto, Open Source Developer, Linuxcare Italia SpA Tel. +39.338.3002140 Fax +39.049.8036484 [email protected] http://www.linuxcare.com/ [email protected] http://www.prosa.it/ Linuxcare. Support for the revolution. To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 2 lines · [email protected] said:
I can hack this up and get it to work on the 512-byte devices if you
like.
I've hacked it up. It doesn't yet work but I'm going home. I've committed the changes to makecsum.c, and that should now work on both types of device
- it definitely works on the 512-byte-page devices.
The actual Grub loader code doesn't yet work so I haven't yet committed it. It's horribly ugly too. Patch below.
Index: doc_stage1.S
===================================================================
RCS file: /home/cvs/mtd/grub/doc_stage1.S,v
retrieving revision 1.8
doc_stage1.S +174 -117
@@ -29,19 +29,18 @@ * defines for the code go here */ +#define LOADLEN (((STAGE2_SIZE + 0xff) & ~0xff) >> 8) +#define GRUBLOADOFS 0x300 + #ifdef OLDGRUB /* Loading Erich's old grub */ -#define LOADLEN (((STAGE2_SIZE + 0xff) & ~0xff) >> 8) -#define GRUBSTART 0x8000 -#define GRUBLOADSEG 0x7e0 -#define GRUBLOADOFS 0x200 +#define GRUBSTART 0x8000 +#define GRUBLOADSEG 0x7d0 #else /* Loading FSF grub */ -#define LOADLEN (((((STAGE2_SIZE + 0xff) & ~0xff) + 0x200)) >> 8) -#define GRUBSTART 0x8200 -#define GRUBLOADSEG 0x800 -#define GRUBLOADOFS 0x000 +#define GRUBSTART 0x8200 +#define GRUBLOADSEG 0x7f0 #endif
@@ -103,7 +102,7 @@ movw $int19,0x0064 /* Copy ourself into the new segment we've just reserved */ - movw $0x80, %cx + movw $0x200, %cx cld pushw %cs popw %ds
@@ -127,18 +126,14 @@ /* Set up our target address for writing stage2 */ movw $GRUBLOADSEG, %ax movw %ax, %es -#if GRUBLOADOFS == 0 - xorw %di, %di -#else movw $GRUBLOADOFS, %di -#endif - /* Contents of DiskOnChip are loaded at 0000:8000 */ - /* The first 0x200 bytes of this is in fact this bootloader, - * and it replaces the bootloader which CVS grub has now - * added to the beginning of stage2 - * Stage2 proper starts at 0x08200, which is convenient. - */ + /* Stage2 proper starts at offset 0x300 on the flash. We + have defined the load address GRUBLOADSEG so that + we're loading this to 0x8000:0000 or 0x8000:0200, + depending on whether this is old or GNU Grub, + respectively. + */ cld
@@ -157,12 +152,157 @@ /* Load %CX with the number of 256-byte blocks to load */ movw $LOADLEN, %cx + + /* + Basically, we know that the DiskOnChip IPL ROM will + load only the first 256 bytes of each 512-byte page + from a 512-byte-page device, but it'll load _all_ + the data from a 256-byte-page device. + + Therefore, we put the code to handle 256-byte-page + devices at offset 0x100, where we know it won't get + loaded if we're actually on a 512-byte-page device. + We put the code to handle 512-byte-page devices at + 0x200, in the knowledge that it'll get loaded to + offset 0x100 if it's appropriate. + + Now, we don't have to probe the device, we just + jump to the code at 0x100, because we _know_ that + the IPL ROM will have loaded the correct code there. + + This is SICK. I love it. + */ + + jmp mainloop + + /* Routines used by both 256- and 512- byte/page loaders. + + /* doc_cmd: Send a command to the flash chip */ +doc_cmd: + /* Enable CLE line to flash */ + movb $CSDN_CTRL_FLASH_IO + CSDN_CTRL_WP + CSDN_CTRL_CLE + CSDN_CTRL_CE, BX_CSDNControl + /* Dummy */ + incw -4(%bx) + /* Write the actual command */ + movb %ah,BX_SlowIO + movb %ah,(%si) + + /* doc_wait: Wait for the DiskOnChip to be ready */ +doc_wait: + incw BX_ChipID +l38: + testb $0x80,BX_CSDNControl + jz l38 + test BX_CSDNControl,%dx + ret + + +/* + * message: write the string pointed to by %si + * + * WARNING: trashes %si, %ax, and %bx + */ + + /* + * Use BIOS "int 10H Function 0Eh" to write character in teletype mode + * %ah = 0xe %al = character + * %bh = page %bl = foreground color (graphics modes) + */ +1: + movw $0x0001, %bx + movb $0xe, %ah + int $0x10 /* display a byte */ + +message: + lodsb + cmpb $0, %al + jne 1b /* if not end of string, jmp to display */ + ret + + /* Hex output routines, used at one point in debugging */ + +doc_seg: .word 0 + +int19_execed_string: .string "Loading GRUB from DiskOnChip\n\r" + + + + + + /* Code for 256-byte-page devices. */ + .org 0x100 +mainloop: +mainloop256: + /* We're still reading a block */ +// testw $0xff, %di +// jnz readbyte + + /* Send new READ0 command */ + + movw %di, %ax + xorb %ah, %ah + call doc_cmd + + /* Start of new block. Set address */ + movb $CSDN_CTRL_FLASH_IO + CSDN_CTRL_WP + CSDN_CTRL_ALE + CSDN_CTRL_CE, BX_CSDNControl + incw BX_ChipID + + /* We sent bits 0-7, then 8-15, then 16-23 */ + movw %di, %dx + /* Bits 0-7 are always zero */ + movb $0,BX_SlowIO + movb $0,SI_CSDN_IO + /* Bits 8-15 */ + movb %dh,BX_SlowIO + movb %dh,SI_CSDN_IO + /* Bits 16-23 */ + .byte 0xb2 /* movb adrbytehi, %dl */ +adrbytehi256: + .byte 0 + movb %dl,BX_SlowIO + movb %dl,SI_CSDN_IO + + /* Clear the ALE line to the flash chip */ + movb $CSDN_CTRL_FLASH_IO + CSDN_CTRL_WP + CSDN_CTRL_CE, BX_CSDNControl + call doc_wait + + pushw %cx /* Store the 'blocks remaining' count */ + movw $0x100, %cx /* Set up to copy 0x100 bytes */ +readbyte256: + testb BX_SlowIO,%al /* dummy read */ + movsb /* movb SI_CSDN_IO ; stosb would be more obvious, */ + decw %si /* but would take an extra byte. */ + loop readbyte256 + + + testw $0xffff, %di /* Check if we've done a whole 0x10000 bytes */ + jnz endloop256 /* No - continue regardless */ + /* Yes - increase %es */ + movw %es, %cx + addb $0x10, %ch + movw %cx, %es + + incb %cs:adrbytehi256 /* If so, increase the high byte too */ + +endloop256: + popw %cx /* Restore the 'blocks remaining' count */ + loop mainloop256 /* Loop till completely done */ +good256: + /* Run it: jmpf 0:2000 */ + + .byte 0xea + .word GRUBSTART,0 -mainloop: - /* We're still reading a block */ -// testw $0xff, %di -// jnz readbyte + .org 0x1ff + .byte 0 /* checksum */ + + + /* Code for 512-byte-page devices. */ + + .org 0x200 +mainloop512: + /* Send new READ command - is it READ0 or READ1? */ movw %di, %ax
@@ -188,7 +328,7 @@ movb %dh,SI_CSDN_IO /* Bits 17-23 are also zero */ .byte 0xb2 /* movb adrbytehi, %dl */ -adrbytehi: +adrbytehi512: .byte 0 movb %dl,BX_SlowIO movb %dl,SI_CSDN_IO
@@ -199,117 +339,34 @@ pushw %cx /* Store the 'blocks remaining' count */ movw $0x100, %cx /* Set up to copy 0x100 bytes */ -readbyte: +readbyte512: testb BX_SlowIO,%al /* dummy read */ movsb /* movb SI_CSDN_IO ; stosb would be more obvious, */ decw %si /* but would take an extra byte. */ - loop readbyte + loop readbyte512 testw $0xffff, %di /* Check if we've done a whole 0x10000 bytes */ - jnz endloop /* No - continue regardless */ + jnz endloop512 /* No - continue regardless */ /* Yes - increase %es */ movw %es, %cx addb $0x10, %ch movw %cx, %es addb $0x80, %cs:adrbit16 /* Increase bit 16 */ - jnc endloop /* Did it overflow? */ - incb %cs:adrbytehi /* If so, increase the high byte too */ + jnc endloop512 /* Did it overflow? */ + incb %cs:adrbytehi512 /* If so, increase the high byte too */ -endloop: +endloop512: popw %cx /* Restore the 'blocks remaining' count */ - loop mainloop /* Loop till completely done */ -good: + loop mainloop512 /* Loop till completely done */ +good512: /* Run it: jmpf 0:2000 */ .byte 0xea .word GRUBSTART,0 - - /* doc_cmd: Send a command to the flash chip */ -doc_cmd: - /* Enable CLE line to flash */ - movb $CSDN_CTRL_FLASH_IO + CSDN_CTRL_WP + CSDN_CTRL_CLE + CSDN_CTRL_CE, BX_CSDNControl - /* Dummy */ - incw -4(%bx) - /* Write the actual command */ - movb %ah,BX_SlowIO - movb %ah,(%si) - /* doc_wait: Wait for the DiskOnChip to be ready */ -doc_wait: - incw BX_ChipID -l38: - testb $0x80,BX_CSDNControl - jz l38 - test BX_CSDNControl,%dx - ret - + .org 0x2ff + .byte 0 /* checksum */ -doc_seg: .word 0 - -int19_execed_string: .string "Loading GRUB from DiskOnChip\n\r" - -/* - * message: write the string pointed to by %si - * - * WARNING: trashes %si, %ax, and %bx - */ - - /* - * Use BIOS "int 10H Function 0Eh" to write character in teletype mode - * %ah = 0xe %al = character - * %bh = page %bl = foreground color (graphics modes) - */ -1: - movw $0x0001, %bx - movb $0xe, %ah - int $0x10 /* display a byte */ - -message: - lodsb - cmpb $0, %al - jne 1b /* if not end of string, jmp to display */ - ret - - /* Hex output routines, used at one point in debugging */ -#if 0 -phword: - pushw %ax - xchgb %al,%ah - call phbyte - movb %ah,%al - call phbyte - popw %ax - ret - - -phbyte: - pushw %ax - movb %al, %ah - shrb $4,%al - call phnibble - movb %ah, %al - call phnibble - popw %ax - ret - -phnibble: - pushw %ax - andb $0xf,%al - addb $48,%al - cmpb $57,%al - jna ph1 - add $7,%al -ph1: mov $0xe,%ah - int $0x10 - popw %ax - ret -#endif - -#if 0 - /* Cause an error if this code was too large. */ - .org 0xff - .byte 0 /* Placement of checksum byte */ -#endif
--
dwmw2
To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 6 lines · [email protected] said:
I've hacked it up. It doesn't yet work but I'm going home. I've committed the changes to
makecsum.c, and that should now work on both types of device - it definitely works on the 512-byte-page devices.The actual Grub loader code doesn't yet work so I haven't yet committed it. It's horribly ugly too. Patch below.
Actually, the RH7 beta had munged my clock and it was a lot earlier than I thought it was, so I didn't go home.
I've just committed an attempt at fixing this. I haven't tested it, so I don't know that it doesn't work, and I'm happy to commit it :)
This time I really am leaving.
--
dwmw2
To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 3 lines · David Woodhouse
0x000-0x0ffholds generic register setup code.0x100-0x1ffholds code specific to the 256-byte-page devices.0x200-0x2ffholds code specific to the 512-byte-page devices.
Clever, I admit. And cool. :)
Quoted 1 line
Start your grub stage2 at
0x300.
...and put it at offset 0x400 in the firmware image.
Ciro
Signature · 10 lines
Ciro Cattuto, Open Source Developer, Linuxcare Italia SpA Tel. +39.338.3002140 Fax +39.049.8036484 [email protected] http://www.linuxcare.com/ [email protected] http://www.prosa.it/ Linuxcare. Support for the revolution. To unsubscribe, send "unsubscribe mtd" to [email protected]
Quoted 1 line · David Woodhouse
doc_stage1.Scould be hacked to work with both.
Sure. I posted my 2 Mb modifications just for reference.
Quoted 1 line
See the existing loader code in the DiskOnChip firmware for inspiration.
I'll think a bit about that - but this requires putting identification code into doc_stage1.S - and maintaining it. It's probably worth doing though.
Ciro
Signature · 10 lines
Ciro Cattuto, Open Source Developer, Linuxcare Italia SpA Tel. +39.338.3002140 Fax +39.049.8036484 [email protected] http://www.linuxcare.com/ [email protected] http://www.prosa.it/ Linuxcare. Support for the revolution. To unsubscribe, send "unsubscribe mtd" to [email protected]