Information wants to be free...

Linux Distribution for 386SX

I have a Commodore PC 50-II system with a Intel 386SX CPU running at 16MHz and only 5MB of RAM, in addition, the harddrive controller and harddrive is also missing. To get around this, I have installed a 3Com 3C509B-TPO ISA Network card and have managed to boot Linux on this ancient PC over the network instead.

At first I tried to use Buildroot, but I had to give up on this in the end, as it seems that pure 386 is not supported anywhere anymore. So instead, I have gone the route of building everything from scratch, so I could pick and choose specific source versions of GCC and the Linux kernel that supports 386 with math emulation. The end result is a cross-compiling toolchain for i386, a stripped down kernel and Busybox-based rootfs mounted over NFS from another host computer.

I ended up using these specific software versions:
* linux-2.4.37.9
* gcc-3.4.6
* busybox-1.01
* uClibc-0.9.33.2
* binutils-2.32

I also had to statically link everything. I tried with dynamic linking in the beginning but the system would hang during boot, and I didn't want to troubleshoot this any further.

I have made some scripts to greatly simplify the whole process of building the cross-compiling toolchain and all the binaries. Bundled in a file here.

Unpack this into a directory and then simply run the following:

./build.sh
./rootfs.sh
          

I have used these on a Slackware 14.2 box with GCC 5.3.0
The result will be a directory with the "rootfs" and a "bzImage" located inside the kernel build tree.

The rootfs is exported over NFS in /etc/exports like this:

/home/nfs/rootfs *(rw,sync,no_root_squash,no_all_squash,no_subtree_check)
          

Also note that the legacy NFSv2 protocol needs to be actived!

To prepare the kernel is the tricky part. To load it over TFTP with Etherboot you have to use the mkelf-linux script from the mknbi package. This package is not compilable on modern Linux distributions, so I ended up compiling and using it from an old Slackware 11.0 installation running in a QEMU virtual machine.

I used the command as follows:

mkelf-linux --output=pc50linux.nb --ip="192.168.0.3:192.168.0.2:192.168.0.1:255.255.255.0:pc50" --append="root=/dev/nfs nfsroot=/home/nfs/rootfs" bzImage
          

Where .3 is the booted client PC, .2 is the NFS server and .1 is the gateway and TFTP server.

The final step is to activate the TFTP/DHCP server. I used dnsmasq for this, with the following relevant configuration:

dhcp-host=00:ff:ff:ff:ff:ff,192.168.0.3,infinite,set:pxelinux
enable-tftp
tftp-root=/var/ftpd
dhcp-boot=net:pxelinux,/var/ftpd/pc50linux.nb,boothost,192.168.0.1
          


Some additional information: I have no Boot ROM on the Ethernet card, so I used a floppy disk to actually kick-start the network booting. More specifically, the "3c509.dsk" image made from compiling parts of the "Etherboot" package. Since this also isn't compilable on modern distributions, I had to use the Slackware 11.0 QEMU virtual machine again.

Commodore PC 50-II


Topic: Configuration, by Kjetil @ 01/12-2019, Article Link

OpenVPN Setup for Android

There are probably many ways to do this, but this is what worked for me in the end, after several trials and errors. I ended up making a "standalone" server solution based on running in GNU Screen to avoid messing too much with my existing server.

I started by downloading the EasyRSA scripts to help generating certificates and such. Then ran the following commands:

./easyrsa init-pki
./easyrsa build-ca
./easyrsa build-server-full server
./easyrsa build-client-full client
./easyrsa gen-dh
          

You will have to enter a CA key passphrase and PEM passphrase, keep those for later.

Once the files are created, copy them into a new location where everything will be stored, in my case the "openvpn" directory under my home directory:

mkdir ~/openvpn
cp pki/ca.crt ~/openvpn/
cp pki/dh.pem ~/openvpn/
cp pki/issued/client.crt ~/openvpn/
cp pki/issued/server.crt ~/openvpn/
cp pki/private/ca.key ~/openvpn/
cp pki/private/client.key ~/openvpn/
cp pki/private/server.key ~/openvpn/
          


The OpenVPN server configuration file must be created manually, at ~/openvpn/server.cfg with the following contents:

ca ca.crt
cert server.crt
key server.key
dh dh.pem
dev tun
ifconfig 10.8.0.1 10.8.0.2
tls-server
port 1194
proto udp
comp-lzo
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
push "ifconfig 10.8.0.2 10.8.0.1"
mode server
verb 4
client-config-dir ccd
          


Create a new directory "ccd" under the directory structure and create the file ~/openvpn/ccd/client with the following single line:

iroute 10.8.0.0 255.255.255.0
          


To be able to start things easily and open the necessary parts of the firewall a script like this can be used, placed at ~/openvpn/start.sh:

#!/bin/sh
screen -S openvpn -d -m sudo openvpn server.cfg

sudo iptables -A INPUT -p udp --dport 1194 -i eth0 -j ACCEPT
sudo iptables -A INPUT -i tun0 -j ACCEPT
sudo iptables -A FORWARD -i tun0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -d 10.8.0.0/255.255.255.0 -j ACCEPT
          

This particular server already has iptables setup for NAT and such, so that is not present in this configuration.

Finally, the Android OpenVPN application requires a matching "ovpn" file with the client configuration. I had to make this one by manually looking something like this:

client
dev tun                             
proto udp
remote my.openvpn.server.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
comp-lzo
verb 3
<cert>
-----BEGIN CERTIFICATE-----
<contents of client.crt file>
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN ENCRYPTED PRIVATE KEY-----
<contents of client.key file>
-----END ENCRYPTED PRIVATE KEY-----
</key>
<ca>
-----BEGIN CERTIFICATE-----
<contents of ca.crt file>
-----END CERTIFICATE-----
</ca>
          


Topic: Configuration, by Kjetil @ 18/08-2019, Article Link

Commodore 64 Game Cheats

I recently tried out the same tricks from my older article about DOS games, but for a Commodore 64 game instead. This time using the VICE emulator for Blagger by Alligata, a game I could never finish as a kid.

I present some of the steps I used to create the "cheat" patch for infinite lives.
1) Start the game (should start with 5 lives) and go into the VICE monitor.
2) Dump the memory and state of the C64 with the "dump" command.
3) Continue the game, and just loose 1 life.
4) Re-enter the monitor and dump the memory and state again with the "dump" command.
5) Convert the dumps to hex and do a diff on them, to see what has changed. It may take a while to find what you are looking for, which may require additional dumps.
Eventually I found this suspicious memory area, where two values were decremented twice:

101c101
< 00000740  20 20 20 20 1e 57 57 1e  57 57 1e 7a 3a 3b 42 43  |    .WW.WW.z:;BC|
---
> 00000740  20 20 20 20 1e 57 57 1e  57 57 1e 7a 3a 3b 44 45  |    .WW.WW.z:;DE|
          

Although this is at address 0x74e and 0x74f in the dump file, the actual memory addresses are 0x6ca and 0x6cb due to the format of the dump.
6) Now, with an address to look at, set a watch point on this in the VICE monitor.
7) Continue the game again and loose another life.
8) The monitor should now stop execution automatically if done correctly. In my case it displayed:

(C:$1102) w $06ca
WATCH: 1  C:$06ca  (Stop on load store)
(C:$1102) x
#1 (Stop on  load 06ca)  076 050
.C:0de6  AE CA 06    LDX $06CA      - A:01 X:44 Y:00 SP:f6 ..-....C  184810550
.C:0de9  CA          DEX            - A:01 X:44 Y:00 SP:f6 ..-....C  184810550
(C:$0de9)
          

This assembly instruction (DEX) means the memory area is being decremented, exactly what we are looking for.
9) After investigation of the assembly code in that area I found two decrement instructions. These could be patched with NOP (No Operation) instructions (6502 machine code 0xEA) from the VICE monitor like so:

(C:$0e0c) > $0de9 ea
(C:$0e0c) > $0dea ea
          

10) Now, when continuing to play the game, any lost life is simply ignored.

To apply a patch like this permanently, do it on the file (in this case a PRG file) instead of directly in memory of course. The code location will be different, so it must be searched for manually.

Topic: Configuration, by Kjetil @ 02/07-2019, Article Link

VPN Through SSH Tunnel

Not just VPN through an SSH tunnel, but also a Wi-Fi hotspot that directs all traffic through it! I needed this to be able to reach the Google Play store on my Android phone in China. I used two WLAN interfaces for this, but it should be possible with one WLAN and one wired connection as well.

VPN through SSH tunnel principle diagram.


Here are the complete steps, with the contents of the files listed after. Many of the commands are started through screen sessions, since they are daemons that will keep running.

First of all, make sure the interface that will be used to connect to the remote SSH server is up and running, then connect to the server and create the SSH tunnel for port 1194, which is used for VPN:

ssh user@your-ssh-server.com -L 127.0.0.1:1194:127.0.0.1:1194
          


One the remote server, enter the following commands:

# Start OpenVPN server:
screen -S openvpn -d -m sudo openvpn server.cfg

# Forward all the traffic from the OpenVPN tunnel interface:
sudo iptables -A INPUT -i tun0 -j ACCEPT
sudo iptables -A FORWARD -i tun0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -d 10.8.0.0/255.255.255.0 -j ACCEPT

# Enable IP forwarding on server:
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
          


Back on the local machine, enter the following commands:

# IP address for Wi-Fi hotspot:
sudo ifconfig wlan0 192.168.8.1 netmask 255.255.255.0

# Start DHCP server for Wi-Fi hotspot:
screen -S dnsmasq -d -m sudo dnsmasq --conf-file=dnsmasq.conf --no-daemon

# Start Host-AP deamon:
screen -S hostapd -d -m sudo hostapd hostapd.conf

# Start OpenVPN client:
screen -S openvpn -d -m sudo openvpn client.cfg

# Let the SSH connection bypass the VPN default route:
SSH_IF='wlan1'
SSH_IP=`host your-ssh-server.com | sed -e 's/.*address //'`
GW_IP=`route -n | grep "^0.0.0.0" | grep $SSH_IF | sed -e 's/0.0.0.0 *//' | sed -e 's/ .*//'`
sudo route add $SSH_IP gw $GW_IP $SSH_IF

# Override the DNS resolver:
sudo cp resolv.conf /etc/resolv.conf

# Enable IP forwarding on local machine:
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"

# Enable NATing through the tunnel interface from the Wi-Fi hotspot:
sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
sudo iptables -A FORWARD -i tun0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i wlan0 -o tun0 -j ACCEPT
          


That should be it, now the phone can connect to the local Wi-Fi hotspot and reach the Internet through the remote SSH server.

Some useful commands for troubleshooting:

sudo iptables -L -v -n
sudo tcpdump -i tun0
          


OpenVPN client configuration. (client.cfg):

remote 127.0.0.1
proto tcp-client
dev tun
ifconfig 10.8.0.2 10.8.0.1
secret static.key
redirect-gateway local def1
route 192.168.0.0 255.255.255.0
          


OpenVPN server configuration. (server.cfg):

dev tun
local 127.0.0.1
proto tcp-server
ifconfig 10.8.0.1 10.8.0.2
secret static.key
          


New DNS resolver configuration, using the Google DNS. This is important because it could have been set by a local DHCP client to a Chinese DNS resolver. (resolv.conf):

nameserver 8.8.8.8
          


DHCP server configuration. (dnsmasq.conf):

interface=lo,wlan0
no-dhcp-interface=lo
dhcp-range=192.168.8.20,192.168.8.254,255.255.255.0,12h
          


Host-AP Wi-Fi hotspot configuration. These are the more important options, I have excluded lots of others. (hostapd.conf):

interface=wlan0
driver=nl80211
ssid=YourSSID
hw_mode=g
wpa=2
wpa_passphrase=YourPassphrase
wpa_key_mgmt=WPA-PSK WPA-EAP
          


Topic: Configuration, by Kjetil @ 10/06-2018, Article Link

Renesas GCC Toolchains

The gcc-renesas.com webpage has good information on how to build the Renesas RX and RL78 toolchains, but the GCC versions used there are a little outdated. And in addition, some patches are applied.

So instead I tried to build the toolchains from scratch directly from the GNU sources, and also get the benefit of the newer GCC version 7 instead of GCC version 4.

My efforts were successful and I have automated it into a single script. Simply change the TARGET variable to build either RL78 or the RX toolchain. It installs everything into a separate directoy in /opt/ on the filesystem. Take a look:

#!/bin/bash
set -e

TARGET="rl78-elf"
#TARGET="rx-elf"
PREFIX="/opt/gcc-${TARGET}/"

export PATH="${PREFIX}bin:$PATH"

# 1) Prepare build directories:
if [ -d build ]; then
  echo "Old build directory detected, please remove it."
  exit 1
else
  mkdir -p build/autoconf
  mkdir -p build/binutils
  mkdir -p build/gcc
  mkdir -p build/gdb
  mkdir -p build/newlib
fi

# 2) Get sources:
if [ ! -d source ]; then
  mkdir source
  cd source
  wget "https://gnuftp.uib.no/autoconf/autoconf-2.64.tar.bz2"
  wget "https://gnuftp.uib.no/gcc/gcc-7.3.0/gcc-7.3.0.tar.xz"
  wget "https://gnuftp.uib.no/gdb/gdb-8.1.tar.xz"
  wget "https://gnuftp.uib.no/binutils/binutils-2.30.tar.xz"
  wget "ftp://sourceware.org/pub/newlib/newlib-2.5.0.tar.gz"
  tar -xvjf autoconf-2.64.tar.bz2
  tar -xvJf gcc-7.3.0.tar.xz
  tar -xvJf gdb-8.1.tar.xz
  tar -xvJf binutils-2.30.tar.xz
  tar -xvzf newlib-2.5.0.tar.gz
  cd ..
fi

# 3) Build autoconf:
cd build/autoconf
../../source/autoconf-2.64/configure --prefix=$PREFIX
make
sudo make install
cd ..

# 4) Build binutils:
cd binutils
../../source/binutils-2.30/configure --target=$TARGET --prefix=$PREFIX --enable-maintainer-mode --disable-nls --disable-werror
make
sudo make install
cd ..

# 5) Get gcc sources:
if [ ! -d ../source/gcc-7.3.0/gmp ]; then
  cd ../source/gcc-7.3.0
  ./contrib/download_prerequisites
  cd ../../build
fi

