Welcome, Guest. Please login or register.

Author Topic: KickWork  (Read 21912 times)

Description:

0 Members and 2 Guests are viewing this topic.

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: KickWork
« Reply #14 on: November 29, 2007, 09:42:01 AM »
Some words on how it works:

Basically the app writes a patched ROM image to the KICK floppy disk. The patch catches the OS reading the floppy bootblock (first two blocks) and if 'KICK' identifier is located it instead returns a valid bootblock. This allows the OS to idenfity the disk as bootable OFS (DOS\0), rather than df0:KICK.

The application loads the kickstart and then scans it for the locations to patch. If it finds the needed locations it then inserts the abovementioned trackdisk.device patch. Finally the program writes out a OFS disk image (.adf) containing first the KICK block + the KS ROM to allow A1000 bootstrap ROM to load the KS ROM, and then OFS rootblock + bitmap block with the area for the KS ROM pre-allocated.

The trackdisk.device CMD_READ patch itself is some really tight m68k assembly since I didn't want to overwrite any functional code inside the KS ROM. Currently it fits exactly over the copyright notice inside the KS ROM image beginning (type hex some kick1.2 or kick1.3 image to see the text it overwrites). The patch works by hooking the trackdisk.device/CMD_READ command which is used to read blocks off disk (check trackdisk.doc autodoc CMD_READ for details). At boot the KS ROM bootstrap uses CMD_READ to read the floppy beginning to see if it is bootable, so once we make sure that proper bootblock is returned it'll automagically work.

Later the KS ROM also uses CMD_READ to identify the filesystem of a inserted floppy (you get dfx:KICK if you insert KICK floppy using unpatched KS ROM). The patch naturally catches this CMD_READ aswell and again provides the required identification (DOS\0 to indicate OFS filesystem).

The program isn't really that complicated, the real magic went into figuring out how to patch the trackdisk.device CMD_READ. Once that was sorted out the rest was pretty straight-forward.

Finally, I really have no clue how the original KickWork works. It might do something similar, but for verification I'd need to take a look at ADF of such KickWork floppy.
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: KickWork
« Reply #15 on: November 29, 2007, 04:53:18 PM »
Ok, I took a look at the original KickWork now. It has series of patches to the Kickstart ROM. The patches are tied to specific KS ROM version (meaning you need separate disks for every ROM).

The patches are:

strap:
- Modify code so that it accepts other than DOS\0 as bootable device (allows booting from KICK disk).
- Modify palette of the "insert floppy" display.
- Modify the "insert floppy" gfx slightly.

Workbench:
- Change workbench titlebar from "Workbench release 1.x." to "AMIGO KickWork  1.x. " (x being the KS rom revision).
- Modify Workbench so that it accepts other than DOS\0 floppies as DOS one (allows KICK disk with proper filesystem to work).

Finally new ROM checksum is poked in.


So in short it takes a different route, but functions pretty similar way. My patch doesn't do all those fancy visual modifications though, it tries to keep the ROM as unmodified as possible.

The floppy itself gets modified during the installation process (bootblock DOS\0 gets replaces with KICK). I'd guess the area where it writes the KS ROM is preallocated in the disk bitmap.

Finally there is one bootblock patch that seemingly does nothing: It replaces author's name "Loew" with "Loew" (no change). I'd guess this is a simple check to make sure the copyright notice hasn't been modified.
 

Offline koaftder

  • Hero Member
  • *****
  • Join Date: Apr 2004
  • Posts: 2116
    • Show only replies by koaftder
    • http://koft.net
Re: KickWork
« Reply #16 on: November 29, 2007, 04:58:10 PM »
Awesome work Piru.
 

Offline rloew

  • Newbie
  • *
  • Join Date: Nov 2007
  • Posts: 4
    • Show only replies by rloew
    • http://members.aol.com/rloew1
Re: KickWork
« Reply #17 on: November 29, 2007, 05:50:29 PM »
I see someone finally figured out the patches I made to create Kickwork 1.x for the Amiga 1000. I think analyzing KickWork 2.0.4 and KickWork 3.0 would be much more of a challenge. Since Amigo Business Computers is no longer in the Amiga business, I sell KickWork and other Amiga products on my own now.

