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:
Now It was time to understand how to write correctly data. I just opened the Netserver and got the control panel:
Let's discover which is the LCD chipset, after removing that 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.
Last update on Sat Dec 6 20:15:41 CET 2003