Hello all. On X201 top 192K are locked. Fortunately the original BIOS
has a way to update this region.
If you extract a X201 image you'll find a lzint compressed file which
makes 192K decompressed. It's the update. In it you can simply replace
74f8d1fe (PR0) with 74f8d0ff (harmless address with the same checksum),
recompress, correct checksum, update, reboot and PR0 is inactive. tools
to do all this were posted previously (x201_analyze and
x201_reconstruct) except compressor. You need compressor at least as
performant as original. I attach here my own version which is about 2%
underperformant. If you want to have a try, be my guest
Otherwise I simply use external flashing.
#include <algorithm>
#include <queue>
#include <stdio.h>
#include <string.h>

using namespace std;

#define MAX_DICBIT    13
#define MAX_DICSIZ (1 << MAX_DICBIT)
#define NP (MAX_DICBIT + 1)
#define PBIT 4

typedef unsigned char grub_uint8_t;
typedef unsigned short grub_uint16_t;
typedef unsigned long grub_size_t;
typedef signed short grub_int16_t;
typedef unsigned int grub_uint32_t;

#define MAXMATCH 256
#define THRESHOLD  3
#define UCHAR_MAX ((1<<(sizeof(unsigned char)*8))-1)
#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
#define USHRT_BIT 16
#define NT (USHRT_BIT + 3)
#define TBIT 5

grub_uint8_t *
lzint_compress (grub_uint8_t *src_in, grub_uint8_t *srcend_in);

static int
count_sim (grub_uint8_t *a, grub_uint8_t *b, grub_size_t lim)
{
  grub_size_t i;
  for (i = 0; i < lim && i < MAXMATCH; i++)
    if (a[i] != b[i])
      break;
  return i;
}

struct freq_node
{
  grub_uint16_t val;
  struct freq_node *left;
  unsigned idx;
  struct freq_node *right;

  const int operator > (const struct freq_node b)
    const
  {
    return this->val > b.val;
  }
};

struct code_elem
{
  int len;
  grub_uint32_t val;
};

static void
process_node (grub_uint32_t c, int depth, freq_node *n, grub_uint32_t *codeword, int target_depth,
	      priority_queue <unsigned, vector <unsigned>, greater <unsigned> > &q)
{
  if (n->right)
    {
      process_node (c << 1, depth + 1, n->left, codeword, target_depth, q);
      process_node ((c << 1) | 1, depth + 1, n->right, codeword, target_depth, q);
      return;
    }
  if (depth != target_depth)
    return;
  q.push (n->idx);
}

static int
get_max_depth (freq_node *n)
{
  if (n->right)
    return max (get_max_depth (n->left), get_max_depth (n->right)) + 1;
  return 0;
}

static struct code_elem *
construct_code (grub_uint16_t *freq, grub_size_t sz)
{
  grub_size_t i;
  priority_queue <freq_node, vector <freq_node>, greater <freq_node> > pq;
  freq_node r;
  struct code_elem *ret;
  grub_uint32_t codeword = 0;
  int md;

  for (i = 0; i < sz; i++)
    if (freq[i])
      {
	freq_node node;
	node.val = freq[i];
	node.idx = i;
	node.left = 0;
	node.right = 0;
	pq.push (node);
      }
  if (pq.size () == 0)
    {
      ret = (code_elem *) malloc (sz * sizeof (ret[0]));
      memset (ret, 0, sz * sizeof (ret[0]));
      return ret;
    }

  while (pq.size () >= 2)
    {
      freq_node a = pq.top (), *aa;
      pq.pop ();
      freq_node b = pq.top (), *bb;
      freq_node n;
      pq.pop ();
      n.left = (freq_node *) malloc (sizeof (a));
      n.right = (freq_node *) malloc (sizeof (b));
      n.val = a.val + b.val;
      if (a.idx < b.idx)
	{
	  *n.left = a;
	  *n.right = b;
	}
      else
	{
	  *n.left = b;
	  *n.right = a;
	}
      n.idx = n.left->idx;
      pq.push (n);
    }
  r = pq.top ();
  ret = (code_elem *) malloc (sz * sizeof (ret[0]));
  memset (ret, 0, sz * sizeof (ret[0]));
  md = get_max_depth (&r) + 1;
  for (i = 0; i < md; i++)
    {
      priority_queue <unsigned, vector <unsigned>, greater <unsigned> > q;
      process_node (0, 0, &r, &codeword, i, q);
      while (!q.empty ())
	{
	  unsigned id = q.top ();
	  q.pop ();
	  ret[id].len = i;
	  ret[id].val = codeword;
	  codeword++;
	}
      codeword <<= 1;
    }
  return ret;
}