Rudolph R. Loew

rloew@hotmail.com
 

Offline amigadave

  • Lifetime Member
  • Hero Member
  • *****
  • Join Date: Jul 2004
  • Posts: 3836
    • Show only replies by amigadave
    • http://www.EfficientByDesign.org
Re: KickWork
« Reply #18 on: November 29, 2007, 05:56:44 PM »
Welcome to Amiga.org first time poster R. R. Loew!

KickWork was/is a great idea, but I was not aware that there was a 2.0.4 and 3.0 version.  Can you tell us a little more about them and what prices you charge for them.

Also, what other Amiga products do you offer?

Again, welcome.
How are you helping the Amiga community? :)
 

Offline hardlink

  • Hero Member
  • *****
  • Join Date: Sep 2006
  • Posts: 586
    • Show only replies by hardlink
Re: KickWork
« Reply #19 on: November 29, 2007, 07:08:56 PM »
Quote

koaftder wrote:
Awesome work Piru.


Agreed!

What an amazing thread! First, that Piru can grok out the KickWork method from over 20 years ago. I thought KickWork was Amiga Nostalgia - then, the real author (I hope) shows up! Amd Amig-o Business Computers is still in business, sans Amig-a. They used to offer some hardware products - we almost bought a, if I rembember, GPIB controller Zorro card off them once. Of course, we did but KickWork from them - and I'm looking for it right now ...

 

Offline yorgleTopic starter

  • Full Member
  • ***
  • Join Date: Jan 2007
  • Posts: 165
    • Show only replies by yorgle
    • http://umlautllama.com
Re: KickWork
« Reply #20 on: November 29, 2007, 08:22:14 PM »
Thank you for making it, Rudolph.  We used it extensively on our A1000... it made it a lot more convenient to use... I'd be willing to bet that it let the eject mechanism in our DF0 live a few extra years. ;)

My dad and I drove up to Amigo a few times to get various software, hardware and just look at the computers.  :)

Unfortunately, I had moved away from Long Island when I went to college before 1.3 came out, and then I had a hard drive, so I never picked up KickWork 1.3 or newer.

I seem to remember getting KickWork 1.1 as well, but that could be my poor memory.

And yeah, cheers for the excellent analysis and such, Piru!
 

Offline rloew

  • Newbie
  • *
  • Join Date: Nov 2007
  • Posts: 4
    • Show only replies by rloew
    • http://members.aol.com/rloew1
Re: KickWork
« Reply #21 on: November 29, 2007, 09:37:20 PM »
Kickwork 2.0.4 and 3.0 are similar to Kickwork 1.x but install Kickstart 2.0.4 or 3.0 on an Amiga 1000. Due to the larger Kickstart image, half is stored in the normal protected RAM and half is stored in user RAM. There are three version of each, one for each of the three memory configurations supported.

Amigo Business Computers never promoted KickWork 2.0.4 or 3.0.

The price is $30 for an E-Mailed Disk Image. Retail packaging is not available for these or KickWork 1.x.

I have developed hundreds of Programs for the Amiga. Most are diagnostic or development tools. A few of the more interesting ones are listed below. Contact me if you are interested in a specific type of program.

XFILE: Advanced file management program with numerous List/Copy/Move/Delete/Execute options.

MERGEUNIQ: Merges files and removes duplicate lines/blocks.

TRACKDISK41: SCSI Disk drive for >4GB Drives without requiring "New Style Driver" support.

Networking File System with Auto Detect Option available in Proprietary Ethernet (AMIGO Ethernet), TCP/IP over Ethernet, Serial Port, Parallel Port, Modem, ARCNET, or Joystick Port (Beta). Auto Detect finds accessible drives over entire network including heterogenous ones.

Large Hard Drive Patches for X-SURF IDE/Ethernet Card.
 

Offline da9000

  • Hero Member
  • *****
  • Join Date: Mar 2005
  • Posts: 922
    • Show only replies by da9000
Re: KickWork
« Reply #22 on: November 30, 2007, 02:50:52 AM »
Excellent thread!