# 6) Build gcc (step 1):
cd gcc
../../source/gcc-7.3.0/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --disable-shared --with-newlib --enable-lto --disable-libstdcxx-pch --disable-nls --disable-werror
make all-gcc
sudo make install-gcc
cd ..

# 7) Build newlib:
cd newlib
../../source/newlib-2.5.0/configure --target=$TARGET --prefix=$PREFIX --disable-nls
make
sudo make install
cd ..

# 8) Build gdb:
cd gdb
../../source/gdb-8.1/configure --target=$TARGET --prefix=$PREFIX --disable-nls
make
sudo make install
cd ..

# 9) Build gcc (step 2):
cd gcc
make
sudo make install
          


Topic: Configuration, by Kjetil @ 03/03-2018, Article Link

Fluxbox Styles

I almost exclusively use the Fluxbox window manager on my systems. Recently I have looked into how to create custom styles, and have finally been able to boil it down into something that's easy to manage.

Here's a desktop screenshot of a style I made:

Custom Fluxbox Style


But the most interesting part is the trimmed down style file:

*.textColor: #009900
*.color: black
*.focus.color: #009900
*.focus.textColor: black
*.focused.color: #009900
*.focused.textColor: black
*.font: glisp
*.borderWidth: 1
*.borderColor: #009900

menu.bullet: triangle
menu.bullet.position: right
menu.title.color: #009900
menu.title.textColor: black
menu.title.justify: center
menu.frame.color: black
menu.frame.textColor: green
menu.hilite.color: #009900
menu.hilite.textColor: black
menu.frame.disableColor: grey50

window.button.focus.picColor: black
window.button.unfocus.picColor: green

window.*.focus: raised gradient vertical
window.*.focus.colorTo: #00ee00
toolbar.*.focused: raised gradient vertical
toolbar.*.focused.colorTo: #00ee00
menu.title: raised gradient vertical
menu.title.colorTo: #00ee00
          


In the corner of the screenshot you'll also notice conky running. Here is the conkyrc file creating a similar colorscheme to match the Fluxbox style.

alignment top_right
background yes
border_width 1
cpu_avg_samples 2
default_color green
default_outline_color green
default_shade_color green
draw_borders no
draw_graph_borders yes
draw_outline no
draw_shades no
use_xft no
xftfont DejaVu Sans Mono:size=12
gap_x 5
gap_y 5
minimum_size 300 5
net_avg_samples 2
no_buffers yes
out_to_console no
out_to_stderr no
extra_newline no
own_window no
own_window_class Conky
own_window_type desktop
own_window_transparent yes
stippled_borders 0
update_interval 1.0
uppercase no
use_spacer none
show_graph_scale no
show_graph_range no
double_buffer yes

TEXT
${color green4}Uptime:$color $uptime
${color green4}Battery:$color $battery ${battery_bar}
${color green4}RAM Usage:$color $mem/$memmax - $memperc% ${membar 4}
${color green4}CPU \#1:$color ${cpu cpu1}% ${cpubar cpu1 4}
${color green4}CPU \#2:$color ${cpu cpu2}% ${cpubar cpu2 4}
${color green4}CPU \#3:$color ${cpu cpu3}% ${cpubar cpu3 4}
${color green4}CPU \#4:$color ${cpu cpu4}% ${cpubar cpu4 4}
${color green4}Processes:$color $processes  ${color green4}Running:$color $running_processes
${color green4}Wired:$color ${addr eth0}
${color green4}Wireless:$color ${addr wlan0}
          


A final recommendation when using styles like this is to make sure that the "ls" command does not produce garish results. This setting helps:

export LS_COLORS='rs=00:di=01:ln=00:mh=00:pi=01:so=01:do=01:bd=01:cd=01:or=31;01:mi=00:su=00:sg=00:ca=00:tw=00:ow=00:st=00:ex=00:'
          


Topic: Configuration, by Kjetil @ 21/10-2017, Article Link

GR-KURUMI Makefiles for Linux

Here's some follow-up information on the GR-KURUMI microcontroller reference board mentioned in the previous article.

On the official Gadget Renesas pages you can find an online editor and compiler refered to as the "Web Compiler", but in case you want to build the sources on your own Linux box then some more work is required.

First of all, download and build the RL78 GCC toolchain. Follow this advice.

Second, you will need the linker script, crt0 and header files which are specific for the RL78. I got this from the Gadget Renesas Web Compiler by downloading an example project.

Finally, here is an example of a simplified Makefile, based around compiling the source file "led.c" into the binary file "led.bin", which can be flashed:

TOOL_PATH:=/path/to/RL78-Toolchain/prefix/bin

CFLAGS = -c -Os -ffunction-sections -fdata-sections -I. -Icommon
LDFLAGS = -Wl,--gc-sections -nostartfiles

led.bin: led.elf
	$(TOOL_PATH)/rl78-elf-objcopy -O binary $^ $@

led.elf: led.o crt0.o
	$(TOOL_PATH)/rl78-elf-gcc $(LDFLAGS) -T common/rl78_R5F100GJAFB.ld $^ -o $@

crt0.o: common/crt0.S
	$(TOOL_PATH)/rl78-elf-gcc $(CFLAGS) $^ -o $@

led.o: led.c
	$(TOOL_PATH)/rl78-elf-gcc $(CFLAGS) $^ -o $@

.PHONY: clean
clean:
	rm -f *.o *.elf *.bin
          


Here is the led.c example, which I have mostly just copied from the Internet and not written myself:

#include <iodefine.h>
#include <iodefine_ext.h>

#define LED_CYAN_PIN    PM1.BIT.bit7
#define LED_MAGENTA_PIN PM5.BIT.bit1
#define LED_YELLOW_PIN  PM5.BIT.bit0
#define LED_CYAN        P1.BIT.bit7
#define LED_MAGENTA     P5.BIT.bit1
#define LED_YELLOW      P5.BIT.bit0

__attribute__((interrupt))
void wdti_handler(void)
{
}

__attribute__((interrupt))
void it_handler(void)
{   
    LED_CYAN    ^= 1;
    LED_MAGENTA = 0;
    LED_YELLOW  ^= 1;
}

void main(void)
{
  asm("di");

  LED_CYAN_PIN    = 0;
  LED_MAGENTA_PIN = 0;
  LED_YELLOW_PIN  = 0;

  LED_CYAN    = 0;
  LED_MAGENTA = 0;
  LED_YELLOW  = 0;

  /* Setup clocks */                                      
  CMC.cmc = 0x11U; /* Enable XT1, disable X1 */
  CSC.csc = 0x80U; /* Start XT1 */
  CKC.ckc = 0x00U;

  /* Interval timer */
  OSMC.osmc = 0x80U;  /* Supply fsub to Interval Timer */
  RTCEN = 1;
  ITMK  = 1; /* Disable interrupt... */
  ITPR0 = 0; /* High pri... */
  ITPR1 = 0;
  ITMC.itmc = 0x8FFFU; /* 270ms... */
  ITIF = 0; /* interrupt request flag... */
  ITMK = 0; /* Enable interrupt... */

  asm("ei"); /* Enable interrupts */

  for(;;)
  {
    asm("stop"); /* STOP mode. */
  }
}
          


Topic: Configuration, by Kjetil @ 23/09-2017, Article Link

Slackware 14.2 on a USB-stick

It's exactly 10 years since the first post on this website.

