Welcome to cyberz's homepage

Sections

Main
Projects
Miscellanea

Links

Links (delicious)

HP NetServer 5/133 LS2 LCD

Some time ago, I got an old nice HP NetServer 5/133 LS2 (upgraded to 2 166mhz cpus) where I put FreeBSD, and everything's fine (raid5 with vinum, checkout FreeBSD's main site). Since the LCD default text is quite useless, I wanted to get a way to change it to something nicer.

Looking in HP's forum, I saw that LSECU floppy could help me changing that string. Running it, is easy to discover that this software just changes some bios settings, but I wanted a realtime modifiable (from FreeBSD) LCD control, so started thinking about how to get that. Of course LSECU means that the Netserver BIOS knows how to change text (indeed at boot it prints there some infos), so I decided to get the BIOS and to look inside it. Googling a bit I discovered a nice BIOS document telling that on i386 BIOS starts at 0xf0000 and its size is 65k: so with root privilegies it's easy to read 65k from /dev/mem at offset 0xf0000, so here you are the biosdump.c program:

#include <stdio.h>
#include <assert.h>

int main() {
	FILE *f = fopen("/dev/mem", "r");
	char bios[0xffff];
								   
	assert(f);

	fseek(f, 0xf0000, SEEK_CUR);

	fread(bios, 1, sizeof(bios), f);
	fwrite(bios, 1, sizeof(bios), stdout);
}

Obviously only root can run that (at -1 securelevel). Once I got the BIOS, I went to Windows and downloaded some programs, as some friends of mine suggested (thanks to sand, Smilzo and tripz), and disassembled it. I searched the initial bios displayed string, I found its offset (0x6f26) and started looking if anyone was using that offset to do something and got:

0000265D: 8CC8                         mov       ax,cs
0000265F: 8ED8                         mov       ds,ax
00002661: BE6F26                       mov       si,0266F
00002664: E888FE                       call      0000024EF   -------- (5)

I don't know much about x86 assembler, but this seems a call to function. Going to 0x24ef we get:

000024EF: 56                           push      si
000024F0: 50                           push      ax
000024F1: 9C                           pushf
000024F2: FC                           cld
000024F3: AC                           lodsb
000024F4: 0AC0                         or        al,al
000024F6: 7405                         je        0000024FD   -------- (3)
000024F8: E88EFF                       call      000002489   -------- (4)
000024FB: EBF6                         jmps      0000024F3   -------- (5)
000024FD: 9D                           popf
000024FE: 58                           pop       ax
00002500: C3                           retn

This function seems to iterate through the string until its gets null. At each iteration the current character is loaded in al, and the 0x2489 function is called. The 0x2489 function looks like:

00002489: 52                           push      dx
0000248A: E8DCFF                       call      000002469   -------- (1)
...

Just pushes dx and calls 0x2469, let's go there:

00002469: 50                           push      ax
0000246A: 33C0                         xor       ax,ax
0000246C: B402                         mov       ah,002
0000246E: E862FF                       call      0000023D3   -------- (1)
00002471: 720D                         jb        000002480   -------- (2)
00002473: 8AF0                         mov       dh,al
00002475: 80E60F                       and       dh,00F
00002478: 8AD0                         mov       dl,al
0000247A: C0FA06                       sar       dl,006
0000247D: 80E201                       and       dl,001
00002480: 58                           pop       ax
00002481: C3                           retn

This function does some things with ax and then calls 0x23d3:

000023D3: 51                           push      cx
000023D4: 52                           push      dx
000023D5: 50                           push      ax
000023D6: B90600                       mov       cx,00006
000023D9: E8BCF1                       call      000001598   -------- (1)
000023DC: 58                           pop       ax
000023DD: BA000E                       mov       dx,00E00
000023E0: 80FC00                       cmp       ah,000
000023E3: 7418                         je        0000023FD   -------- (2)
000023E5: 80FC02                       cmp       ah,002
000023E8: 7410                         je        0000023FA   -------- (3)
000023EA: BA040E                       mov       dx,00E04
000023ED: 80FC01                       cmp       ah,001
000023F0: 740B                         je        0000023FD   -------- (4)
000023F2: 80FC03                       cmp       ah,003
000023F5: 7403                         je        0000023FA   -------- (5)
000023F7: F9                           stc
000023F8: EB04                         jmps      0000023FE   -------- (6)
000023FA: EC                           in        al,dx
000023FB: EB01                         jmps      0000023FE   -------- (7)
000023FD: EE                           out       dx,al
000023FE: 5A                           pop       dx
000023FF: 59                           pop       cx
00002400: C3                           retn

Finally I got what I was looking for: some data bus I/O operations (in and out). Looking at the code, it seems that I/O on LCD uses two I/O ports, 0xe00 and 0xe04. Got the I/O addresses, I could start writing something. With a little fast test, I was able to put some nonsense characters to the LCD:

nonsense chars on display

Now It was time to understand how to write correctly data. I just opened the Netserver and got the control panel:

control panel

Let's discover which is the LCD chipset, after removing that metal block:

control panel without metal block control panel without metal block

The chipset was HD44780A00, a processor of the well documented and widely used HD44780 type. Got the HD44780 datasheet, was easy to discover that 0xe00 is used to send commands and 0xe04 is used to send data to the device, and so I've written lcdw, a little program to write directly on your display. Using lcdw, it's easy to put on the LCD some nice infos about system current status, like uptime or load average, for example (note that the regex is complex because it matches both FreeBSD's and Linux different uptimes format, eitherway it looks overkill)...

# ./lcdw "`uptime | sed 's@.*, *\(.*\),.*,.*,.*$@\1@'`" "`uptime | sed 's@.*,.*,.*: *\(.*,.*,.*\)$@\1@'`"

...shows how many users are currently logged in on the first line, and system load on the second one.

stats on display

Last update on Sat Dec 6 20:15:41 CET 2003

OpenSolaris: Love at First Boot