@Piru:
Thank you for the in-depth explanations and reverse engineering!

Only a small question: when you say "The application loads the kickstart and then scans it for the locations to patch.", do you scan certain fixed locations (so it only works on certain Kickstart versions), or some other form of heuristic (so the program will work with other Kickstart versions) ?

@Mr. Loew:

Glad to have you here and hear from you. I'd be curious to know if Kickwork or any other of your software is still being used by businesses/corporations, and if so what sectors/industries?

 

Offline rloew

  • Newbie
  • *
  • Join Date: Nov 2007
  • Posts: 4
    • Show only replies by rloew
    • http://members.aol.com/rloew1
Re: KickWork
« Reply #23 on: November 30, 2007, 03:11:19 AM »
I can answer the question Piru was asked. Each version of KickWork was designed to work with one version of Kickstart. Only two versions were sold by Amigo Business Conputers, KickWork 1.2 and KickWork 1.3.

As far as business use is concerned, KickWork was probably used mostly by individuals. A number of businesses purchased Amigo Ethernet to network their Amigas. I created some customized versions to work with the Scala authoring package to network their creation and presentation stations. I do not know how many Amiga based systems are still out there. I do know that Scala has migrated to the PC platform and is still selling software.
 

Offline da9000

  • Hero Member
  • *****
  • Join Date: Mar 2005
  • Posts: 922
    • Show only replies by da9000
Re: KickWork
« Reply #24 on: November 30, 2007, 03:22:58 AM »
@Mr. Loew:

Thanks for the info!

As for the question to Piru, I meant it for his version of the software - that's what he was describing, if I understood correctly.
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: KickWork
« Reply #25 on: November 30, 2007, 07:36:19 AM »
@da9000
Quote
when you say "The application loads the kickstart and then scans it for the locations to patch.", do you scan certain fixed locations (so it only works on certain Kickstart versions), or some other form of heuristic (so the program will work with other Kickstart versions) ?

My software indeed has heuristics to scan for the locations to patch (newtdread and oldtdreadptr pointers).

It has worked with all KS 1.x I've tried so far. It'll probably work with early KS 0.x betas, too.
 

Offline da9000

  • Hero Member
  • *****
  • Join Date: Mar 2005
  • Posts: 922
    • Show only replies by da9000
Re: KickWork
« Reply #26 on: December 01, 2007, 02:30:44 AM »
If I may ask:

do you search for "byte patterns" or instruction fingerprints if you like, which span a few bytes before, including, and after the target location?

In other words,if the hypothetical byte stream is:
39 b3
50 34
25 64  <-- target
14 8a
9f ff

Would you be searching for "35 25 64 14" ?

Also, do you start searching from a certain approximate location, or do you search the entire ROM (from start for example)?

Just curious what's a more effective method.
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: KickWork
« Reply #27 on: December 01, 2007, 01:49:50 PM »
@da9000
Code: [Select]

