Archive for August, 2009

TI-99/4A BASIC as a Scripting Language

Monday, August 24th, 2009

It is a good time for statically recompiled versions of BASIC from old computers.  First there was Apple I BASIC.  Then came Commodore BASIC.  Now, due to overwhelming demand, we’re proud to release TI-99/4A BASIC. For those unfamiliar the TI-99/4A was a home computer by Texas Instruments released in 1981. Unusually for the time it had a 16-bit CPU: the TMS9900.

Download the program from the project page on SourceForge. Binaries for Windows and Mac OS X are available and the source should compile on most POSIX-like systems. If you port it to a new platform please drop us a line; we’d love hear about it.

It supports the same interfaces as the previous projects.  You can use it interactively in direct mode:

$ tibasic
TI BASIC READY
>print 4*atn(1)
 3.141592654

>bye

Or you can write a line-numbered program:

$ tibasic
>10 FOR I=1 TO 10
>20 PRINT TAB(I);"Hello, world!"
>30 NEXT I
>RUN
Hello, world!
 Hello, world!
  Hello, world!
   Hello, world!
    Hello, world!
     Hello, world!
      Hello, world!
       Hello, world!
        Hello, world!
         Hello, world!

** DONE **

>BYE

You can also run programs from a file:

$ cat name.bas
10 INPUT "What is your name? ":N$
20 PRINT "Hello, ";N$;"!"

$ tibasic.exe name.bas
What is your name? James
Hello, James!

There are a few sample programs available on the homepage that you can run in this manner.

How it works

This program works much like the already mentioned Commodore BASIC project. The original program is statically recompiled to produce a new native binary. The recompiler is the work of Michael Steil and the  support for the TI-99/4A is by James Abbatiello.

The output of the recompiler is tibasic.c which is platform independent. The support functions are in runtime_functions.c and it is this file that you would edit to port to a new system or to add new features.

There are a couple quirks of the TI-99/4A which made this a bit trickier to support than the C64 version:

  • The BASIC interpreter was not written in assembly language as you might expect. Instead it was programmed in something called Graphics Programming Language (GPL). GPL was much like an assembly language with some high-level primitives for commonly needed functions. A program written in GPL would be assembled to bytecode and then run on an interpreter that was written in TMS9900 assembly language. This made BASIC programs on the machine rather slow. The CPU would execute the GPL interpreter. The GPL interpreter would run the BASIC interpreter. Finally, the BASIC interpreter would run your program. Only the TMS9900 code is statically recompiled in this program. The GPL still runs interpreted just as it did on the original machine. While it would theoretically be possible to statically recompile the GPL code as well this would be significantly more difficult since GPL was never officially documented by TI. The only definitive reference is the original interpreter.
  • C64 BASIC outputs characters to the screen via one function (CHROUT) which was easy to trap. TI-99/4A BASIC outputs to the screen with direct writes to video memory from multiple different places in the code. This requires some ugly hacks to get anything approximating reasonable on stdout.

Limitations

The Cassette, Disk, and Sound devices are not currently emulated. Contributions in these areas are most welcome.

Links

Amiga intern (PDF)

Tuesday, August 18th, 2009

(German) Die Qualität dieses Scans ist furchtbar, aber wenigstens ist die PDF durchsuchbar.

Dittrich, S., Gelfand, R., & Schemmel, J. (1988). Amiga intern. DĂźsseldorf: Data Becker. (PDF, 718 S., 11 MB)

DAS STEHT DRIN:

In der dritten überarbeiteten Auflage finden Sie alles von der Hardware über den Betriebssystemkern EXEC bis zum DOS, alle entscheidenden Informationen zum Amiga. Und zwar so verständlich, daß auch die Nicht-Profis unter Ihnen die Arbeitsweise des Amiga-Betriebssystems schnell verstehen werden.