Anyway, I discovered that installing Slackware on a USB-stick wasn't as easy as it was last time in 2012, and those instructions are no longer valid for newer versions like 14.2. The main problem is that the kernel no longer contains built-in support for USB mass storage and the extended file systems.

Here are the updated steps:

1. Boot a host machine with the original Slackware DVD.

2. Insert the USB-stick into the host machine and use fdisk to create a large single Linux (0x83) partition on it.

3. Run the Slackware setup program and choose the newly created USB-stick partition as the target, with an ext4 file system.

4. Near the end of the setup process, skip the step involving installation of the LILO boot loader!

5. Unplug the USB-stick and put it into another fully functional Slackware 14.2 box.

6. Mount and chroot into the USB-stick filesystem. (In my case this was at /dev/sdc1 mounted on /mnt/sdc1):

mount /mnt/sdc1
mount -o bind /proc /mnt/sdc1/proc
mount -o bind /sys /mnt/sdc1/sys
mount -o bind /dev /mnt/sdc1/dev
chroot /mnt/sdc1
          


6. Configure and update the Linux kernel, by following these steps:

cd /usr/src/linux
make menuconfig # Do the necessary changes as described below.
make
make modules
make modules_install
make install # Will fail on LILO install, but just ignore this since kernel image is still copied to /boot.
          

In menuconfig, make sure to change these from module to built-in:
* xHCI HCD (USB 3.0) support
* EHCI HCD (USB 2.0) support
* USB Mass Storage support
* Second extended fs support
* The Extended 3 (ext3) filesystem
* The Extended 4 (ext4) filesystem

7. Modify /etc/fstab on the USB-stick and make sure that the root file system uses the correct partition device on the target machine. (e.g. /dev/sdb1)

8. Create the file /boot/extlinux.conf on the USB-stick and input contents similar to this:

default Linux
prompt 1
timeout 100
label Linux
  kernel vmlinuz
  append root=/dev/sdb1 rootwait vga=normal vt.default_utf8=0
          


8. Exit the chroot environment:

exit
umount /mnt/sdc1/proc
umount /mnt/sdc1/sys
umount /mnt/sdc1/dev
          


9. Install the boot loader on the USB-stick with the "extlinux" command like this: "extlinux -i /mnt/sdc1/boot". (Replace /mnt/sdc1 with correct mount point if necessary.)

10. Unmount the USB-stick and overwrite the master boot record on it with a command like this: "cat /usr/share/syslinux/mbr.bin > /dev/sdc". (Replace /dev/sdc with correct device if necessary.)

Topic: Configuration, by Kjetil @ 28/07-2017, Article Link

4096 Byte Sector Mount

Using a large hard disk of over 2TB on a USB enclosure, and then attempting to use the same disk on a regular Serial ATA interface may not work at all. The issue lies in the USB enclosure using some trick to convert 512 byte sectors to 4096 byte sectors when displaying the disk to the OS. I present here the solution to mount and read such a disk with Linux.

I have used a 4TB disk with a small partition to experiment.
When the disk is connected to the USB enclosure, Linux reports it with 4096-byte logical blocks:

usb 2-1.2: new high speed USB device using ehci_hcd and address 4
usb 2-1.2: New USB device found, idVendor=174c, idProduct=5106
usb 2-1.2: New USB device strings: Mfr=2, Product=3, SerialNumber=1
usb 2-1.2: Product: USB to ATA/ATAPI bridge
usb 2-1.2: Manufacturer: Asmedia
usb 2-1.2: SerialNumber: 30700000000000000A22
scsi9 : usb-storage 2-1.2:1.0
scsi 9:0:0:0: Direct-Access     WDC WD40 EZRZ-00WN9B0     80.0 PQ: 0 ANSI: 0
sd 9:0:0:0: Attached scsi generic sg6 type 0
sd 9:0:0:0: [sdf] 976754646 4096-byte logical blocks: (4.00 TB/3.63 TiB)
sd 9:0:0:0: [sdf] Write Protect is off
sd 9:0:0:0: [sdf] Mode Sense: 23 00 00 00
sd 9:0:0:0: [sdf] Assuming drive cache: write through
          


But when connected on the SATA interface, Linux reports it with 512-byte logical blocks:

ata6.00: ATA-9: WDC WD40EZRZ-00WN9B0, 80.00A80, max UDMA/133
ata6.00: 7814037168 sectors, multi 0: LBA48 NCQ (depth 0/32)
ata6.00: configured for UDMA/100
ata6: EH complete
scsi 5:0:0:0: Direct-Access     ATA      WDC WD40EZRZ-00W 0A80 PQ: 0 ANSI: 5
sd 5:0:0:0: [sdd] 7814037168 512-byte logical blocks: (4.00 TB/3.64 TiB)
sd 5:0:0:0: [sdd] 4096-byte physical blocks
sd 5:0:0:0: [sdd] Write Protect is off
sd 5:0:0:0: [sdd] Mode Sense: 00 3a 00 00
sd 5:0:0:0: [sdd] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
          


Attempting to mount the partition directly will fail because of the sector (block) mismatch:

# mount /dev/sdd1 /mnt/sdd1
mount: /dev/sdd1 is write-protected, mounting read-only
NTFS signature is missing.
Failed to mount '/dev/sdd1': Invalid argument
The device '/dev/sdd1' doesn't seem to have a valid NTFS.
Maybe the wrong device is used? Or the whole disk instead of a
partition (e.g. /dev/sda, not /dev/sda1)? Or the other way around?
          


To get around this, we need to use a loopback device, but first some calculations must be done, based on the start and end sectors of the partition. This data can be gotten with e.g. fdisk:

# fdisk -l /dev/sdd
Disk /dev/sdd: 3.7 TiB, 4000787030016 bytes, 7814037168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x52205024

Device     Boot Start   End Sectors  Size Id Type
/dev/sdd1         256 25855   25600 12.5M 83 Linux
          


Using 4096 byte sectors, we get the start sector at byte: 4096 * 256 = 1048576
And a byte size of: 4096 * 25600 = 104857600

Using these numbers, the partition can be mounted like so:

losetup --verbose --offset 1048576 --sizelimit 104857600 /dev/loop0 /dev/sdd
mount /dev/loop0 /mnt/loop
          


And after use, unmounted like so:

umount /mnt/loop
losetup -d /dev/loop0
          


Topic: Configuration, by Kjetil @ 17/05-2017, Article Link

Libvirt for KVM Guest

Referring to the Buildroot-based KVM Guest earlier, here is a way to set it up using libvirt: The virtualization API. Using libvirt instead of just QEMU gives additional flexibility, like easier pinning of physical CPUs to VCPUs and so on.

This setup also assumes that the root filesystem is already laid out in /tmp/kvm_guest, to be shared using the 9P protocol. Due to the fact that many files in the root filesystem are owned by root, the whole virtualization also needs to be run as root, or else the host will not allow access to the shared files.