static __inline u_int32_t rl(const u_int8_t *p)
{
    return (u_int32_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
}

static __inline int romptr(u_int32_t p)
{
    return p >= ROMSTART && p < ROMEND;
}

for (i = 8; i < 512; i += 2)
{
    static const u_int8_t header[] =
      &quot;\xff\xff\xff\xff\x0d\x0a\x0a&quot; &quot;AMIGA ROM Operating System&quot;;
    u_int8_t * const p = (u_int8_t *) rom + i;

    if (!memcmp(p, header, sizeof(header) - 1))
    {
        newtdread = p;
        if (verbose > 1)
        {
            fprintf(stderr, &quot;0x%06x: Patch position\n&quot;,
              (u_int8_t *) newtdread - (u_int8_t *) rom + ROMSTART);
        }
        break;
    }
}

for (i = 8; i < ROMSIZE - 40; i += 2)
{
    u_int8_t * const p = (u_int8_t *) rom + i;
    u_int32_t p1, p2;
    p1 = rl(p);
    p2 = rl(p + 8);
    if (romptr(p1) && romptr(p2) &&
        rl(p + 4) == p1 && rl(p + 12) == p2 &&
        romptr(rl(p + 16)) && romptr(rl(p + 20)) &&
        rl(p + 24) == p1 && rl(p + 28) == p1 && rl(p + 32) == p1)
    {
        const u_int8_t *func = (u_int8_t *) rom + p2 - ROMSTART;
        if (rl(func) == 0x48E70038 && rl(func + 4) == 0x26690018)
        {
            oldtdreadptr = p + 8;
            if (verbose > 1)
            {
                fprintf(stderr, &quot;0x%06x: trackdisk.device CMD_READ function ptr\n&quot;,
                  (u_int8_t *) oldtdreadptr - (u_int8_t *) rom + ROMSTART);
            }
            break;
        }
    }
}

Efficiency does not matter here. The code is executed once when creating the disk.

The first loop finds the strings at the beginning of the ROM (it's quite pointless since in fact I think the strings are always at the same offset for all pre-2.0 ROMs). This is where the patch code will be placed.

The second loop is more magic, it locates the jumptable entry for the trackdisk.device CMD_READ command. There it looks for certain combination of pointers, and also has some code matching for the beginning of the actual cmd_read routine. The magical pattern is:

Code: [Select]

ptr1 ; CMD_INVALID
ptr1 ; CMD_RESET
ptr2 ; CMD_READ
ptr2 ; CMD_WRITE
ptr3 ; CMD_UPDATE
ptr4 ; CMD_CLEAR
ptr1 ; CMD_STOP
ptr1 ; CMD_START
ptr1 ; CMD_FLUSH

Once the code finds this pattern of pointers it then checks the code pointed by ptr2. It checks for:
Code: [Select]

ptr2:
    movem.l a2-a4,-(sp)
    move.l  (IO_UNIT,a1),a3

Those are the first two instructions of the cmd_read routine (actually read/write.. as you can see both CMD_READ and CMD_WRITE point to the same routine, the routines are so similar it helped to reduce the codesize to combine them).

Once this jumptable entry is located it is changed to point to the first pointer (where we've copied the patch code to). The patch code is adjusted to jsr to the original cmd_read(write) routine.

Obviously this isn't the only way to patch the trackdisk.device, there are several other ways to do it aswell. One would been by patching the trackdisk.device BEGINIO vector for example. However, in my case I had very little storage left for my patch so to simplify the patchcode I had to locate the patch to as close to actual read operation as possible. Patching BEGINIO would have required for the patch routine to perform further checking to make sure it is a CMD_READ operation.
 

Offline da9000

  • Hero Member
  • *****
  • Join Date: Mar 2005
  • Posts: 922
    • Show only replies by da9000
Re: KickWork
« Reply #28 on: December 03, 2007, 02:30:10 PM »
Cool stuff! I love technical analyses! I need to do some refreshing on jump-tables and libraries.

Almost all made sense, so just a couple of questions:

1)
For the life of me I can't decode your acronym for rl() :-). I can see it reverses the order of the bytes (swizzling?). Why is it necessary?

EDIT: a guess: ReverseLong? Can't be! You'd ditch u_int32_t for long!??! :-D

2)
I see the "magic pattern" code:
Code: [Select]

  if (romptr(p1) && romptr(p2) &&
        rl(p + 4) == p1 && rl(p + 12) == p2 &&
        romptr(rl(p + 16)) && romptr(rl(p + 20)) &&
        rl(p + 24) == p1 && rl(p + 28) == p1 && rl(p + 32) == p1)


but where do you check for ptr3 and ptr4?

romptr(rl(p + 16)) and the call afterwards are only checking bounds, right?


 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: KickWork
« Reply #29 from previous page: December 03, 2007, 02:50:11 PM »
@da9000
Quote
rl()

It's big endian 32bit integer read, I did it this way so that the source is endian safe (it works with any endianity, say for example x86). The rl() comes from "read long", wl() is short from "write long".

Quote
where do you check for ptr3 and ptr4?

romptr(rl(p + 16)) and the call afterwards are only checking bounds, right?

Bounds checking of ptr3 and ptr4 is enough, I just check that they're pointers to ROM.