struct outbuf
{
  grub_uint8_t *ptr;
  grub_uint8_t *s;
  int bitn;
};

static void
write_bits (struct outbuf *out, grub_uint16_t val, int sz)
{
  while (sz--)
    {
      if (val & (1 << sz))
	*out->ptr |= out->bitn;
      if (out->bitn != 1)
	out->bitn >>= 1;
      else
	{
	  out->ptr++;
	  out->bitn = 0x80;
	}
    }
}

static void
write_p_code (struct code_elem *code, grub_size_t sz, struct outbuf *out,
	      int nbit, int i_special, int li)
{
  int last, i;
  for (last = sz - 1; last >= 0; last--)
    if (code[last].len)
      break;
  write_bits (out, last + 1, nbit);
  if (last == -1)
    {
      write_bits (out, li, nbit);
      return;
    }

  for (i = 0; i <= last; i++)
    {
      if (code[i].len < 7)
	{
	  write_bits (out, code[i].len, 3);
	}
      else
	{
	  write_bits (out, ~0, code[i].len - 4);
	  write_bits (out, 0, 1);
	}

      if (i == i_special)
	{
	  int c = 0;
	  while (i + 1 <= last && c < 3 && code[i + 1].len == 0)
	    i++, c++;
	  write_bits (out, c, 2);
	}
    }
}


static int
get_highest_bit (grub_uint16_t v)
{
  int i;
  for (i = 15; i>= 0; i--)
    if (v & (1 << i))
      break;
  return i;
}

static void
write_c_code (struct code_elem *code, struct outbuf *out, int li)
{
  int last, i;
  grub_uint16_t c[NC];
  int cc = 0;
  grub_uint16_t freq_co[NT];
  struct code_elem *pcode;
  int pli = 0;

  memset (freq_co, 0, sizeof (freq_co));

  for (last = NC - 1; last >= 0; last--)
    if (code[last].len)
      break;
  for (i = 0; i <= last; i++)
    {
      if (code[i].len)
	{
	  c[cc++] = 2 + code[i].len;
	  freq_co[2 + code[i].len]++;
	  pli = 2 + code[i].len;
	}
      else
	{
	  int nz;
	  for (nz = 0; i + nz <= last; nz++)
	    if (code[i+nz].len)
	      break;
	  if (nz >= 3 && nz <= 18)
	    {
	      c[cc++] = 1;
	      freq_co[1]++;
	      pli = 1;
	      c[cc++] = nz - 3;
	      i += nz - 1;
	      continue;
	    }
	  if (nz >= 20)
	    {
	      c[cc++] = 2;
	      freq_co[2]++;
	      pli = 2;
	      c[cc++] = nz - 20;
	      i += nz - 1;
	      continue;
	    }
	  freq_co[0]++;
	  pli = 0;
	  c[cc++] = 0;
	}
    }

  pcode = construct_code (freq_co, NT);

  printf ("%d bits written\n", (out->ptr - out->s) * 8 + 7 - get_highest_bit (out->bitn));

  write_p_code (pcode, NT, out,
		TBIT, 2, pli);

  printf ("before c table: %d bits written\n", (out->ptr - out->s) * 8 + 7 - get_highest_bit (out->bitn));

  write_bits (out, last + 1, 9);

  if (last == -1)
    {
      write_bits (out, li, 9);      
    }
  else
    for (i = 0; i < cc; i++)
      {
	write_bits (out, pcode[c[i]].val, pcode[c[i]].len);
	if (c[i] == 1)
	  {
	    i++;
	    write_bits (out, c[i], 4);
	    continue;
	  }
	if (c[i] == 2)
	  {
	    i++;
	    write_bits (out, c[i], 9);
	    continue;
	  }
      }
  printf ("after c table: %d bits written\n", (out->ptr - out->s) * 8 + 7 - get_highest_bit (out->bitn));
}