Here is the XML configuration file for libvirt, some paths and the UUID may need to be changed. I named it "kvm_guest.xml":

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
  <name>kvm_guest</name>
  <uuid>00000000-0000-0000-0000-000000000000</uuid>
  <memory unit='KiB'>131072</memory>
  <currentMemory unit='KiB'>131072</currentMemory>
  <vcpu placement='static'>1</vcpu>
  <os>
    <type arch='x86_64' machine='pc-i440fx-2.6'>hvm</type>
    <kernel>/tmp/buildroot/kvmguest/output/images/bzImage</kernel>
    <cmdline>root=/dev/root rw rootfstype=9p rootflags=trans=virtio console=hvc0</cmdline>
  </os>
  <features>
    <acpi/>
  </features>
  <cpu mode='custom' match='exact'>
    <model fallback='allow'>kvm64</model>
  </cpu>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
    <controller type='pci' index='0' model='pci-root'/>
    <memballoon model='none'/>
    <console type='pty'>
      <target type='virtio' port='0'/>
    </console>
    <interface type='ethernet'>
      <mac address='00:00:de:ad:be:ef'/>
      <target dev='tap0'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </interface>
  </devices>
  <qemu:commandline>
    <qemu:arg value='-chardev'/>
    <qemu:arg value='stdio,id=char0'/>
    <qemu:arg value='-device'/>
    <qemu:arg value='virtio-serial'/>
    <qemu:arg value='-device'/>
    <qemu:arg value='virtconsole,chardev=char0'/>
    <qemu:arg value='-fsdev'/>
    <qemu:arg value='local,id=fs0,path=/tmp/kvm_guest,security_model=none'/>
    <qemu:arg value='-device'/>
    <qemu:arg value='virtio-9p-pci,fsdev=fs0,mount_tag=/dev/root'/>
  </qemu:commandline>
</domain>
          


It can then be started and accessed like so:

sudo /etc/rc.d/rc.libvirt start
sudo virsh create kvm_guest.xml
sudo virsh console kvm_guest
          


The rc.libvirt script is possibly Slackware specific, your system may have a different way to start the libvirt daemons.

Topic: Configuration, by Kjetil @ 04/03-2017, Article Link

Bluray on Slackware

Here's information on how I was able to play encrypted Bluray disks on Slackware using a custom MPlayer.

This statement from the MPlayer homepage is vital:
"MPlayer does support encrypted BluRay playback, though not all steps are handled by MPlayer itself. The two alternative methods use the URL schemes bd:// (always supports decryption, but you need the key for each and every disk in ~/.dvdcss/KEYDB.cfg and only works well with very simple BluRays, similar to dvd:// vs. dvdnav://) and br:// (uses libbluray and should support the same as VideoLAN in the link below but that is untested)."

I only got it to work with the "br://" scheme. The MPlayer package that follows the default Slackware installation does NOT link to libbluray, so I had to download and compile it manually, and then use this separate MPlayer binary for Bluray playback only. Prior to this, I had already installed libbluray, libbdplus and libaacs on the system.

I launch it with the following helper script:

#!/bin/sh
if ! fgrep /mnt/cdrom /proc/mounts > /dev/null; then
  mount /mnt/cdrom || exit 1
fi

# Enable debugging info for libbluray:
export BD_DEBUG_MASK="0xFFFFFFF"

# NOTE: Set the BLURAY_TITLE variable to change titles.
# NOTE: Use -chapter <id> argument to change chapters.
export BLURAY_TITLE=0
exec ~/opt/mplayer-bluray-bin br://$BLURAY_TITLE//mnt/cdrom "$@"
          


Finally, you will need to have an updated KEYDB.cfg file at ~/.config/aacs/KEYDB.cfg and hope that the VUK (Volume Unique Key) has been discovered for your Bluray disc.

Topic: Configuration, by Kjetil @ 18/02-2017, Article Link

Buildroot for KVM Guest

Here is a set of configuration files to quickly build a minimal KVM-based hypervisor guest with Buildroot. It attempts to use mostly VirtIO paravirtualization to maximize performance. This includes virtual console, virtual network and virtualized filesystem with the 9P protocol.

These files are based on version 2016.11 of Buildroot, gotten from https://buildroot.org/downloads/buildroot-2016.11.tar.bz2

Main Buildroot configuration file, should be stored as "configs/kvm_guest_defconfig" in the Buildroot structure:

BR2_x86_64=y
BR2_x86_core2=y
BR2_TOOLCHAIN_BUILDROOT_GLIBC=y
BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_4=y
BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_TARGET_GENERIC_HOSTNAME="kvm-guest"
BR2_TARGET_GENERIC_ISSUE="Welcome to Virtualized KVM Guest"
BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y
BR2_TARGET_GENERIC_GETTY_PORT="hvc0"
BR2_TARGET_GENERIC_GETTY_BAUDRATE_115200=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.4.38"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/kvm_guest/linux-4.4.config"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_ROOTFS_EXT2_4=y
# BR2_TARGET_ROOTFS_TAR is not set
          


Linux kernel configuration, should be stored as "board/kvm_guest/linux-4.4.config":

CONFIG_SYSVIPC=y
CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_NAMESPACES=y
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_SMP=y
CONFIG_HYPERVISOR_GUEST=y
CONFIG_SCHED_SMT=y
CONFIG_NUMA=y
CONFIG_IA32_EMULATION=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_VIRTIO_BLK=y
CONFIG_NETDEVICES=y
CONFIG_VIRTIO_NET=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_VIRTIO=y
CONFIG_VIRT_DRIVERS=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_9P_FS=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_DEBUG_FS=y
CONFIG_STACKTRACE=y
          


Once the files are in place, the build can be performed with:

make kvm_guest_defconfig
make
          


Here is a helper script to unpack the root filesystem and launch the whole thing under QEMU:

#!/bin/sh

if [ `id -u` != "0" ]; then
  echo "Must be root!"
  exit 1
fi

cd `dirname "$0"`