Aus dem Inhalt:

  • Die Chips des Amiga (68000, CIA, Gary, Agnus, Denise, Paula)
  • Die Schnittstellen (Video, Audio, RGB, Centronics, seriell, Floppy, Gameport, Expansionsport, Zorro-Bus, Tastatur)
  • Programmierung der Hardware (Speicherbelegung, Interrupts, Copper, Blitter, Disk-Controller)
  • Strukturen des EXEC (Node, List, Libraries, Tasks)
  • Funktion des Multitasking (Task-Switching, Kommunikation zwischen Tasks, Exceptions, Traps, Semaphoren, Speicherverwaltung)
  • I/O-Handhabung beim Amiga durch Devices und I/O-Request Interrupt-Handhabung und Verwaltung der Ressources
  • RESET-feste Programme und Strukturen, Dokumentation der RESET-Routine Programmierung eigener Handler, Devices und Libraries
  • EXEC-Base (Dokumentation und Nutzung der Systemvariablen) DOS-Bibliothek (Funktionen, Parameter, Fehlermeldungen)
  • Disketten (Boot-Vorgang, Datenstrukturen, Programmaufbau) Fast-Filing-System auf Diskette und Festplatte
  • Programmstart, Parameter, Aufruf von CU und Workbench, detaillierte Beschreibung des internen Aufbaus der CU-Befehle (Interne DOS-Bibliothek) Ein-/Ausgaben (Tastatur, Bildschirm, Diskette, parallele und serielle Schnittstelle)

UND GESCHRIEBEN HABEN DIESES BUCH:

Johannes Schemmel ist Hardware-Spezialist mit der Fähigkeit, Gesamtzusammenhänge verständlich darzustellen. Stefan Dittrich als 68000-Spezialist hat schon mit seinem Buch “Amiga Maschinensprache” dem interessierten AmigaAnwender gezeigt, welche Fähigkeiten in dem Rechner stecken. Ralf Gelfand ist ausgefuchster Amiga-Programmierer, der spätestens seit dem großen Floppy-Buch zum Amiga ein Begriff ist.

ISBN 3-89011-104-1

Dangerous Xbox 360 Update Killing Homebrew

Tuesday, August 11th, 2009

On Tuesday, Microsoft has released an Xbox 360 software update that overwrites the first stage bootloader of the system. Although there have been numerous software updates for Microsoft’s gaming console in the past, this is the first one to overwrite the vital boot block. Any failure while updating this will break the Xbox 360 beyond repair. Statistics from other systems have shown that about one in a thousand bootloader updates goes wrong, and unless Microsoft has a novel solution to this problem, this puts tens of thousands of Xboxes at risk.

It seems that this update is being done to fix a vulnerability already known to the Free60 Project. This vulnerability has been successfully exploited to run arbitrary code, and a complete end user compatible hack has been in development for some time and is planned to be released on free60.org shortly. It will allow users to take back control of their Xboxes and run arbitrary code like homebrew applications or Linux right after turning on the console and without the need of a modchip, finally opening up the Xbox 360 to a level of hacking as the original Xbox.

Because of the dangerousness of the update and the homebrew lockout, the Free60 Project advises all Xbox 360 users to not update their systems to the latest software version. The Project website at http://free60.org/ will provide the latest information on this ongoing topic, including the final hack software.

Free60 (www.free60.org) is a project that aims to enable Xbox 360 users to run homebrew applications and operating systems like Linux on their consoles. The effort is headed by Felix Domke and Michael Steil, who have a background in dbox2, Xbox and GameCube hacking, and who have spoken at various conferences about their findings. Two years ago, Free60 released a hack that allowed arbitrary code execution using a game (“King Kong Hack”) as well as an adapted version of Linux, but this possibility has been disabled by Microsoft in subsequent updates of the Xbox 360 software.

Felix and Michael have repeatedly argued that game console manufacturers should open up their platforms to Linux and homebrew, similar to what Sony has done with the PlayStation 3.

(Felix Domke, Michael Steil, Free60 Project; 11 August 2009)

Minimizing the Assembly needed for Machine Initialization

Monday, August 10th, 2009

In many operating systems, I have seen overly complicated startup code. Too much is done in assembly, and printf() and framebuffer access is only available very late. In the next three blog posts, I will show how this can be avoided.

In this post, I am showing how little assembly code is needed for startup. Minimizing the assembly makes your code significantly more maintainable. Everything that really needs to be done is setting up the CPU state to support 64 bit (or 32 bit) C code running at physical addresses, and everything else, including setting up the final machine state, can be done in C with a little inline assembly. The following example switches from 16 bit (real mode) or 32 bit mode (flat protected mode) into 64 bit mode on an x86_64 CPU (NASM syntax):