#define min(a,b) (((a) < (b)) ? (a) : (b))

static void
compress_block (grub_uint8_t **src_in, grub_size_t len,
		struct outbuf *out)
{
  grub_uint8_t *src = *src_in;
  int i, j;
  grub_uint16_t lz[65536];
  grub_int16_t off[65536];
  grub_uint16_t freq_lz[NC];
  grub_uint16_t freq_off[NP];
  struct code_elem *code_main;
  struct code_elem *code_off;
  grub_uint8_t *s = out->ptr;
  int li = 0, pli = 0;

  memset (freq_lz, 0, sizeof (freq_lz));
  memset (freq_off, 0, sizeof (freq_off));

  printf ("block\n");

  for (i = 0, j = 0; i < len && j < 65535; )
    {
      int best = 3;
      int bj = -1;
      int k;
      for (k = max (i - MAX_DICSIZ, 0); k < i; k++)
	{
	  int cand = count_sim (src + k, src + i, min (len - i, i - k));
	  if (cand >= best)
	    {
	      bj = k;
	      best = cand;
	    }
	}
      if (bj == -1)
	{
	  lz[j] = src[i];
	  off[j] = -1;
	  freq_lz[src[i]]++;
	  i++;
	  j++;
	  li = src[i];
	}
      else
	{
	  int b;
	  int v = i - bj - 1;
	  lz[j] = 0x100 + best - 3;
	  off[j++] = v;
	  freq_lz[0x100 + best - 3]++;
	  b = get_highest_bit (v) + 1;
	  freq_off[b]++;
	  pli = b;
	  i += best; 
	  li = 0x100 + best - 3;
	}
    }
  *src_in += i;
  printf ("%d/%d\n", i, j);

  printf ("stat\n");

  write_bits (out, j, 16);

  code_main = construct_code (freq_lz, NC);
  code_off = construct_code (freq_off, NP);

  printf ("before p1 table: %d bits written\n", (out->ptr - out->s) * 8 + 7 - get_highest_bit (out->bitn));

  write_c_code (code_main, out, li);
  write_p_code (code_off, NP, out, PBIT, -1, pli);
  printf ("after p table: %d bits written\n", (out->ptr - out->s) * 8 + 7 - get_highest_bit (out->bitn));

  for (i = 0; i < j; i++)
    {
      write_bits (out, code_main[lz[i]].val, code_main[lz[i]].len);
      if (off[i] != -1)
	{
	  int b = get_highest_bit (off[i]);
	  write_bits (out, code_off[b + 1].val, code_off[b + 1].len);
	  if (b > 0)
	    write_bits (out, off[i], b);
	}
    }
  printf ("%d\n", out->ptr - s);
}

grub_uint8_t *
lzint_compress (grub_uint8_t *src, grub_uint8_t *srcend, grub_size_t *dest_size)
{
  grub_uint8_t *ret = (grub_uint8_t *) malloc (1048576 * 10);
  struct outbuf optr = { ret, ret, 0x80 };

  while (src < srcend)
    compress_block (&src, srcend - src, &optr);
  if (optr.bitn != 0x80)
    {
      optr.ptr++;
      optr.bitn = 0x80;
    }
  *dest_size = optr.ptr - ret;
  return ret;
}

int
main (int argc, char ** argv)
{
  FILE *in, *out;
  grub_uint8_t *inbuf;
  grub_uint8_t *outbuf;
  grub_size_t outsize;
  int insize;
  in = fopen (argv[1], "rb");
  fseek (in, 0, SEEK_END);
  insize = ftell (in);
  fseek (in, 0, SEEK_SET);
  inbuf = (grub_uint8_t *) malloc (insize);
  fread (inbuf, 1, insize, in);
  fclose (in);
  outbuf = lzint_compress (inbuf, inbuf + insize, &outsize);
  out = fopen (argv[2], "wb");
  fwrite (&outsize, 1, 4, out);
  fwrite (&insize, 1, 4, out);
  fwrite (outbuf, 1, outsize, out);
  fclose (out);
  return 0;
}

Attachment: signature.asc
Description: OpenPGP digital signature

-- 
coreboot mailing list: coreboot@coreboot.org
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to