if [ ! -d /tmp/kvm_guest ]; then
  mkdir -p /tmp/kvm_guest
  mkdir -p /tmp/kvm_guest_loop
  mount -o loop output/images/rootfs.ext4 /tmp/kvm_guest_loop
  cp -a /tmp/kvm_guest_loop/* /tmp/kvm_guest
  umount /tmp/kvm_guest_loop
  rmdir /tmp/kvm_guest_loop
fi

qemu-system-x86_64 \
  -enable-kvm \
  -cpu host \
  -m 128 \
  -kernel output/images/bzImage \
  -serial none \
  -display none \
  -monitor none \
  -chardev stdio,id=char0 \
  -device virtio-serial \
  -device virtconsole,chardev=char0 \
  -fsdev local,id=fs0,path=/tmp/kvm_guest,security_model=none \
  -device virtio-9p-pci,fsdev=fs0,mount_tag=/dev/root \
  -net nic,macaddr=00:00:de:ad:be:ef,model=virtio,vlan=1 \
  -net tap,ifname=tap0,vlan=1,script=no,downscript=no \
  -append "root=/dev/root rw rootfstype=9p rootflags=trans=virtio console=hvc0"
          


Topic: Configuration, by Kjetil @ 14/01-2017, Article Link

Steam on Slackware 14.2

Slackware 14.2 was recently released, so I decided to attempt a Steam installation on it, which succeeded in the end.

Here are the steps I followed:
1) Download and install the 64-bit version of Slackware 14.2. You can get it here: http://www.slackware.com/getslack/torrents.php
2) Setup "multilib", so the system is able to run 32-bit programs. Use this guide: http://www.slackware.com/~alien/multilib/.
3) Install OpenAL, which is a dependency for Steam. I recommend to use SlackBuilds: https://slackbuilds.org/repository/14.2/libraries/OpenAL/
4) Install Steam. Also easy with SlackBuilds: https://slackbuilds.org/repository/14.2/games/steam/
5) Install a proprietary graphics driver, for better OpenGL performance.

It is important to install a 64-bit base system because some of the games on Steam are in fact only 64-bit. However, Steam itself and certain other games are only 32-bit, hence the need for multilib. I use an nVidia graphics card, and this had to be installed AFTER multilib had been set up, so I recommend doing the same.

I have done only minor testing so far, but I am still a bit sceptical about the OpenAL dependency. It seems that some games bundle their own OpenAL libraries, so they aren't always needed. It is also possible that a 32-bit version of the OpenAL library needs to be installed for certain stuff to work.

Topic: Configuration, by Kjetil @ 07/07-2016, Article Link

Japanese Input on Slackware

I have been looking for the least intrusive way to enter Japanese text on my main Slackware box, without messing with the rest of the system. I am used to running with $LANG set to "en_US", which is the Slackware default. Then using Latin-1/ISO-8859-1 as the encoding in the filesystem and so on.

The goal is enter Japanese text into Mozilla Firefox and (G)Vim, under the Fluxbox window manager.

Fortunately, those two programs are GTK-based and starts SCIM automatically as long as certain environment variables are set. Here is how it's done:

#!/bin/sh
export LC_CTYPE='ja_JP.utf8'
export GTK_IM_MODULE="scim-bridge"
firefox
          

In that Firefox session, Control + Space can be used to switch between input methods.

Topic: Configuration, by Kjetil @ 11/12-2015, Article Link

Buildroot for 486

Here are the steps I used in order to get a brand new Linux version 4 kernel running on an old 486 DX computer. The setup is based on the Buildroot system for making embedded systems. The end result is the kernel with a very simple BusyBox based userland.

All the steps are based on the 2015.05 version of Buildroot, gotten from http://buildroot.uclibc.org/downloads/buildroot-2015.05.tar.gz

Get the three necessary configuration files from Here.

First of all copy the configuration files into Buildroot and prepare it:

mkdir board/i486
cp i486_defconfig configs/
cp linux-4.0.4-i486.defconfig board/i486
cp extlinux.conf board/i486
make i486_defconfig
          


For any further changes to the configuration, use:

make menuconfig
make linux-menuconfig
          


Then build!:

make
          


I had to use extlinux as a bootloader, since neither syslinux nor GRUB worked correctly in my case. A Compact Flash card was inserted as /dev/sdd, and setup like this:

fdisk /dev/sdd # One primary partition, active, uses all space.
sudo cat /usr/share/syslinux/mbr.bin > /dev/sdd
mkfs.ext2 /dev/sdd1
          


Once the CF card is prepared, relative from the Buildroot folder, the files can be copied over:

mount /mnt/sdd1
sudo tar xf ./output/images/rootfs.tar -C /mnt/sdd1
sudo mkdir /mnt/sdd1/boot
sudo cp ./output/images/bzImage /mnt/sdd1/boot/
sudo cp ./board/i486/extlinux.conf /mnt/sdd1/boot/
sudo extlinux -i /mnt/sdd1/boot
sync
umount /mnt/sdd1
          


The card is then ready to be used.

Topic: Configuration, by Kjetil @ 01/08-2015, Article Link

Static PDCurses with MinGW

Statically linking a curses program on Windows is not as easy as it sounds. The main problem is that the PDCurses distributions that you'll find on sourceforge.net only contains the dynamic (DLL) library, not the static library. To get the static library, the only option seems to be to build PDCurses yourself from source.

I will try to explain. Before starting, make sure that you have installed MinGW and remembered to include the "make" program as well. Then proceed to download the PDCurses source and unpack it. Open a Windows command window and build it like this:

PATH=C:\MinGW\bin;C:\MinGW\msys\1.0\bin
cd PDCurses-3.4\win32\
make -f mingwin32.mak
          

(I had to set the PATH manually, or else I kept getting problems with a missing reference to libgmp-10.dll.)

The quick and dirty way to now link your curses program is to just copy the resulting pdcurses.a file (from the win32 directory) and the curses.h file (from the root PDCurses directory) to where you got your source and compile like this:

gcc -o program program.c -I. pdcurses.a
          


You can verify that the program is indeed statically linked by using objdump like this:

objdump -p program.exe
          

There should NOT be any reference to a PDCurses.dll file. If there is, well, then the program is still dynamically linked.

Sure a statically linked program is much larger, but it's much easier to distribute, since I doubt many people have the PDCurses.dll file on their Windows computers.

Topic: Configuration, by Kjetil @ 01/01-2014, Article Link

DOS Game Cheats

This is article is a response to the one about binary patching tools that I made earlier. The reason these tools were created in the first place, was to have an easy way to specify cheat patches for some old DOS games. Below you will find "infinite lives" patches for three games that I managed to run in a debugger and crack open. Use the binary patching tool to read these and apply the changes.

Blues Brothers:

# Apply to "1.EXE", Original md5sum: 4317d3fa97fff52b5785cc31d3110ece

# Get infinite lives:
000062cd: 90 90 90 90
0000a061: 90 90 90 90

# Remove infinite lives:
#000062cd: 26 fe 4f 61
#0000a061: 26 80 7f 61
          


Fantasy World Dizzy:

# Apply to "DIZZY.EXE", Original md5sum: d614048d262945dccf069fe968f747cb

# Get infinite lives:
00006038: 90 90 90 90 90 90

# Remove infinite lives:
#00006038: fe 0e 84 4d 78 5e
          


Soccer Kid:

# Apply to "KID.EXE", Original md5sum: b5c443e0c8a9099706f22b952b68b2c1

# Get infinite lives:
00001257: 90 90

# Remove infinite lives:
#00001257: 2c 01
          


Topic: Configuration, by Kjetil @ 01/07-2013, Article Link

Commodore 64 RS-232 Interface

By using a TTL-level RS-232 to USB converter, like this one, it was surprisingly easy to connect the Commodore 64 to a Linux box. I read somewhere that an inverter was required on the RxD/TxD signals, but during my testing with this converter, that was not necessary. This means you only need wires, and no additional electronics!

The RS-232 interface is found on the C64's user port, and the wiring is as follows:

C64 Signal:   C64 User Port:   Converter:
-----------------------------------------
Ground        A + N            Gnd
RxD           B + C            TxD
TxD           M                RxD 
          


The best terminal program for the Commodore 64 is NovaTerm, since it supports VT102/ANSI emulation and such.

Assuming the converter is connected to a Linux box and detected as /dev/ttyUSB0, the connection can be tested like this at 1200 baud, which is the most common:

screen /dev/ttyUSB0 1200
          


To provide a login prompt at 1200 baud and supporting ANSI escape characters, something like this can be run as root:

agetty -L ttyUSB0 1200 ansi
          


Here's a "screenshot" of NovaTerm 9.6c connected to a Linux box and running top:

Screenshot of top via NovaTerm.


Topic: Configuration, by Kjetil @ 19/01-2013, Article Link

Easy Kernel Upgrade

Here are the steps needed to compile a new Linux kernel (2.6.x or 3.x) on recent Slackware versions, based on the configuration of the old (running) kernel. Assuming a new kernel has been downloaded and unpacked into /usr/src, proceed like this:

# Become the super user:
su

# Move into the standard source(s) location:
cd /usr/src

# Remove old symlink:
rm linux

# Create new symlink:
# (Replace X.X.XX with whatever was downloaded.)
ln -s linux-X.X.XX linux

# Move into new kernel:
cd linux

# Copy old kernel configuration from running kernel:
cat /proc/config.gz | gunzip > .config

# Use old .config to make a new one:
# (Just press enter on all the questions to use defaults.)
make oldconfig

# Compile the kernel:
make

# Compile the modules:
make modules

# Install the modules:
# (Will be placed under /lib/modules/X.X.XX/)
make modules_install

# Install the kernel:
# (Everything is done automatically, including update of LILO!)
make install

# Reboot to load the new kernel:
reboot
          


Topic: Configuration, by Kjetil @ 26/12-2012, Article Link

SGI Indigo2 Network Boot

I have gotten hold of an old Silicon Graphics Indigo2, a beautiful piece of machinery. While attempting to recover the root password, the harddisk failed. But by some extreme luck, I managed to create a copy of the root filesystem before this happened. By using an SGI manual and lots of trial and error, I finally managed to boot IRIX and run the entire thing over the network from some Linux boxes. I have written down everything required to configure this in a LaTeX typesetted PDF document here.

Here's a photo of the desktop of IRIX 5.3, the UNIX used by SGI:

SGI Indigo2 Desktop Photo.


And in case you are wondering, here is a dump of the "hinv" command, showing the hardware specs:

Iris Audio Processor: version A2 revision 1.1.0
1 200 MHZ IP22 Processor
FPU: MIPS R4010 Floating Point Chip Revision: 0.0
CPU: MIPS R4400 Processor Chip Revision: 6.0
On-board serial ports: 2
On-board bi-directional parallel port
Data cache size: 16 Kbytes
Instruction cache size: 16 Kbytes
Secondary unified instruction/data cache size: 1 Mbyte
Main memory size: 192 Mbytes
EISA bus: adapter 0
Integral Ethernet: ec0, version 1
Integral SCSI controller 1: Version WD33C93B, revision D
Integral SCSI controller 0: Version WD33C93B, revision D
Disk drive / removable media: unit 2 on SCSI controller 0
Graphics board: GU1-Extreme
          


Topic: Configuration, by Kjetil @ 08/09-2012, Article Link

Easy File Selection

Here is a trick to let you easily select a file "graphically" for a console based application, when launched from a menu in a window manager. It uses Python and two modules that are delivered with the standard distribution.

The following example launches the "mplayer" media player with a selected file:

#!/usr/bin/python

import subprocess
import tkFileDialog

file = tkFileDialog.askopenfilename()
if len(file) > 0:
    subprocess.call(["mplayer", file])
          


Instead of launching the application directly, create a script like this and point the menu entry towards that instead.

Topic: Configuration, by Kjetil @ 04/04-2012, Article Link

Slackware on a USB-stick

I present here the steps I used to get Slackware Linux installed on a USB-stick. These are the steps that worked for me, and I cannot guarantee that they will work for everyone, but it will give some pointers that may be helpful anyway. Also, I assume the reader has some familiarity with Linux already, so the steps described may be somewhat high-level. The motivation behind this was to get Slackware running on a laptop without touching the contents of the original hard drive in it.

Also note that this particular procedure ties the USB-stick to a specific machine, or at least a specific device layout. It is necessary to know (beforehand) what device identifier will be assigned for the root partition on the particular machine where the USB-stick will be used. In my case this was /dev/sdb1, so this will be used in description below.

I divided the procedure into three major steps with some sub-steps each, here we go:

1. Install Slackware the usual way, but with the USB-stick as the root file system.
1.1. Boot a host machine with the original Slackware DVD.
1.2. Insert the USB-stick into the host machine and use fdisk to create a large single Linux (0x83) partition on it.
1.3. Run the Slackware setup program and choose the newly created USB-stick partition as the target, with an ext2 file system.
1.4. Near the end of the setup process, skip the step involving installation of the LILO boot loader!

2. Install the special "extlinux" boot loader on the USB-stick.
2.1. Insert the USB-stick into a host machine running the necessary Linux software, and mount it. (In my case this was /dev/sdc1 mounted on /mnt/usb.)
2.2. Modify /etc/fstab on the USB-stick and make sure that the root filesystem uses the correct partition device on the target machine. (e.g. /dev/sdb1)
2.3. Create the file /boot/extlinux.conf on the USB-stick and input contents similar to this:

default Linux
prompt 1
timeout 100
label Linux
  kernel vmlinuz
  append root=/dev/sdb1 rootdelay=10 vga=normal vt.default_utf8=0
          

The crucial configuration here is the "rootdelay" parameter to the kernel!
2.4. Install the boot loader on the USB-stick with the "extlinux" command like this example: "extlinux -i /mnt/usb/boot". (Replace /mnt/usb with correct mount point if necessary.)
2.5. Unmount the USB-stick and overwrite the master boot record on it with a command like this: "cat /usr/lib/syslinux/mbr.bin > /dev/sdc". (Replace /dev/sdc with correct device if necessary.)

3. Boot the target machine with the USB-stick.
3.1. For some reason I got a lot of "ext2_lookup" error messages while booting, and I am not really sure what these where caused by. But they can be fixed by running "e2fsck -y -v /dev/sdb1" in system recovery mode on the target machine.

Topic: Configuration, by Kjetil @ 12/02-2012, Article Link

TCP proxy with Netcat

Here is an interesting way to setup a generic TCP proxy using the netcat tool. What makes this method interesting is that traffic is not simply forwarded, but also sent back the other way. In order to do this, we require a two Unix pipes. One is created using the shell's own mechanism, and the other one is created manually as a named pipe (also known as a fifo).

Imagine we want to connect with telnet to some remote host, through the proxy like this:
local-host <-> proxy-host <-> remote-host.

On the proxy-host, enter this on the shell:

mkfifo /tmp/backpipe
nc -l -p 31337 < /tmp/backpipe | nc remote-host 23 > /tmp/backpipe
          


On the local-host, you can now enter this...:

telnet proxy-host 31337
          

...to reach port 23 on the remote host, and the traffic will flow in both directions.

Topic: Configuration, by Kjetil @ 18/07-2010, Article Link

Send and Receive files with Netcat

Here is a very simple way to send single files over the network, from one host to another. All you need is the netcat tool (also known as "nc" on the command line) and a couple of shell scripts. The transfer method is like FTP (over a straight TCP connection), but without the control channel.

Sender script:

#!/bin/sh
if [ -z "$1" ]; then
  echo "Usage: $0 <file to send>"
  exit 1
fi
nc $REMOTE_HOST 10001 -q 1 < "$1"
          


Receiver script:

#!/bin/sh
if [ -z "$1" ]; then
  echo "Usage: $0 <file to receive>"
  exit 1
fi
if [ -e "$1" ]; then
  echo "error: file exists."
  exit 1
else
  nc -p 10001 -l > "$1"
fi
          


In these examples, I am using a static host as the receiver ($REMOTE_HOST), so I don't need to specify it all the time. I have also decided on a static port number (10001) to use on both ends. The port number should probably be over 1024, so a normal user can create a listening socket on it. Also note that the receiver script always needs to be started before the sender script, if not, the connection will be refused.

Topic: Configuration, by Kjetil @ 29/11-2009, Article Link

Aspire One D250 Tweaks

I recently bought a new netbook, an Acer Aspire One D250 (HD version). Unfortunately, it was not possible to get it with Linux pre-installed, but I quickly re-formatted the hard-drive and installed Slackware 13.0. As usual with new hardware on Linux, some devices were not supported out of the box. After some tweaking however, I got it all up and running.

There were problems with both the ethernet and the wireless network interfaces, and also with the built in microphone controlled by the sound-card. Here is the "lspci -nn" information of the affected hardware devices:

0:1b.0 Audio device [0403]: Intel Corporation 82801G (ICH7 Family) High Definition Audio Controller [8086:27d8] (rev 02)
01:00.0 Network controller [0280]: Broadcom Corporation BCM4312 802.11b/g [14e4:4315] (rev 01)
03:00.0 Ethernet controller [0200]: Attansic Technology Corp. Atheros AR8132 / L1c Gigabit Ethernet Adapter [1969:1062] (rev c0)
          


The Wi-Fi interface can be fixed by installing the proprietary driver from Broadcom, instead of using the open source "b43" driver. (The b43 driver did not support this particular chip-set in the beginning of September when I installed everything, but this may have changed now.) I used the "hybrid-portsrc-x86_32-v5_10_91_9.tar.gz" driver with the "5_10_91_9_patch_2_6_29_kernel.zip" patch, and it has so far worked fine. I used the following steps to install it (some of the same information can also be found in the driver's readme file):

patch -p1 < patch_2.6.29_kernels
make -C /lib/modules/2.6.29.6-smp/build M=`pwd` clean
make -C /lib/modules/2.6.29.6-smp/build M=`pwd`
sudo cp wl.ko /lib/modules/2.6.29.6-smp/updates/drivers/net/wireless/
sudo depmod
reboot
          


The ethernet interface suffers from strange bugs in the driver (atl1c) shipped with the default kernel (2.6.29.6). Sometimes the chip itself disappears from the PCI bus, and does not show up until a complete power on/off has been done. The "ifconfig" command also shows crazy RX and TX values for the interface. I had to blacklist the kernel driver (by adding a file with "blacklist atl1c in the /etc/modprobe.d/ directory) and install the proprietary Atheros driver to fix it. I used the "AR81Family-linux-v1.0.0.10.tar.gz" file, which makes a new kernel module/driver named "atl1e".

The final thing I had issues with was the internal microphone, but it was fixed simply by updating the ALSA driver and library to version 1.0.21.

Topic: Configuration, by Kjetil @ 03/10-2009, Article Link

Amilo L7300 Tweaks

I have a Fujitsu Siemens Amilo L7300 laptop with Slackware Linux (kernel version 2.6.27) installed on it. As usual with laptop hardware, there are quirks and other special things, mostly because of the complex ACPI system.

In the /etc/rc.d/rc.local script that runs at start-up, I have put some commands that helps with some of the issues with this particular laptop. Hopefully this information can be of use for others also.

One issue is that the fans are turned on at power on, but they are never turned off. Normally they should be activated on demand when temperature rises and then deactivated as the temperature drops. They need to be turned on, then off and then on again manually to fix them.

Another issue is an annoying bug with the keyboard and touch-pad. Around 10% of the times the system has booted, they do not work at all, no reaction. The root cause seems to be the i8042 controller, but luckily it can be "reset".

Finally there is custom keyboard button (with a fan or atomic symbol on it) that is not recognised by the kernel. There is a command to map it, so that it can be used in X afterwards.

Here is parts of the rc.local script:

#!/bin/sh

echo "Reset ACPI fan status."
echo 3 >> /proc/acpi/fan/FN1/state
echo 3 >> /proc/acpi/fan/FN2/state
sleep 1
echo 0 >> /proc/acpi/fan/FN1/state
echo 0 >> /proc/acpi/fan/FN2/state
sleep 1
echo 3 >> /proc/acpi/fan/FN1/state
echo 3 >> /proc/acpi/fan/FN2/state

echo "Reset i8042 keyboard and touch-pad."
echo -n "i8042" > /sys/bus/platform/drivers/i8042/unbind 
sleep 1
echo -n "i8042" > /sys/bus/platform/drivers/i8042/bind 

echo "Assign keycode for extra key on keyboard."
/usr/bin/setkeycodes 6d 120
          


Topic: Configuration, by Kjetil @ 01/09-2009, Article Link

X Terminal Directory Hack

When working under the X Window System environment with multiple terminals opened, I usually work in the same directory on the file system. Instead of manually changing directory every time a new terminal is opened, I had an idea to do it with shell functions like this:

function mk { pwd | xclip; }
function rt { cd `xclip -o`; }
          


These functions will use the X clipboard to store and retrieve the current directory using the xclip tool. This way, the current directory can be marked (mk) in the terminal currently in use and retrieved (rt) in the new terminal afterwards.

Topic: Configuration, by Kjetil @ 17/08-2009, Article Link

Deus Ex vblank fix.

Deus Ex is one of those games that seems to work flawlessly under Wine in Linux, except for this issue I will mention below.

If you play Deus Ex on a fast machine, you may experience that the audio dialogs cuts off to early. According to information lying around on the Internet, this seems to be a generic bug/weakness in the Unreal engine, and apparently affects all platforms(?). But it can be fixed by forcing sync to vblank, which slows down the (too fast) frame rate. There does not seem to be any way of doing this from the menus in Deus Ex, but it can be done by configuring it in the graphics driver.

On Linux (at least with the proprietary Nvidia drivers) there is an easy way to setup sync to vblank automatically, by setting an environment variable.

You can just wrap/replace the actual binary with a small shell script like this:

#!/bin/sh
export __GL_SYNC_TO_VBLANK=1
exec /path/to/deusex
          


Topic: Configuration, by Kjetil @ 06/03-2009, Article Link

OpenTTD music files in other formats.

OpenTTD is a multi-platform clone of the classic game Transport Tycoon.

Normally, the original midi files are used, and requires a midi player to play the music. The default midi player is "timidity", which produces excellent sound, but seems to use a lot of CPU, so I want to use something else.

It is actually possible to use other formats (and players) than midi, due to the way the music system is currently implemented in OpenTTD. When a music track is started; OpenTTD fork()s and starts the music player as a separate process with the music filename as an argument.

I have successfully managed to use "ogg123" (part of the vorbis-tools package from xiph.org) to play the music files, by converting all the midi files to Ogg Vorbis format and perform a single configuration change. In the configuration file "openttd.cfg", there is a section named "[music]", where a option named "extmidi" resides. Simply change the option value to "ogg123" or the name of the player you want to use. When converting the midi files to a different format, make sure the filenames of the new files are exactly the same as the old ones.

I tested this with OpenTTD version 0.5.3 under Linux.

Topic: Configuration, by Kjetil @ 31/12-2007, Article Link

TrueType fonts in Linux.

The GIMP was used to create the header logo on this site, and I used an old TrueType font I had lying around in it. But anyway, how does one install such fonts under Linux?

The answer is simple. Just copy the font file (as root) into the fonts directory with a command like this:
cp file.ttf /usr/share/fonts/corefonts/

Topic: Configuration, by Kjetil @ 29/07-2007, Article Link