PAGE_SIZE	equ	0x1000
STACK_SIZE	equ	16*1024

PML2		equ	0x1000
PML3		equ	PML2+PAGE_SIZE
PML4		equ	PML3+PAGE_SIZE

STACK_BOTTOM	equ	PML4+PAGE_SIZE
STACK_TOP	equ	STACK_BOTTOM+STACK_SIZE

CODE_START	equ	STACK_TOP

	org CODE_START

	[BITS 16]
	cli

	; clear 3 pages of pagetables
	mov edi, PML2
	xor eax, eax
	mov ecx, 3*4096/4
	rep stosd

	; set up pagetables
	mov dword [PML2], 0x87		; single 4 MB id mapping PML2
	mov dword [PML3], PML2 | 7	; single entry at PML3
	mov dword [PML4], PML3 | 7	; single entry at PML4

	; load the GDT
	lgdt [gdt_desc]

	; set PSE,  PAE
	mov eax, 0x30
	mov cr4, eax

	; long mode
	mov ecx, 0xc0000080
	rdmsr
	or eax, 0x100
	wrmsr

	; enable pagetables
	mov eax, PML4
	mov cr3, eax

	; turn on long mode and paging
	mov eax, 0x80010001
	mov cr0, eax

	jmp SEL_CS:code64

code64:
	[BITS 64]
	mov ax, SEL_DS
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax

	mov sp, STACK_TOP
	call start

inf:	jmp inf

gdt_desc:
	dw  GDT_LEN-1
	dd  gdt
	align 8
gdt	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; 0x00 dummy
gdt_cs	db 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xaf, 0x00 ; 0x08 code64
gdt_ds	db 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xaf, 0x00 ; 0x18 data64

GDT_LEN equ $ - gdt
SEL_CS equ gdt_cs - gdt
SEL_DS equ gdt_ds - gdt

While switching into 32 bit flat mode is trivial, switching into 64 bit mode requires setting up pagetables. This code sets up 4 MB of identity-mapped memory starting at address 0.

The code is designed to switch from 16 bit mode into 64 bit mode, but since 16 and 32 bit flat mode on i386 are assembly source compatible, you can replace “[BITS 16]” with “[BITS 32]“, and the code will switch from 32 bit to 64 bit mode. (Yes, it is possible to switch from real mode directly into 64 bit mode: osdev.org Forums)

If you use this code, be careful about the memory layout. The example leaves the first page in memory untouched (in case you need the original real mode BIOS IDT for something later), and occupies the next few pages for the pagetables and the stack. Your code should be above that, but, on a BIOS system, not be between 640 KB and 1 MB (this might be device memory and ROM), and also not above 1 MB before you have enabled the A20 gate.

While this code is enough to support 64 bit C code, this is not enough to set up the machine to support all aspects of an operating system. You probably want to set up your own GDT that has entries for 32 bit code and data too, you want to set up an IDT in order to be able to catch exceptions and interrupts, and you will need real pagetables to support virtual memory. Also, you will have to move your stack pointer once you have your final memory layout.

But it is possible to construct the overly complicated GDT, IDT and pagetable structures using readable C code, and the “lidt”, “lgdt” etc. instructions can be done in inline assembly. While this is not portable C code, it is possible to reuse large parts of the machine initialization for a 32 bit (i386) and a 64 bit (x86_64) version of the operating system, which is not as easy to get right in assembly.

In my next post, I am going to show how easy it is to get printf() working as soon as you reach C, so you don’t have to mess around with puts()- and print_hex()-like functions in early machine initialization.

Aggressive Tail Call Optimization

Tuesday, August 4th, 2009

In some i386/x86_64 assembly code my coworker was working on, there was a macro like this:

#define ENDFUNC leave \
                ret

Having forgotten about the exact implementation of the macro, he then wrote a function that ended like this:

        leave
        ENDFUNC

Now this obviously ended the function with

        leave
        leave
        ret

and he got very interesting results. What was happening?