Mercurial > hvf > hvf-old
changeset 485:a5a03e983d49
Merge branch 'loader'
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Wed, 20 Apr 2011 20:50:32 -0400 |
parents | 440c330d23ab (current diff) 25abe8a2c816 (diff) |
children | b08396f8a1d0 |
files | cp/Makefile cp/include/list.h cp/include/loader.h cp/ipl/ipl_rdr.S cp/ipl/ipl_tape.S_in cp/ipl/linker.script cp/ipl/loader.c cp/ipl/loader_asm.S cp/ipl/setmode.S cp/scripts/gen_rdr_ccws.sh cp/scripts/gen_tape_ipl_s.sh |
diffstat | 45 files changed, 3636 insertions(+), 1473 deletions(-) [+] |
line wrap: on
line diff
--- a/.gitignore Sat Feb 26 17:58:57 2011 -0500 +++ b/.gitignore Wed Apr 20 20:50:32 2011 -0400 @@ -1,3 +1,5 @@ *.swp *.orig *.rej + +installer.bin
--- a/Makefile Sat Feb 26 17:58:57 2011 -0500 +++ b/Makefile Wed Apr 20 20:50:32 2011 -0400 @@ -7,17 +7,33 @@ # all: + make -C build make -C lib make -C cp make -C nss/8ball + make -C loader + make -C installer + ./build/mkarchive \ + cp/hvf.directory text 80 \ + cp/hvf bin \ + loader/eckd.rto bin \ + loader/loader.rto bin \ + doc/installed_files.txt text 80 \ + > installer/archive.cpio + ./build/padcat installer/rdr.rto installer/loader.rto installer/archive.cpio > installer.bin doc: make -C doc/manual clean: + make -C build clean make -C lib clean make -C cp clean make -C nss/8ball clean + make -C loader clean + make -C installer clean make -C doc/manual clean + rm -f installer/archive.cpio + rm -f installer.bin .PHONY: all doc clean
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build/.gitignore Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,3 @@ +ccw_gen +padcat +mkarchive
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build/Makefile Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,16 @@ +HOSTCC=gcc +CFLAGS=-Wall -O2 -g + +all: ccw_gen padcat mkarchive + +clean: + rm -f ccw_gen padcat mkarchive + +ccw_gen: ccw_gen.c + $(HOSTCC) $(CFLAGS) -o $@ $< + +padcat: padcat.c + $(HOSTCC) $(CFLAGS) -o $@ $< + +mkarchive: mkarchive.c + $(HOSTCC) $(CFLAGS) -o $@ $<
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build/ccw_gen.c Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,252 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static char *deck_head = +"#\n" +"# NOTE: This file was automatically generated by " __FILE__ "\n" +"#\n" +"# During the system IPL, 24 bytes are read from the device.\n" +"#\n" +"# NOTE: zArch IPLs in ESA/390 mode.\n" +"#\n"; + +static char *card_head = +"\n" +"#######################################################################\n" +"# CARD %-3d #\n" +"#######################################################################\n"; + +static char *psw_head = +"#\n" +"# Bytes 0-7 contain PSW to be loaded after IO operation completes\n" +"#\n"; + +static char *psw = +" .byte 0x%c%c\n" +" # bits value name desc\n" +" # 0 0 <zero>\n" +" # 1 0 PER Mask (R) disabled\n" +" # 2-4 0 <zero>\n" +" # 5 0 DAT Mode (T) disabled\n" +" # 6 0 I/O Mask (IO) disabled\n" +" # 7 0 External Mask (EX) disabled\n" +"\n" +" .byte 0x%c%c\n" +" # bits value name desc\n" +" # 8-11 0 Key\n" +" # 12 1 <one>\n" +" # 13 0 Machine-Check Mask (M) disabled\n" +" # 14 0 Wait State (W) executing\n" +" # 15 0 Problem State (P) supervisor state\n" +"\n" +" .byte 0x%c%c\n" +" # bits value name desc\n" +" # 16-17 0 Address-Space Control (AS) disabled\n" +" # 18-19 0 Condition Code (CC)\n" +" # 20-23 0 Program Mask exceptions disabled\n" +"\n" +" .byte 0x%c%c\n" +" # bits value name desc\n" +" # 24-30 0 <zero>\n" +" # 31 0 Extended Addressing (EA) ! 64 mode\n" +"\n" +" .byte 0x%c%c # bits 32-39\n" +" .byte 0x%c%c # bits 40-47\n" +" .byte 0x%c%c # bits 48-55\n" +" .byte 0x%c%c # bits 56-63\n" +" # bits value name desc\n" +" # 32 1 Basic Addressing (BA) BA = 31, !BA = 24\n" +" # 33-63 addr Instruction Address Address to exec\n"; + +static char *psw_tail = +"\n" +"#\n" +"# The remaining 16 bytes should contain CCW to read data from device\n" +"#\n" +"\n" +"# CCW format-0:\n" +"# bits name\n" +"# 0-7 Cmd Code\n" +"# 8-31 Data Address\n" +"# 32 Chain-Data (CD)\n" +"# 33 Chain-Command (CC)\n" +"# 34 Sup.-Len.-Inditcation (SLI)\n" +"# 35 Skip (SKP)\n" +"# 36 Prog.-Contr.-Inter. (PCI)\n" +"# 37 Indir.-Data-Addr. (IDA)\n" +"# 38 Suspend (S)\n" +"# 39 Modified I.D.A. (MIDA)\n" +"# 40-47 <ignored>\n" +"# 48-63 number of bytes to read\n" +"\n" +"# CP-CCW 1\n" +" # READ 80 bytes of CCWs to 0x%06X\n" +" .byte 0x02, 0x%02X, 0x%02X, 0x%02X\n" +" .byte 0x%02X, 0x00, 0x00, 0x50\n" +"\n" +"# CP-CCW 2\n" +" # TIC to 0x%06X\n" +" .byte 0x08, 0x%02X, 0x%02X, 0x%02X\n" +" .byte 0x00, 0x00, 0x00, 0x00\n"; + +static char *pad = +"\n" +"#\n" +"# Pad to 80 bytes\n" +"#\n" +" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n" +" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n" +" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n" +" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n" +" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n" +" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n" +" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n"; + +static char *cp_ccw = +"\n" +"# CP-CCW %d\n" +" .byte 0x02, 0x%02X, 0x%02X, 0x%02X\n" +" .byte 0x40, 0x00, 0x00, 0x50\n"; + +#define CHAIN 0x40 + +static char *data_ccw = +"\n" +"# LOADER-CCW %d\n" +" .byte 0x02, 0x%02X, 0x%02X, 0x%02X\n" +" .byte 0x%02X, 0x00, 0x00, 0x50\n"; + +static char *nop_ccw = +"\n" +"# NOP-CCW %d\n" +" .byte 0x03, 0x00, 0x00, 0x08\n" +" .byte 0x60, 0x00, 0x00, 0x01\n"; + +#define ADDR(x) (((x)[0]<<16) | \ + ((x)[1]<<8) | \ + ((x)[2])) + +#define ADDRS(x) (x)[0], (x)[1], (x)[2] + +static void die(char *pgm, char *s) +{ + fprintf(stderr, "Error: %s\n", s); + fprintf(stderr, "Usage: %s <psw word 1> <psw word 2> <file size> " + "<address> <channel pgm addr>\n", pgm); + exit(1); +} + +static unsigned int unhex(char *pgm, char c) +{ + if ((c >= '0') && (c <= '9')) + return c - '0'; + if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + die(pgm, "Argument not hexadecimal"); + return 0; +} + +static void __add(unsigned int *addr, int a) +{ + int i; + + addr[2] += a; + for(i=2; i>=0; i--) { + if (addr[i] > 255) { + addr[i-1] += addr[i] / 256; + addr[i] %= 256; + } + } +} + +int main(int argc, char **argv) +{ + int i = 1, j; + unsigned int card; + unsigned int ccw_addr[3]; + unsigned int addr[3]; + unsigned int size; + unsigned int data_cards; + + if (argc != 6) + die(argv[0], "Invalid number of args"); + + if ((strlen(argv[1]) != 8) || + (strlen(argv[2]) != 8)) + die(argv[0], "Invalid PSW argument length"); + + size = atol(argv[3]); + if (!size) + die(argv[0], "Invalid file size"); + + if ((strlen(argv[4]) != 6) || + (strlen(argv[5]) != 6)) + die(argv[0], "Invalid addr argument length"); + + addr[0] = (unhex(argv[0], argv[4][0]) << 4) | + unhex(argv[0], argv[4][1]); + addr[1] = (unhex(argv[0], argv[4][2]) << 4) | + unhex(argv[0], argv[4][3]); + addr[2] = (unhex(argv[0], argv[4][4]) << 4) | + unhex(argv[0], argv[4][5]); + + ccw_addr[0] = (unhex(argv[0], argv[5][0]) << 4) | + unhex(argv[0], argv[5][1]); + ccw_addr[1] = (unhex(argv[0], argv[5][2]) << 4) | + unhex(argv[0], argv[5][3]); + ccw_addr[2] = (unhex(argv[0], argv[5][4]) << 4) | + unhex(argv[0], argv[5][5]); + + /* round up */ + if (size % 80) + size = size - (size % 80) + 80; + + data_cards = size / 80; + + printf(deck_head); + + printf(card_head, i); + printf(psw_head); + printf(psw, + argv[1][0], argv[1][1], argv[1][2], argv[1][3], + argv[1][4], argv[1][5], argv[1][6], argv[1][7], + argv[2][0], argv[2][1], argv[2][2], argv[2][3], + argv[2][4], argv[2][5], argv[2][6], argv[2][7]); + + if (data_cards == 1) + die(argv[0], "Cannot handle the case where size <= 80"); + + card = 2; + i = 0; + j = 1; + + printf(psw_tail, ADDR(ccw_addr), ADDRS(ccw_addr), CHAIN, + ADDR(ccw_addr), ADDRS(ccw_addr)); + printf(pad); + __add(ccw_addr, 80); + + for(i=0; i<=((data_cards+9)/10) + (((data_cards+9)/10)+9)/10 - 2; i++) { + printf(cp_ccw, i+3, ADDRS(ccw_addr)); + __add(ccw_addr, 80); + } + + while (i % 10) { + printf(nop_ccw, i); + i++; + } + + for(i=1; i<=data_cards; i++) { + printf(data_ccw, i, ADDRS(addr), + (i == data_cards) ? 0 : CHAIN); + + __add(addr, 80); + } + + return 0; + + printf(card_head, card++); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build/mkarchive.c Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2011 Josef 'Jeff' Sipek + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <libgen.h> + +typedef unsigned char u8; + +struct cpio_hdr { + u8 magic[6]; + u8 dev[6]; + u8 ino[6]; + u8 mode[6]; + u8 uid[6]; + u8 gid[6]; + u8 nlink[6]; + u8 rdev[6]; + u8 mtime[11]; + u8 namesize[6]; + u8 filesize[11]; + u8 data[0]; +}; + +struct buffer { + struct buffer *next; + int len; + u8 data[0]; +}; + +static void storeoct(u8 *buf, int len, unsigned val) +{ + len--; + + while(val) { + buf[len] = '0' + (val % 8); + val /= 8; + len--; + } +} + +static void mkhdr(struct cpio_hdr *hdr, char *fn, unsigned filesize) +{ + memset(hdr, '0', sizeof(struct cpio_hdr)); + + hdr->magic[1] = '7'; + hdr->magic[3] = '7'; + hdr->magic[5] = '7'; + + hdr->nlink[5] = '1'; + + storeoct(hdr->namesize, 6, strlen(fn)+1); + storeoct(hdr->filesize, 11, filesize); +} + +static unsigned __text(char *fn, int lrecl) +{ + struct cpio_hdr hdr; + struct buffer *first, *last, *cur, *tmp; + FILE *f; + int l; + unsigned flen; + + if (!lrecl) { + fprintf(stderr, "Error: zero lrecl is bogus\n"); + exit(1); + } + + f = fopen(fn, "rb"); + if (!f) { + fprintf(stderr, "Error: could not open file '%s'\n", + fn); + exit(1); + } + + flen = 0; + first = NULL; + last = NULL; + for(;;) { + cur = malloc(sizeof(struct buffer) + lrecl + 1); + if (!cur) { + fprintf(stderr, "Error: OOM\n"); + exit(2); + } + + if (!fgets((char*)cur->data, lrecl+1, f)) + break; + + l = strlen((char*)cur->data); + + if (l && cur->data[l-1]) + l--; + + assert(l <= lrecl); + + memset(cur->data+l, ' ', lrecl-l); + + cur->next = NULL; + if (!first) + first = cur; + if (last) + last->next = cur; + last = cur; + + flen += lrecl; + } + + fclose(f); + + mkhdr(&hdr, basename(fn), flen); + fwrite(&hdr, sizeof(hdr), 1, stdout); + fwrite(basename(fn), strlen(basename(fn))+1, 1, stdout); + + for(cur=first; cur; cur=tmp) { + fwrite(cur->data, 1, lrecl, stdout); + tmp = cur->next; + free(cur); + } + + return flen + strlen(basename(fn)) + 1 + sizeof(hdr); +} + +#define BUF_LEN 4096 +static unsigned __bin(char *fn) +{ + struct cpio_hdr hdr; + struct buffer *first, *last, *cur, *tmp; + FILE *f; + unsigned flen; + size_t s; + + f = fopen(fn, "rb"); + if (!f) { + fprintf(stderr, "Error: could not open file '%s'\n", + fn); + exit(1); + } + + flen = 0; + first = NULL; + last = NULL; + for(;;) { + cur = malloc(sizeof(struct buffer) + BUF_LEN); + if (!cur) { + fprintf(stderr, "Error: OOM\n"); + exit(2); + } + + memset(cur->data, 0, BUF_LEN); + if (!(s = fread(cur->data, 1, BUF_LEN, f))) + break; + + cur->next = NULL; + cur->len = s; + if (!first) + first = cur; + if (last) + last->next = cur; + last = cur; + + flen += s; + } + + fclose(f); + + mkhdr(&hdr, basename(fn), flen); + fwrite(&hdr, sizeof(hdr), 1, stdout); + fwrite(basename(fn), strlen(basename(fn))+1, 1, stdout); + + for(cur=first; cur; cur=tmp) { + fwrite(cur->data, 1, cur->len, stdout); + tmp = cur->next; + free(cur); + } + + return flen + strlen(basename(fn)) + 1 + sizeof(hdr); +} + +static void mktail(unsigned len) +{ + struct cpio_hdr hdr; + + mkhdr(&hdr, "TRAILER!!!", 0); + fwrite(&hdr, sizeof(hdr), 1, stdout); + printf("TRAILER!!!"); + + while(len % 512) { + fwrite("", 1, 1, stdout); // write a nul char + len++; + } +} + +int main(int argc, char **argv) +{ + int lrecl; + char *fn; + int i; + unsigned len; + + i=1; + len=0; + while((i+1) < argc) { + fn = argv[i]; + i++; + + if (!strcmp(argv[i], "text")) { + lrecl = atoi(argv[i+1]); + i += 2; + + len += __text(fn, lrecl); + } else if (!strcmp(argv[i], "bin")) { + len += __bin(fn); + i++; + } else { + fprintf(stderr, "Error: cannot understand type '%s'\n", + argv[i]); + return 1; + } + } + + mktail(len); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build/padcat.c Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +void cat(char *fn) +{ + FILE *f; + char buf[80]; + size_t n; + + f = fopen(fn, "rb"); + if (!f) { + fprintf(stderr, "Could not open file \"%s\".\n", + fn); + exit(1); + } + + do { + memset(buf, 0, 80); + n = fread(buf, 1, 80, f); + if (n) + assert(fwrite(buf, 1, 80, stdout) == 80); + } while(n == 80); + + fclose(f); +} + +int main(int argc, char **argv) +{ + int i; + + for(i=1; i<argc; i++) + cat(argv[i]); + + return 0; +}
--- a/cp/Makefile Sat Feb 26 17:58:57 2011 -0500 +++ b/cp/Makefile Wed Apr 20 20:50:32 2011 -0400 @@ -32,13 +32,12 @@ TOP_DIRS=nucleus/ mm/ fs/ drivers/ shell/ .PHONY: all build clean mrproper cleanup tags -.PHONY: ipl/ $(TOP_DIRS) +.PHONY: $(TOP_DIRS) include scripts/Makefile.commands all: build hvf @echo "Image is `stat -c %s hvf` bytes" - @$(MAKE) ipl/ V=$V hvf: $(patsubst %/,%/built-in.o,$(TOP_DIRS)) $(call link-hvf,$^ $(patsubst %,../lib/%.a,$(LIBS)),$@) @@ -53,7 +52,6 @@ @$(MAKE) DIR=drivers/ cleanup V=$V @$(MAKE) DIR=shell/ cleanup V=$V $(call clean,hvf) - $(call clean,loader_*.bin ipl/*.o ipl/*.rto ipl/.*.o ipl/ipl_tape.S ipl/ipl_rdr_ccws.S) $(call clean,shell/directory_structs.c) $(call rclean,doc/commands) @@ -75,48 +73,3 @@ # Include Makefiles from all the top level directories # include $(patsubst %/,%/Makefile,$(TOP_DIRS)) - -# -# IPL specific bits -# - -.PRECIOUS: ipl/%.o - -ipl/: loader_rdr.bin loader_tape.bin - @echo -n - -loader_rdr.bin: ipl/ipl_rdr.rto ipl/ipl_rdr_ccws.rto ipl/setmode.rto ipl/loader_rdr.rto - $(call concat,$^,$@) - $(call pad,$@,80) - @echo "Card reader loader is `stat -c %s $@` bytes" - -loader_tape.bin: ipl/ipl_tape.rto ipl/setmode.rto ipl/loader_tape.rto - $(call concat,$^,$@) - @echo "Tape loader is `stat -c %s $@` bytes" - -ipl/loader_asm.o: ipl/loader_asm.S - $(call s-to-o,$<,$@) - -ipl/ipl_tape.S: ipl/ipl_tape.S_in ipl/setmode.rto ipl/loader_tape.rto scripts/gen_tape_ipl_s.sh - $(call genipl-tape,ipl/ipl_tape.S_in,$@) - -ipl/ipl_rdr_ccws.S: ipl/setmode.rto ipl/loader_rdr.rto - $(call genipl-rdr,$@) - -ipl/loader_%.rto: ipl/loader_%.o - $(call objcopy-tdr,$<,$@) - -ipl/loader_tape.o: ipl/loader.c ipl/loader_asm.o - $(call c-to-o-ipl,ipl/loader.c,ipl/loader_c_tape.o,4096,-DTAPE_SEEK) - $(call link-ipl,ipl/loader_c_tape.o ipl/loader_asm.o,$@) - -ipl/loader_rdr.o: ipl/loader.c ipl/loader_asm.o - $(call c-to-o-ipl,ipl/loader.c,ipl/loader_c_rdr.o,80,) - $(call link-ipl,ipl/loader_c_rdr.o ipl/loader_asm.o,$@) - -ipl/%.rto: ipl/%.o - $(call objcopy-t,$<,$@) - -ipl/%.o: ipl/%.S - $(call s-to-o,$<,$@) -
--- a/cp/include/list.h Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,421 +0,0 @@ -/* - * Based on list.h from Linux Kernel - */ - -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#define LIST_POISON1 ((void*) 0x8585858585858585ULL) -#define LIST_POISON2 ((void*) 0x8686868686868686ULL) - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -#endif
--- a/cp/include/loader.h Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * This file is released under the GPLv2. See the COPYING file for more - * details. - */ - -#ifndef __LOADER_H -#define __LOADER_H - -#define TEMP_BASE ((unsigned char*) 0x400000) /* 4MB */ - -extern unsigned char ORB[32]; - -#define memcpy(d,s,l) __builtin_memcpy((d), (s), (l)) -#define memset(s,c,n) __builtin_memset((s),(c),(n)) - -/* - * It is easier to write this thing in assembly... - */ -extern int __do_io(); -extern void PGMHANDLER(); - -extern void load_nucleus(void); - -#endif
--- a/cp/ipl/ipl_rdr.S Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * This file is released under the GPLv2. See the COPYING file for more - * details. - */ - -# During the system IPL, 24 bytes are read from the device. -# -# NOTE: zArch IPLs in ESA/390 mode. -# - -# -# Bytes 0-7 contain PSW to be loaded after IO operation completes -# - .byte 0x00 - # bits value name desc - # 0 0 <zero> - # 1 0 PER Mask (R) disabled - # 2-4 0 <zero> - # 5 0 DAT Mode (T) disabled - # 6 0 I/O Mask (IO) disabled - # 7 0 External Mask (EX) disabled - - .byte 0x08 - # bits value name desc - # 8-11 0 Key - # 12 1 <one> - # 13 0 Machine-Check Mask (M) disabled - # 14 0 Wait State (W) executing - # 15 0 Problem State (P) supervisor state - - .byte 0x00 - # bits value name desc - # 16-17 0 Address-Space Control (AS) disabled - # 18-19 0 Condition Code (CC) - # 20-23 0 Program Mask exceptions disabled - - .byte 0x00 - # bits value name desc - # 24-30 0 <zero> - # 31 0 Extended Addressing (EA) ! 64 mode - - .byte 0x80 # bits 32-39 - .byte 0x80 # bits 40-47 - .byte 0x00 # bits 48-55 - .byte 0x00 # bits 56-63 - # bits value name desc - # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 - # 33-63 addr Instruction Address Address to exec - -# -# The remaining 16 bytes should contain CCW to read data from device -# - -# CCW format-0: -# bits name -# 0-7 Cmd Code -# 8-31 Data Address -# 32 Chain-Data (CD) -# 33 Chain-Command (CC) -# 34 Sup.-Len.-Inditcation (SLI) -# 35 Skip (SKP) -# 36 Prog.-Contr.-Inter. (PCI) -# 37 Indir.-Data-Addr. (IDA) -# 38 Suspend (S) -# 39 Modified I.D.A. (MIDA) -# 40-47 <ignored> -# 48-63 number of bytes to read - -# -# CCW 1 (bytes 8-15): format-0 -# - # read 80 bytes to 0x18 - .byte 0x02, 0x00, 0x00, 0x18 - .byte 0x60, 0x00, 0x00, 0x50 - -# -# CCW 2 (bytes 16-23): format-0 -# - # read 24 bytes to 0x68 - .byte 0x02, 0x00, 0x00, 0x68 - .byte 0x60, 0x00, 0x00, 0x18 - -# -# Pad to fill up a whole card -# - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 24-31 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 32-39 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 40-47 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 48-55 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 56-63 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 64-71 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 72-79 -
--- a/cp/ipl/ipl_tape.S_in Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -# During the system IPL, 24 bytes are read from the device. -# -# NOTE: zArch IPLs in ESA/390 mode. -# - -# -# Bytes 0-7 contain PSW to be loaded after IO operation completes -# - .byte 0x00 - # bits value name desc - # 0 0 <zero> - # 1 0 PER Mask (R) disabled - # 2-4 0 <zero> - # 5 0 DAT Mode (T) disabled - # 6 0 I/O Mask (IO) disabled - # 7 0 External Mask (EX) disabled - - .byte 0x08 - # bits value name desc - # 8-11 0 Key - # 12 1 <one> - # 13 0 Machine-Check Mask (M) disabled - # 14 0 Wait State (W) executing - # 15 0 Problem State (P) supervisor state - - .byte 0x00 - # bits value name desc - # 16-17 0 Address-Space Control (AS) disabled - # 18-19 0 Condition Code (CC) - # 20-23 0 Program Mask exceptions disabled - - .byte 0x00 - # bits value name desc - # 24-30 0 <zero> - # 31 0 Extended Addressing (EA) ! 64 mode - - .byte 0x80 # bits 32-39 - .byte 0x80 # bits 40-47 - .byte 0x00 # bits 48-55 - .byte 0x00 # bits 56-63 - # bits value name desc - # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 - # 33-63 addr Instruction Address Address to exec - -# -# The remaining 16 bytes should contain CCW to read data from device -# - -# -# The following is a little bit subtle... -# -# CCW 1 loads (( CCW1H << 16 ) + CCW1L ) bytes to 0x800000 (command chain) -# CCW 2 loads (( CCW2H << 16 ) + CCW2L ) bytes to -# 0x800000 + (( CCW1H << 16 ) + CCW1L ) (no command chain) -# - -# -# CCW 1 (bytes 8-15): format-0 -# - .byte 0x27 - # bits value name desc - # 0-7 2 Cmd Code ?, modifiers - - .byte 0x00 - .byte 0x00 - .byte 0x00 - # bits value name desc - # 8-31 addr Data Address dest of the read - - .byte 0x60 - # bits value name desc - # 32 0 Chain-Data (CD) don't chain - # 33 1 Chain-Command (CC) read more - # 34 1 Sup.-Len.-Inditcation (SLI) suppress - # 35 0 Skip (SKP) issue read - # 36 0 Prog.-Contr.-Inter. (PCI) don't interrupt - # 37 0 Indir.-Data-Addr. (IDA) real addr - # 38 0 Suspend (S) don't suspend - # 39 0 Modified I.D.A. (MIDA) real addr - - .byte 0x00 - # bits value name desc - # 40-47 0 <ignored> - - .byte 0x00 - .byte 0x01 - # bits value name desc - # 48-63 len number of bytes to read - -# -# CCW 2 (bytes 16-23): format-0 -# - .byte 0x02 - # bits value name desc - # 0-7 2 Cmd Code read, no modifiers - - .byte 0x7f - .byte 0xff - .byte 0xb0 - # bits value name desc - # 8-31 addr Data Address dest of the read - - .byte 0x20 - # bits value name desc - # 32 0 Chain-Data (CD) don't chain - # 33 0 Chain-Command (CC) don't chain - # 34 1 Sup.-Len.-Inditcation (SLI) suppress - # 35 0 Skip (SKP) issue read - # 36 0 Prog.-Contr.-Inter. (PCI) don't interrupt - # 37 0 Indir.-Data-Addr. (IDA) real addr - # 38 0 Suspend (S) don't suspend - # 39 0 Modified I.D.A. (MIDA) real addr - - .byte 0x00 - # bits value name desc - # 40-47 0 <ignored> - - .byte CCW2H - .byte CCW2L - # bits value name desc - # 48-63 len number of bytes to read - -# -# For whatever reason, it would seem that we need to pad until byte 0x50 = 80 -# - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 24-31 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 32-39 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 40-47 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 48-55 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 56-63 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 64-71 - .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 72-79 -
--- a/cp/ipl/linker.script Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -SECTIONS -{ - ENTRY(load_nucleus) - . = 0x800020; - .text : { *(.text) } - .data : { *(.data) } - .rodata : { *(.rodata) } - .bss : { *(.bss) } -}
--- a/cp/ipl/loader.c Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,352 +0,0 @@ -/* - * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * This file is released under the GPLv2. See the COPYING file for more - * details. - */ - -#ifndef BLOCK_SIZE -#error missing BLOCK_SIZE -#endif - -#include <loader.h> -#include <binfmt_elf.h> - -static unsigned char seek_ccw[8] __attribute__ ((aligned (8))) = { - /* - * CCW1; seek to the right place - */ - - 0x3F, - /* bits value name desc */ - /* 0-7 2 Cmd Code ?, modifiers */ - - 0x00,0x00,0x00, - /* bits value name desc */ - /* 8-31 addr Data Address dest of the read */ - - 0x20, - /* bits value name desc */ - /* 32 0 Chain-Data (CD) don't chain */ - /* 33 0 Chain-Command (CC) don't chain */ - /* 34 1 Sup.-Len.-Inditcation (SLI) suppress */ - /* 35 0 Skip (SKP) issue read */ - /* 36 0 Prog.-Contr.-Inter. (PCI) don't interrupt */ - /* 37 0 Indir.-Data-Addr. (IDA) real addr */ - /* 38 0 Suspend (S) don't suspend */ - /* 39 0 Modified I.D.A. (MIDA) real addr */ - - 0x00, - /* bits value name desc */ - /* 40-47 0 <ignored> */ - - 0x00,0x01, - /* bits value name desc */ - /* 48-63 len number of bytes to read */ -}; - -static unsigned char read_ccw[8] __attribute__ ((aligned (8))) = { - /* - * CCW2; read the entire nucleus ELF - */ - - 0x02, - /* bits value name desc */ - /* 0-7 2 Cmd Code read, no modifiers*/ - - 0xff, 0xff, 0xff, - /* bits value name desc */ - /* 8-31 addr Data Address dest of the read */ - - 0x20, - /* bits value name desc */ - /* 32 0 Chain-Data (CD) don't chain */ - /* 33 0 Chain-Command (CC) don't chain */ - /* 34 1 Sup.-Len.-Inditcation (SLI) suppress */ - /* 35 0 Skip (SKP) issue read */ - /* 36 0 Prog.-Contr.-Inter. (PCI) don't interrupt */ - /* 37 0 Indir.-Data-Addr. (IDA) real addr */ - /* 38 0 Suspend (S) don't suspend */ - /* 39 0 Modified I.D.A. (MIDA) real addr */ - - 0x00, - /* bits value name desc */ - /* 40-47 0 <ignored> */ - - 0xff, 0xff, - /* bits value name desc */ - /* 48-63 len number of bytes to read */ -}; - -unsigned char ORB[32] __attribute__ ((aligned (16))) = { - /* Word 0 */ - 0x12,0x34,0x56,0x78, - /* bits value name desc */ - /* 0-31 magic Interrupt Parameter */ - - /* Word 1 */ - 0x00, - /* bits value name desc */ - /* 0-3 0 Subchannel Key */ - /* 4 0 Suspend Control */ - /* 5 0 Streaming-Mode Control */ - /* 6 0 Modification Control */ - /* 7 0 Synchronization Control */ - - 0x00, - /* bits value name desc */ - /* 8 0 Format Control format-0 CCWs */ - /* 9 0 Prefetch Control */ - /* 10 0 Initial-Status-Interruption Control */ - /* 11 0 Address-Limit-Checking Control */ - /* 12 0 Suppress-Suspended-Interruption Control */ - /* 13 0 <zero> */ - /* 14 0 Format-2-IDAW Control */ - /* 15 0 2K-IDAW Control */ - - 0xff, - /* bits value name desc */ - /* 16-23 0xff Logical-Path Mask All paths */ - - 0x00, - /* bits value name desc */ - /* 24 0 Incorrect-Length-Suppression Mode */ - /* 25 0 Modified-CCW-Indirect-Data-Addressing Control*/ - /* 26-30 0 <zero> */ - /* 31 0 ORB-Extension Control */ - - /* Word 2 */ - 0xff,0xff,0xff,0xff, - /* bits value name desc */ - /* 0-31 addr Channel-Program Address */ - - /* Word 3 */ - 0x00, - /* bits value name desc */ - /* 0-7 0 Channel-Subsystem Priority */ - - 0x00, - /* bits value name desc */ - /* 8-15 0 <zero/reserved> */ - - 0x00, - /* bits value name desc */ - /* 15-23 0 Control-Unit Priority */ - - 0x00, - /* bits value name desc */ - /* 24-31 0 <zero/reserved> */ - - /* Word 4 */ - 0x00,0x00,0x00,0x00, - /* bits value name desc */ - /* 0-31 0 <zero/reserved> */ - - /* Word 5 */ - 0x00,0x00,0x00,0x00, - /* bits value name desc */ - /* 0-31 0 <zero/reserved> */ - - /* Word 6 */ - 0x00,0x00,0x00,0x00, - /* bits value name desc */ - /* 0-31 0 <zero/reserved> */ - - /* Word 7 */ - 0x00,0x00,0x00,0x00, - /* bits value name desc */ - /* 0-31 0 <zero/reserved> */ -}; - -/* - * halt the cpu - * - * NOTE: we don't care about not clobbering registers as when this - * code executes, the CPU will be stopped. - */ -static inline void die(void) -{ - asm volatile( - "SR %r1, %r1 # not used, but should be zero\n" - "SR %r3, %r3 # CPU Address\n" - "SIGP %r1, %r3, 0x05 # Signal, order 0x05\n" - ); - - /* - * Just in case SIGP fails - */ - for(;;); -} - -static u64 pgm_new_psw[2] = { - 0x0000000180000000ULL, (u64) &PGMHANDLER, -}; - -/* - * determine amount of storage - */ -static u64 sense_memsize(void) -{ - u64 size; - int cc; - -#define SKIP_SIZE (1024*1024ULL) - - /* set new PGM psw */ - memcpy((void*)0x1d0, pgm_new_psw, 16); - - for(size = 0; size < ((u64)~SKIP_SIZE)-1; size += SKIP_SIZE) { - asm volatile( - "lg %%r1,%1\n" - "tprot 0(%%r1),0\n" - "ipm %0\n" - "srl %0,28\n" - : /* output */ - "=d" (cc) - : /* input */ - "m" (size) - : /* clobber */ - "cc", "r1" - ); - - /* - * we cheat here a little...if we try to tprot a location - * that isn't part of the configuration, a program exception - * fires off, but our handler sets the CC to 3, and resumes - * execution - */ - if (cc == 3) - break; - } - - /* invalidate new PGM psw */ - memset((void*)0x1d0, 0, 16); - - return size; -} - -/* - * read the entire nucleus into into TEMP_BASE - */ -static inline void readnucleus(void) -{ - register unsigned long base; - - /* - * First, seek past the tape mark - */ - - /* set the CCW address in the ORB */ - *((u32 *) &ORB[8]) = (u32) (u64) seek_ccw; - -#ifdef TAPE_SEEK - /* - * Seek to the next tape mark - */ - if (__do_io()) - die(); -#endif - - /* - * Second, read in BLOCK_SIZE chunks of nucleus - */ - - /* set the CCW address in the ORB */ - *((u32 *) &ORB[8]) = (u32) (u64) read_ccw; - - read_ccw[6] = ((unsigned char) (BLOCK_SIZE >> 8) & 0xff); - read_ccw[7] = ((unsigned char) (BLOCK_SIZE & 0xff)); - - base = (unsigned long) TEMP_BASE; - for(;; base += BLOCK_SIZE) { - read_ccw[1] = ((unsigned char) (base >> 16)); - read_ccw[2] = ((unsigned char) (base >> 8) & 0xff); - read_ccw[3] = ((unsigned char) (base & 0xff)); - if (__do_io()) - break; - } -} - -void load_nucleus(void) -{ - /* - * These are all stored in registers - */ - register u32 iplsch; - register int i; - register Elf64_Ehdr *nucleus_elf; - register Elf64_Shdr *section; - register void (*start_sym)(u64,u32); - - /* Save the IPL device subchannel id */ - iplsch = *((u32*) 0xb8); - - /* - * Read entire ELF to temporary location - */ - readnucleus(); - - nucleus_elf = (Elf64_Ehdr*) TEMP_BASE; - - /* - * Check that this looks like a valid ELF - */ - if (nucleus_elf->e_ident[0] != '\x7f' || - nucleus_elf->e_ident[1] != 'E' || - nucleus_elf->e_ident[2] != 'L' || - nucleus_elf->e_ident[3] != 'F' || - nucleus_elf->e_ident[EI_CLASS] != ELFCLASS64 || - nucleus_elf->e_ident[EI_DATA] != ELFDATA2MSB || - nucleus_elf->e_ident[EI_VERSION] != EV_CURRENT || - nucleus_elf->e_type != ET_EXEC || - nucleus_elf->e_machine != 0x16 || // FIXME: find the name for the #define - nucleus_elf->e_version != EV_CURRENT) - die(); - - /* - * Iterate through each section, and copy it to the final - * destination as necessary - */ - for (i=0; i<nucleus_elf->e_shnum; i++) { - section = (Elf64_Shdr*) (TEMP_BASE + - nucleus_elf->e_shoff + - nucleus_elf->e_shentsize * i); - - switch (section->sh_type) { - case SHT_PROGBITS: - if (!section->sh_addr) - break; - - /* - * just copy the data from TEMP_BASE to - * where it wants to be - */ - memcpy((void*) section->sh_addr, - TEMP_BASE + section->sh_offset, - section->sh_size); - break; - case SHT_NOBITS: - /* - * No action needed as there's no data to - * copy, and we assume that the ELF sections - * don't overlap - */ - memset((void*) section->sh_addr, - 0, section->sh_size); - break; - case SHT_SYMTAB: - case SHT_STRTAB: - /* TODO: relocate */ - break; - default: - /* Ignoring */ - break; - } - } - - /* - * Now, jump to the nucleus entry point - */ - start_sym = (void*) nucleus_elf->e_entry; - start_sym(sense_memsize(), iplsch); -}
--- a/cp/ipl/loader_asm.S Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,252 +0,0 @@ -/* - * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * This file is released under the GPLv2. See the COPYING file for more - * details. - */ - -#include <loader.h> - -.text - .align 4 -.globl __do_io - .type __do_io, @function -__do_io: - # - # r4 = 0x80000000 - # - XGR %r4, %r4 - LHI %r4, 0x8 - SLL %r4, 20 - # - # r14 = r14 & 0x7fffffff don't ask, it's strangely retarded - # - L %r1,ADDRMASK(%r4) - NR %r14, %r1 # mask out the bit - - # set up the interrupt handler - MVC 0x1f0(16),IOPSW(%r4) # SET NEW IO PSW - LA %r1,IOHANDLER(%r4) # GET HANDLER ADDRESS - STG %r1,0x1f0+8 # SAVE IN NEW PSW - - L %r1, 0xb8 # load subsystem ID - - SSCH ORB(%r4) # issue IO - - # Load Control Register 6 with I/O interrupt subclass mask - STCTG 6,6,TMPVAR(%r4) # GET CR6 - OI TMPVAR+4(%r4),0xFF # enable all - LCTLG 6,6,TMPVAR(%r4) # RELOAD MODIFIED CR6 - -/* -7) Enable the PSW for I/O interrupts and go into wait state (you need bits 6, 12 & 14 set to 1 in the PSW : X'020A000000000000' is a good example) -*/ - LPSWE WAITPSW(%r4) - -# -# The IO interrupt handler -# -.globl IOHANDLER -IOHANDLER: - # is this for us? - L %r1, MAGICVAL(%r4) - C %r1, 0xbc - BNE IONOTDONE(%r4) - - # it is! - - L %r1, 0xb8 # load subsystem ID - - TSCH IRB(%r4) - -/* -FIXME: we should do more checking! - -11) If Unit check or Channel Status|=0 : An I/O error occurred and act accordingly -12) If unit exception : End of media (for tape & cards) and act accordingly -13) If device end : I/O Completed.. Perform post I/O stuff (like advancing your pointers) and back to step 3 -*/ - - # unit check? (end of media?) - L %r1,IRB+5(%r4) - LA %r0,0x02 - NR %r0,%r1 - LA %r2,1 # return 1 - end of medium - BCR 4,%r14 # unit chk => return - - # check the SCSW.. If CE Only : LPSW Old I/O PSW - LA %r0,0x04 - NR %r0,%r1 - LA %r2,0 # means IO done - BCR 4,%r14 # device end => return - -IONOTDONE: - LPSWE 0x170 - -# -# The PGM interrupt handler -# -.globl PGMHANDLER -PGMHANDLER: - STMG %r1,%r3,0x200 - - # r3 = 0x80000000 - XGR %r3, %r3 - LHI %r3, 0x8 - SLL %r3, 20 - - # is ILC == 3? - LGH %r2,0x8C - CGHI %r2,0x0006 - BNE ERR - - # grab the old PSW address, subtract length of TPROT, and compare it - # with the TPROT opcode (0xe501) - LG %r1,0x158 - AGHI %r1,-6 - LLGH %r2,TPROTOP(%r3) - LLGH %r1,0(%r1) - CGR %r2,%r1 - BNE ERR(%r3) - - # set CC=3 - OI 0x152,0x30 - - LMG %r1,%r3,0x200 - - LPSWE 0x150 - -ERR: -.byte 0x00, 0x00 - - -# -# Useful data -# -.data -.globl TPROTOP -TPROTOP: -.byte 0xe5, 0x01 - - .align 8 -.globl IOPSW -IOPSW: - .byte 0x00 - # bits value name desc - # 0 0 <zero> - # 1 0 PER Mask (R) disabled - # 2-4 0 <zero> - # 5 0 DAT Mode (T) disabled - # 6 0 I/O Mask (IO) enabled - # 7 0 External Mask (EX) disabled - - .byte 0x00 - # bits value name desc - # 8-11 0 Key - # 12 0 <one> - # 13 0 Machine-Check Mask (M) disabled - # 14 0 Wait State (W) executing - # 15 0 Problem State (P) supervisor state - - .byte 0x00 - # bits value name desc - # 16-17 0 Address-Space Control (AS) disabled - # 18-19 0 Condition Code (CC) - # 20-23 0 Program Mask exceptions disabled - - .byte 0x01 - # bits value name desc - # 24-30 0 <zero> - # 31 1 Extended Addressing (EA) EA + BA = 64 mode - - .byte 0x80 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - # bits value name desc - # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 - # 33-63 0 <zero> - # 64-127 addr Instruction Address Address to exec - -.globl WAITPSW -WAITPSW: - .byte 0x02 - # bits value name desc - # 0 0 <zero> - # 1 0 PER Mask (R) disabled - # 2-4 0 <zero> - # 5 0 DAT Mode (T) disabled - # 6 1 I/O Mask (IO) enabled - # 7 0 External Mask (EX) disabled - - .byte 0x02 - # bits value name desc - # 8-11 0 Key - # 12 0 <zero> - # 13 0 Machine-Check Mask (M) disabled - # 14 1 Wait State (W) not executing - # 15 0 Problem State (P) supervisor state - - .byte 0x00 - # bits value name desc - # 16-17 0 Address-Space Control (AS) disabled - # 18-19 0 Condition Code (CC) - # 20-23 0 Program Mask exceptions disabled - - .byte 0x01 - # bits value name desc - # 24-30 0 <zero> - # 31 1 Extended Addressing (EA) EA + BA = 64 mode - - .byte 0x80 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - .byte 0x00 - # bits value name desc - # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 - # 33-63 0 <zero> - # 64-127 addr Instruction Address Address to exec - -.globl TMPVAR -TMPVAR: - .8byte 0x0 - -.globl ADDRMASK -ADDRMASK: - .4byte 0x7fffffff - -.globl MAGICVAL -MAGICVAL: - .4byte 0x12345678 - -.globl IRB -IRB: - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 - .8byte 0x00 -
--- a/cp/ipl/setmode.S Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * This file is released under the GPLv2. See the COPYING file for more - * details. - */ - -# -# At this point, the machine is running in ESA390 mode. Let's load a new -# PSW, making it switch to 64-bit mode -# - - # switch to 64-bit mode - # - # Signal Processor - # Order 0x12: Set Architecture - # R1 bits 56-63 = 0x01 (switch all CPUs to z/Arch) - SR %r1, %r1 - LHI %r1, 0x1 # switch all to z/Arch - SR %r3, %r3 # CPU Address (CPU0000) - SIGP %r1, %r3, 0x12 # Signal, order 0x12 - SAM64 - # On error: - # Bit 55 = 1, cc1 (inval param) - # Bit 54 = 1, cc1 (incorrect state) - - # FIXME: check for errors? - -# -# At this point, we should be in 64-bit mode -# - - # - # It is unfortunate that the below code is required. - # - # Let's set the stack pointer to make gcc happy - # - # A standard stack frame is 160 bytes. - # - # NOTE: Once this thread of execution turns into the idle thread, - # the stack can be reused for something else. Since it's allocated - # in the 128th processor's PSA, we have to make sure that it won't - # get initialized until after the idle thread kicks in. - # - - # r15 = 0x100000 - # = (1 << 20) - # - SR %r15, %r15 - LHI %r15, 0x1 - SLL %r15, 20 - AHI %r15, -160 - -# -# Padding to make the entire file 0x20 bytes -# - BCR 0, %r7 - BCR 0, %r7
--- a/cp/mm/buddy.c Sat Feb 26 17:58:57 2011 -0500 +++ b/cp/mm/buddy.c Wed Apr 20 20:50:32 2011 -0400 @@ -29,7 +29,7 @@ INIT_LIST_HEAD(&orders[order]); if (pages & (1 << order)) { - p = addr_to_page(base); + p = addr_to_page((void*) base); list_add(&p->buddy, &orders[order]);
--- a/cp/scripts/Makefile.commands Sat Feb 26 17:58:57 2011 -0500 +++ b/cp/scripts/Makefile.commands Wed Apr 20 20:50:32 2011 -0400 @@ -7,13 +7,12 @@ # cmd-c-to-o=$(CC) $(CFLAGS) $(NUCLEUSCFLAGS) -c -o $(2) $(1) cmd-c-to-s=$(CC) $(CFLAGS) $(NUCLEUSCFLAGS) -S -o $(2) $(1) -cmd-c-to-o-ipl=$(CC) $(CFLAGS) -DBLOCK_SIZE=$(3) $(4) -c -o $(2) $(1) cmd-s-to-o=$(AS) -m64 -o $(2) $(1) cmd-o-to-builtin=$(LD) $(LDFLAGS) -r -o $(2) $(1) cmd-link-hvf=$(LD) $(LDFLAGS) -T scripts/linker.script -o $(2) $(1) -cmd-link-ipl=$(LD) -melf64_s390 -T ipl/linker.script -o $(2) $(1) +cmd-link-ipl=$(LD) -melf64_s390 -T linker.script -o $(2) $(1) cmd-objcopy-t=$(OBJCOPY) -O binary -j .text $(1) $(2) -cmd-objcopy-tdr=$(OBJCOPY) -O binary -j .text -j .data -j .rodata $(1) $(2) +cmd-objcopy-tdr=$(OBJCOPY) -O binary -j .text -j .data -j .rodata -j .rodata.str1.2 $(1) $(2) cmd-genipl-rdr=bash scripts/gen_rdr_ccws.sh $(1) cmd-genipl-tape=bash scripts/gen_tape_ipl_s.sh $(1) $(2) cmd-concat=cat $(1) > $(2)
--- a/cp/scripts/gen_rdr_ccws.sh Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2008 Josef 'Jeff' Sipek -# - -len=`stat -c %s ipl/setmode.rto` -len=`expr $len + $(stat -c %s ipl/loader_rdr.rto)` -dif=`expr $len % 80` - -if [ $dif -ne 0 ]; then - len=`expr $len - $dif` - len=`expr $len + 80` -fi - -len=`expr $len \/ 80` - -# 13 CCWs * 80 bytes/ccw = 1040 bytes -if [ $len -gt 13 ]; then - echo "ERROR: loader code is too long" >&2 - exit 1 -fi - -echo -n "" > "$1" - -addr=8388608 # == 0x800000 -flags="0x60" -for x in `seq 1 $len`; do - high_addr=`expr $addr \/ 65536` - mid_addr=`expr $(expr $addr \/ 256) % 256` - low_addr=`expr $addr % 256` - - [ $x -eq $len ] && flags="0x20" - - echo "# CCW $x" >> "$1" - echo " .byte 0x02, $high_addr, $mid_addr, $low_addr" >> "$1" - echo " .byte $flags, 0x00, 0x00, 0x50" >> "$1" - echo "" >> "$1" - - addr=`expr $addr + 80` -done - -echo "# pad" >> "$1" -for x in `seq $len 19`; do - echo " .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40" >> "$1" -done
--- a/cp/scripts/gen_tape_ipl_s.sh Sat Feb 26 17:58:57 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2007 Josef 'Jeff' Sipek -# - -len=80 # this is going the be the size of ipl.rto -len=$(expr $len + `stat -c %s ipl/setmode.rto`) -len=$(expr $len + `stat -c %s ipl/loader_tape.rto`) -dif=`expr $len % 80` - -if [ $dif -ne 0 ]; then - len=`expr $len - $dif` - len=`expr $len + 80` -fi - -if [ $len -gt `expr 65536` ]; then - echo "ERROR: loader code is too long" >&2 - exit 1 -fi - -ccw2=$len - -ccw2h=`expr $ccw2 / 256` -ccw2l=`expr $ccw2 % 256` - -sed -e "s/CCW2H/$ccw2h/g" \ - -e "s/CCW2L/$ccw2l/g" \ - "$1" > "$2"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/installed_files.txt Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,17 @@ +HVF installer creates the following files: + +This file (listing everything installed): + HVF TEXT + +The directory: + HVF DIRECT + +The system configuration file: + SYSTEM CONFIG + +The nucleus: + HVF ELF + +The nucleus loader: + DASDLOAD BIN + ECKDLOAD BIN
--- a/hercules/hvf.cnf Sat Feb 26 17:58:57 2011 -0500 +++ b/hercules/hvf.cnf Wed Apr 20 20:50:32 2011 -0400 @@ -31,7 +31,7 @@ #--- ---- -------------------- # Card Reader -000C 3505 ../cp/loader_rdr.bin ../cp/hvf ebcdic multifile intrq +000C 3505 ../installer.bin ebcdic autopad eof # Card Punch 000D 3525 punch00d.txt ascii
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/list.h Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,421 @@ +/* + * Based on list.h from Linux Kernel + */ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#define LIST_POISON1 ((void*) 0x8585858585858585ULL) +#define LIST_POISON2 ((void*) 0x8686868686868686ULL) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +#endif
--- a/include/string.h Sat Feb 26 17:58:57 2011 -0500 +++ b/include/string.h Wed Apr 20 20:50:32 2011 -0400 @@ -8,12 +8,15 @@ #ifndef __STRING_H #define __STRING_H +#include <vsprintf.h> + #define memset(d,s,l) __builtin_memset((d),(s),(l)) #define memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) +extern void *memmove(void *dest, const void *src, size_t count); #define memcmp(d,s,l) __builtin_memcmp((d),(s),(l)) extern size_t strnlen(const char *s, size_t count); extern int strcmp(const char *cs, const char *ct); -#define strncmp(a,b,l) __builtin_strncmp((a),(b),(l)) +extern int strncmp(const char *cs, const char *ct, int len); extern int strcasecmp(const char *s1, const char *s2); extern char *strncpy(char *dest, const char *src, size_t count);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/.gitignore Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,6 @@ +*.o +*.rto + +rdr.S + +archive.cpio
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/Makefile Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,33 @@ +AS=$(CROSS_COMPILE)as +OBJCOPY=$(CROSS_COMPILE)objcopy +CC=$(CROSS_COMPILE)gcc +LD=$(CROSS_COMPILE)ld +CFLAGS=-g -fno-strict-aliasing -fno-builtin -nostdlib -Wall -m64 -I ../include/ -O2 -include ../include/types.h +NUCLEUSCFLAGS= +LIBS=string ebcdic + +include ../cp/scripts/Makefile.commands + +all: rdr.rto loader.rto + +clean: + rm -f *.o + rm -f *.rto + rm -f rdr.S + +loader.o: setmode.o loader_c.o loader_asm.o cpio.o malloc.o edf.o + $(call link-ipl,$^ $(patsubst %,../lib/%.a,$(LIBS)),$@) + +rdr.S: loader.rto + ../build/ccw_gen 00080000 80100000 `stat -c %s $<` 100000 080000 > $@ + +%.o: %.c + $(call c-to-o,$<,$@) + +%.rto: %.o + $(call objcopy-tdr,$<,$@) + +%.o: %.S + $(call s-to-o,$<,$@) + +.PRECIOUS: %.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/cpio.c Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2011 Josef 'Jeff' Sipek + */ +#include "loader.h" +#include <string.h> +#include <ebcdic.h> + +struct cpio_hdr { + u8 magic[6]; + u8 dev[6]; + u8 ino[6]; + u8 mode[6]; + u8 uid[6]; + u8 gid[6]; + u8 nlink[6]; + u8 rdev[6]; + u8 mtime[11]; + u8 namesize[6]; + u8 filesize[11]; + u8 data[0]; +}; + +struct table { + char *arch; + char fn[8]; + char ft[8]; + int lrecl; + int text; + u32 lba; /* 0 means undef */ +}; + +static struct table table[] = { + {"hvf.directory", "HVF ", "DIRECT ", 80, 1, 0}, + {"hvf.config", "SYSTEM ", "CONFIG ", 80, 1, 0}, +// {"hvf", "HVF ", "ELF ", 4096, 0, 0}, + {"eckd.rto", "ECKDLOAD", "BIN ", 4096, 0, 1}, + {"loader.rto", "DASDLOAD", "BIN ", 4096, 0, 2}, + {"installed_files.txt", "HVF ", "TEXT ", 80, 1, 0}, + {"", "" , "" , -1, -1, 0}, +}; + +static void save_file(struct table *te, int filesize, u8 *buf) +{ + char pbuf[100]; + struct FST fst; + int ret; + int rec; + + ret = find_file(te->fn, te->ft, &fst); + if (!ret) { + wto("File '"); + wto(te->fn); + wto("' already exists on the device.\n"); + wto("The device has been left unmodified.\n"); + die(); + } + + ret = create_file(te->fn, te->ft, te->lrecl, &fst); + if (ret) { + wto("Could not create file '"); + wto(te->fn); + wto("'.\n"); + die(); + } + + if (te->text) + ascii2ebcdic(buf, filesize); + + if (te->lba) { + if (filesize > te->lrecl) + die(); + snprintf(pbuf, 100, "special file, writing copy of data to LBA %d\n", + te->lba); + wto(pbuf); + write_blk(buf, te->lba); + } + + for(rec=0; rec<(filesize/te->lrecl); rec++) { + snprintf(pbuf, 100, "rec %03x at %p\n", rec, + buf + (rec * te->lrecl)); + wto(pbuf); + append_record(&fst, buf + (rec * te->lrecl)); + } + + if (filesize % te->lrecl) { + u8 buf2[te->lrecl]; + + memset(buf2, 0, te->lrecl); + memcpy(buf2, buf + (rec * te->lrecl), filesize % te->lrecl); + + snprintf(pbuf, 100, "rec %03x at %p\n", rec, + buf + (rec * te->lrecl)); + wto(pbuf); + append_record(&fst, buf2); + } +} + +static u32 getnumber(u8 *data, int digits) +{ + u32 ret = 0; + + for(;digits; digits--, data++) + ret = (ret * 8) + (*data - '0'); + + return ret; +} + +static void readcard(u8 *buf) +{ + static int eof; + int ret; + struct ccw ccw; + + if (eof) + return; + + ccw.cmd = 0x02; + ccw.flags = 0; + ccw.count = 80; + ccw.addr = ADDR31(buf); + + ORB.param = 0x12345678, + ORB.f = 1, + ORB.lpm = 0xff, + ORB.addr = ADDR31(&ccw); + + ret = __do_io(ipl_sch); + if (ret == 0x01) { + eof = 1; + return; // end of media + } + + if (ret) + die(); +} + +void unload_archive(void) +{ + char printbuf[132]; + struct cpio_hdr *hdr; + u8 *dasd_buf; + int save; + int fill; + int i; + + u32 filesize; + u32 namesize; + + dasd_buf = malloc(2*1024*1024); + hdr = (void*) dasd_buf; + + wto("\n"); + + fill = 0; + while(1) { + /* read a file header */ + if (fill < sizeof(struct cpio_hdr)) { + readcard(dasd_buf + fill); + fill += 80; + } + + namesize = getnumber(hdr->namesize, 6); + filesize = getnumber(hdr->filesize, 11); + + while(namesize + sizeof(struct cpio_hdr) > fill) { + readcard(dasd_buf + fill); + fill += 80; + } + + if ((namesize == 11) && + !strncmp("TRAILER!!!", (char*) hdr->data, 10)) + break; + + save = 0; + for(i=0; table[i].lrecl != -1; i++) { + if (!strcmp((char*) hdr->data, table[i].arch)) { + save = 1; + break; + } + } + + if (save) { + snprintf(printbuf, 132, "processing '%.8s' '%.8s' => '%s'\n", + table[i].fn, table[i].fn + 8, (char*) hdr->data); + wto(printbuf); + } else { + snprintf(printbuf, 132, "skipping '%s'\n", + (char*) hdr->data); + wto(printbuf); + } + + fill -= (sizeof(struct cpio_hdr) + namesize); + memmove(hdr, hdr->data + namesize, fill); + + /* read the entire file into storage (assuming it's <= 1MB) */ + while(fill < filesize) { + readcard(dasd_buf + fill); + fill += 80; + } + + if (save) + save_file(&table[i], filesize, dasd_buf); + + fill -= filesize; + memmove(dasd_buf, dasd_buf + filesize, fill); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/edf.c Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2011 Josef 'Jeff' Sipek + */ +#include "loader.h" +#include <string.h> +#include <ebcdic.h> +#include <list.h> + +union adt_u { + struct ADT adt; + char buf[4096]; +}; + +struct block_map { + struct list_head list; + + /* key */ + u8 fn[8]; /* EBCDIC */ + u8 ft[8]; /* EBCDIC */ + u8 level; /* 0 = data */ + u32 blk_no; + + /* value */ + u32 lba; + void *buf; + + /* dirty list */ + int dirty; +}; + +static union adt_u *adt; +static struct FST *directory; +static struct FST *allocmap; + +static LIST_HEAD(block_map); + +/* borrowed from Linux */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* borrowed from Linux */ +#define offsetof(type, member) __builtin_offsetof(type,member) + +#define DIRECTOR_FN ((u8*) "\x00\x00\x00\x01\x00\x00\x00\x00") +#define DIRECTOR_FT ((u8*) "\xc4\xc9\xd9\xc5\xc3\xe3\xd6\xd9") +#define ALLOCMAP_FN ((u8*) "\x00\x00\x00\x02\x00\x00\x00\x00") +#define ALLOCMAP_FT ((u8*) "\xc1\xd3\xd3\xd6\xc3\xd4\xc1\xd7") + +static struct block_map *block_map_find(u8 *fn, u8 *ft, u8 level, u32 blk_no) +{ + struct block_map *cur; + + list_for_each_entry(cur, &block_map, list) { + if (!memcmp(fn, cur->fn, 8) && + !memcmp(ft, cur->ft, 8) && + (level == cur->level) && + (blk_no == cur->blk_no)) + return cur; + } + + return NULL; +} + +static void block_map_add(u8 *fn, u8 *ft, u8 level, u32 blk_no, u32 lba) +{ + struct block_map *map; + + map = block_map_find(fn, ft, level, blk_no); + if (map) { + if (map->lba != lba) + die(); + + return; + } + + map = malloc(sizeof(struct block_map)); + if (!map) + die(); + + memcpy(map->fn, fn, 8); + memcpy(map->ft, ft, 8); + map->level = level; + map->blk_no = blk_no; + + map->lba = lba; + map->buf = NULL; + map->dirty = 0; + + list_add(&map->list, &block_map); +} + +static void *read_file_blk(u8 *fn, u8 *ft, u8 level, u32 blk) +{ + struct block_map *map; + + map = block_map_find(fn, ft, level, blk); + if (!map) { + char buf[128]; + snprintf(buf,128,"%s could not find block %d at level %d\n", + __func__, blk, level); + wto(buf); + die(); + } + + if (map->buf) + return map->buf; + + map->buf = malloc(adt->adt.DBSIZ); + if (!map->buf) + die(); + + read_blk(map->buf, map->lba); + + return map->buf; +} + +static void blk_set_dirty(u8 *fn, u8 *ft, u8 level, u32 blk) +{ + struct block_map *map; + + map = block_map_find(fn, ft, level, blk); + if (!map || !map->buf) + die(); + + map->dirty = 1; +} + +void writeback_buffers() +{ + struct block_map *cur; + char buf[100]; + + list_for_each_entry(cur, &block_map, list) { + if (!cur->dirty) + continue; + + if (!cur->buf) + die(); + + snprintf(buf, 100, "wb: %10d %p\n", cur->lba, cur->buf); + wto(buf); + write_blk(cur->buf, cur->lba); + } +} + +/* + * fills in *fst with existing file info and returns 0, or if file doesn't + * exist, returns -1 + */ +int find_file(char *fn, char *ft, struct FST *fst) +{ + struct FST *FST; + u8 FN[8]; + u8 FT[8]; + int rec; + int blk; + + memcpy(FN, fn, 8); + memcpy(FT, ft, 8); + ascii2ebcdic(FN, 8); + ascii2ebcdic(FT, 8); + + for(blk=0; blk<directory->ADBC; blk++) { + FST = read_file_blk(DIRECTOR_FN, DIRECTOR_FT, 0, blk); + + for(rec=0; rec<adt->adt.NFST; rec++) { + if ((!memcmp(FST[rec].FNAME, FN, 8)) && + (!memcmp(FST[rec].FTYPE, FT, 8))) { + memcpy(fst, &FST[rec], sizeof(struct FST)); + return 0; + } + } + } + + return -1; +} + +static void update_directory(struct FST *fst) +{ + struct FST *FST; + int rec; + int blk; + + for(blk=0; blk<directory->ADBC; blk++) { + FST = read_file_blk(DIRECTOR_FN, DIRECTOR_FT, 0, blk); + + for(rec=0; rec<adt->adt.NFST; rec++) { + if ((!memcmp(FST[rec].FNAME, fst->FNAME, 8)) && + (!memcmp(FST[rec].FTYPE, fst->FTYPE, 8))) { + memcpy(&FST[rec], fst, sizeof(struct FST)); + blk_set_dirty(DIRECTOR_FN, DIRECTOR_FT, 0, blk); + return; + } + } + } + + die(); +} + +static int file_blocks_at_level(u32 ADBC, int level) +{ + const u32 ptrs_per_block = adt->adt.DBSIZ / 4; + int blks; + int i; + + blks = 1; + for(i=0; i<level; i++) + blks *= ptrs_per_block; + blks = (ADBC + blks - 1) / blks; + + return blks; +} + +static void __read_file(struct FST *fst) +{ + const u32 ptrs_per_block = adt->adt.DBSIZ / fst->PTRSZ; + u32 *blk_ptrs; + int level; + + int blocks; + int i,j; + + if (!fst->NLVL) { + block_map_add(fst->FNAME, fst->FTYPE, 0, 0, fst->FOP); + return; + } + + /* there are pointer blocks, let's read them in and then + * follow each pointer + */ + + block_map_add(fst->FNAME, fst->FTYPE, fst->NLVL, 0, fst->FOP); + + /* for each level of pointers... */ + for(level=fst->NLVL; level>0; level--) { + blocks = file_blocks_at_level(fst->ADBC, level); + + if (level == fst->NLVL && blocks != 1) + die(); + + /* read in each block */ + for(i=0; i<blocks; i++) { + blk_ptrs = read_file_blk(fst->FNAME, + fst->FTYPE, + level, + i); + + /* and add each pointer to the next level */ + for(j=0; j<ptrs_per_block; j++) { + block_map_add(fst->FNAME, + fst->FTYPE, + level-1, + (i*ptrs_per_block) + j, + blk_ptrs[j]); + } + } + } +} + +int create_file(char *fn, char *ft, int lrecl, struct FST *fst) +{ + /* first, fill in the FST */ + memset(fst, 0, sizeof(struct FST)); + + memcpy(fst->FNAME, fn, 8); + memcpy(fst->FTYPE, ft, 8); + + ascii2ebcdic(fst->FNAME, 8); + ascii2ebcdic(fst->FTYPE, 8); + + fst->FMODE[0] = '\xc1'; // EBCDIC 'A' + fst->FMODE[1] = '\xf1'; // EBCDIC '1' + fst->RECFM = FSTDFIX; // fixed record size + fst->LRECL = lrecl; + fst->PTRSZ = 4; + + append_record(directory, (u8*) fst); + + return 0; +} + +static u32 __get_free_block() +{ + u32 blk; + u8 *buf; + u32 i; + u32 bit; + + for(blk=0; blk<allocmap->ADBC; blk++) { + buf = read_file_blk(allocmap->FNAME, allocmap->FTYPE, 0, blk); + + for(i=0; i<adt->adt.DBSIZ; i++) { + if (buf[i] == 0xff) + continue; + + if ((buf[i] & 0x80) == 0) { bit = 0; goto found; } + if ((buf[i] & 0x40) == 0) { bit = 1; goto found; } + if ((buf[i] & 0x20) == 0) { bit = 2; goto found; } + if ((buf[i] & 0x10) == 0) { bit = 3; goto found; } + if ((buf[i] & 0x08) == 0) { bit = 4; goto found; } + if ((buf[i] & 0x04) == 0) { bit = 5; goto found; } + if ((buf[i] & 0x02) == 0) { bit = 6; goto found; } + if ((buf[i] & 0x01) == 0) { bit = 7; goto found; } + + continue; /* this is not necessary since we check + for 0xff right away, but GCC really + likes to complain about possibly + uninitialized use of 'bit' */ + +found: + buf[i] |= (0x80 >> bit); + + blk_set_dirty(allocmap->FNAME, allocmap->FTYPE, 0, blk); + + return ((blk * adt->adt.DBSIZ * 8) + (i * 8) + bit) + 1; + } + } + + die(); + return 0; +} + +static void __append_block(struct FST *fst) +{ + struct block_map *map; + u32 *buf; + u32 lba, prevlba; + u32 blk; + u8 lvl; + + /* no data blocks yet */ + if (!fst->ADBC) { + fst->ADBC = 1; + fst->NLVL = 0; + fst->FOP = __get_free_block(); + + block_map_add(fst->FNAME, fst->FTYPE, 0, 0, fst->FOP); + return; + } + + for(lvl=0; lvl<=fst->NLVL; lvl++, prevlba=lba) { + blk = file_blocks_at_level(fst->ADBC+1, lvl); + + map = block_map_find(fst->FNAME, fst->FTYPE, lvl, blk-1); + if (map) { + int x; + + if (!lvl) + die(); + + buf = read_file_blk(fst->FNAME, fst->FTYPE, lvl, + blk-1); + blk_set_dirty(fst->FNAME, fst->FTYPE, lvl, blk-1); + + x = file_blocks_at_level(fst->ADBC+1, lvl-1) % + (adt->adt.DBSIZ / 4); + buf[x-1] = prevlba; + + fst->ADBC++; + return; + } + + lba = __get_free_block(); + + block_map_add(fst->FNAME, fst->FTYPE, lvl, blk-1, lba); + + if (!lvl) + continue; + + buf = read_file_blk(fst->FNAME, fst->FTYPE, lvl, blk-1); + blk_set_dirty(fst->FNAME, fst->FTYPE, lvl, blk-1); + + *buf = prevlba; + } + + lba = __get_free_block(); + block_map_add(fst->FNAME, fst->FTYPE, fst->NLVL+1, 0, lba); + + buf = read_file_blk(fst->FNAME, fst->FTYPE, fst->NLVL+1, 0); + blk_set_dirty(fst->FNAME, fst->FTYPE, fst->NLVL+1, 0); + + buf[0] = fst->FOP; + buf[1] = prevlba; + + fst->FOP = lba; + + fst->NLVL++; + fst->ADBC++; +} + +void append_record(struct FST *fst, u8 *buf) +{ + u32 foff; + u32 blk; + u32 off; + u32 rem; + + u8 *dbuf; + + if (fst->RECFM != FSTDFIX) + die(); + + foff = fst->AIC * fst->LRECL; + + blk = foff / adt->adt.DBSIZ; + off = foff % adt->adt.DBSIZ; + rem = (fst->ADBC * adt->adt.DBSIZ) - foff; + + /* need to add another block */ + if (rem < fst->LRECL) + __append_block(fst); + + dbuf = read_file_blk(fst->FNAME, fst->FTYPE, 0, blk); + + if (!rem || (rem >= fst->LRECL)) { + memcpy(dbuf + off, buf, fst->LRECL); + blk_set_dirty(fst->FNAME, fst->FTYPE, 0, blk); + } else { + memcpy(dbuf + off, buf, rem); + blk_set_dirty(fst->FNAME, fst->FTYPE, 0, blk); + + dbuf = read_file_blk(fst->FNAME, fst->FTYPE, 0, blk+1); + memcpy(dbuf, buf + rem, fst->LRECL - rem); + blk_set_dirty(fst->FNAME, fst->FTYPE, 0, blk+1); + } + + fst->AIC++; + + update_directory(fst); +} + +void mount_fs() +{ + struct FST *fst; + + adt = malloc(sizeof(union adt_u)); + + read_blk(adt, EDF_LABEL_BLOCK_NO); + + if ((adt->adt.IDENT != __ADTIDENT) || + (adt->adt.DBSIZ != EDF_SUPPORTED_BLOCK_SIZE) || + (adt->adt.OFFST != 0) || + (adt->adt.FSTSZ != sizeof(struct FST))) + die(); + + block_map_add(DIRECTOR_FN, DIRECTOR_FT, 0, 0, adt->adt.DOP); + + fst = read_file_blk(DIRECTOR_FN, DIRECTOR_FT, 0, 0); + + if (memcmp(fst[0].FNAME, DIRECTOR_FN, 8) || + memcmp(fst[0].FTYPE, DIRECTOR_FT, 8) || + (fst[0].RECFM != FSTDFIX) || + memcmp(fst[1].FNAME, ALLOCMAP_FN, 8) || + memcmp(fst[1].FTYPE, ALLOCMAP_FT, 8) || + (fst[1].RECFM != FSTDFIX)) + die(); + + directory = fst; + allocmap = fst+1; + + __read_file(&fst[0]); /* the directory */ + __read_file(&fst[1]); /* the alloc map */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/layout.txt Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,8 @@ +dasd layout: + +0,0,1 eckd.S +0,0,2 setmode.S + loader.c + loader_asm.S + +<on fs> hvf.elf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/linker.script Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,10 @@ +SECTIONS +{ + ENTRY(MAIN) + . = 0x100000; + .text : { *(.text) } + .data : { *(.data) } + .rodata : { *(.rodata) } + .rodata.str1.2 : { *(.rodata.str1.2) } + .bss : { *(.bss) } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/loader.h Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,340 @@ +#ifndef __LOADER_H +#define __LOADER_H + +#include <errno.h> + +/* + * "Config" values + */ +#define TEMP_BASE ((unsigned char*) 0x200000) /* 2MB */ + +#define CON_DEVNUM 0x0009 + +/* 3390 with 0 key length, and 4096 data length */ +#define RECORDS_PER_CYL (15*12) +#define RECORDS_PER_TRACK 12 + +/* the nucleus fn ft (in EBCDIC) => HVF ELF */ +#define CP_FN "\xC8\xE5\xC6\x40\x40\x40\x40\x40" +#define CP_FT "\xC5\xD3\xC6\x40\x40\x40\x40\x40" + +static inline int strlen(char *p) +{ + int i; + + for(i=0;*p; p++, i++) + ; + + return i; +} + +/* + * halt the cpu + * + * NOTE: we don't care about not clobbering registers as when this + * code executes, the CPU will be stopped. + */ +static inline void die(void) +{ + asm volatile( + "SR %r1, %r1 # not used, but should be zero\n" + "SR %r3, %r3 # CPU Address\n" + "SIGP %r1, %r3, 0x05 # Signal, order 0x05\n" + ); + + /* + * Just in case SIGP fails + */ + for(;;); +} + +/* + * I/O related structs, macros & variables + */ +struct ccw { + u8 cmd; /* Command code */ + u8 flags; /* Flags */ + u16 count; /* Count */ + u32 addr; /* Data Address */ +} __attribute__((packed,aligned(8))); + +#define CCW_FLAG_CD 0x80 /* Chain-Data */ +#define CCW_FLAG_CC 0x40 /* Chain-Command */ +#define CCW_FLAG_SLI 0x20 /* Suppress-Length-Indication */ +#define CCW_FLAG_SKP 0x10 /* Skip */ +#define CCW_FLAG_PCI 0x08 /* Program-Controlled-Interruption */ +#define CCW_FLAG_IDA 0x04 /* Indirect-Data-Address */ +#define CCW_FLAG_S 0x02 /* Suspend */ +#define CCW_FLAG_MIDA 0x01 /* Modified-Indirect-Data-Address */ + +struct orb { + /* word 0 */ + u32 param; /* Interruption Parameter */ + + /* word 1 */ + u8 key:4, /* Subchannel Key */ + s:1, /* Suspend */ + c:1, /* Streaming-Mode Control */ + m:1, /* Modification Control */ + y:1; /* Synchronization Control */ + u8 f:1, /* Format Control */ + p:1, /* Prefetch Control */ + i:1, /* Initial-Status-Interruption Control */ + a:1, /* Address-Limit-Checking control */ + u:1, /* Suppress-Suspend-Interruption Control */ + __zero1:1, + h:1, /* Format-2-IDAW Control */ + t:1; /* 2K-IDAW Control */ + u8 lpm; /* Logical-Path Mask */ + u8 l:1, /* Incorrect-Length-Suppression Mode */ + d:1, /* Modified-CCW-Indirect-Data-Addressing Control */ + __zero2:5, + x:1; /* ORB-Extension Control */ + + /* word 2 */ + u32 addr; /* Channel-Program Address */ + + /* word 3 */ + u8 css_prio; /* Channel-Subsystem Priority */ + u8 __reserved1; + u8 cu_prio; /* Control-Unit Priority */ + u8 __reserved2; + + /* word 4 - 7 */ + u32 __reserved3; + u32 __reserved4; + u32 __reserved5; + u32 __reserved6; +} __attribute__((packed,aligned(4))); + +struct scsw { + /* word 0 */ + u16 key:4, /* Subchannel key */ + s:1, /* Suspend control */ + l:1, /* ESW format */ + cc:2, /* Deferred condition code */ + f:1, /* Format */ + p:1, /* Prefetch */ + i:1, /* Initial-status interruption control */ + a:1, /* Address-limit-checking control */ + u:1, /* Supress-suspended interruption */ + z:1, /* Zero condition code */ + e:1, /* Extended control */ + n:1; /* Path no operational */ + u16 __zero:1, + fc:3, /* Function control */ + ac:8, /* Activity control */ + sc:4; /* Status control */ + + /* word 1 */ + u32 addr; /* CCW Address */ + + /* word 2 */ + u8 dev_status; /* Device status */ + u8 sch_status; /* Subchannel status */ + u16 count; /* Count */ +} __attribute__((packed)); + +/* Path Management Control Word */ +struct pmcw { + /* word 0 */ + u32 interrupt_param; /* Interruption Parameter */ + + /* word 1*/ + u8 __zero1:2, + isc:3, /* I/O-Interruption-Subclass Code */ + __zero2:3; + u8 e:1, /* Enabled */ + lm:2, /* Limit Mode */ + mm:2, /* Measurement-Mode Enable */ + d:1, /* Multipath Mode */ + t:1, /* Timing Facility */ + v:1; /* Device Number Valid */ + u16 dev_num; /* Device Number */ + + /* word 2 */ + u8 lpm; /* Logical-Path Mask */ + u8 pnom; /* Path-Not-Operational Mask */ + u8 lpum; /* Last-Path-Used Mask */ + u8 pim; /* Path-Installed Mask */ + + /* word 3 */ + u16 mbi; /* Measurement-Block Index */ + u8 pom; /* Path-Operational Mask */ + u8 pam; /* Path-Available Mask */ + + /* word 4 & 5 */ + u8 chpid[8]; /* Channel-Path Identifiers */ + + /* word 6 */ + u16 __zero3; + u16 __zero4:13, + f:1, /* Measurement Block Format Control */ + x:1, /* Extended Measurement Word Mode Enable */ + s:1; /* Concurrent Sense */ +}; + +struct schib { + struct pmcw pmcw; /* Path Management Control Word */ + struct scsw scsw; /* Subchannel Status Word */ + u32 w0, w1; + u32 model_dep_area; +} __attribute__((packed,aligned(4))); + +#define ADDR31(x) ((u32) (u64) (x)) + +extern void wto(char *str); +extern void wtor(char *str, char *inp, int buflen); +extern void __readwrite_blk(void *ptr, u32 lba, int rwccw); +#define read_blk(ptr, lba) __readwrite_blk((ptr), (lba), 0x86) +#define write_blk(ptr, lba) __readwrite_blk((ptr), (lba), 0x05) + +extern int __do_io(u32 sch); +extern void __wait_for_attn(); +extern void PGMHANDLER(); +extern void IOHANDLER(); + +extern void load_nucleus(void); + +extern struct orb ORB; + +extern u64 ipl_sch; +extern u64 con_sch; +extern u64 dasd_sch; + +static inline int store_sch(u32 sch, struct schib *schib) +{ + int cc; + + asm volatile( + "lr %%r1,%2\n" + "stsch %1\n" + "ipm %0\n" + "srl %0,28\n" + : /* output */ + "=d" (cc), + "=Q" (*schib) + : /* input */ + "d" (sch) + : /* clobbered */ + "cc", "r1", "memory" + ); + + if (cc == 3) + return -EINVAL; + return 0; +} + +static inline int modify_sch(u32 sch, struct schib *schib) +{ + int cc; + + asm volatile( + "lr %%r1,%1\n" + "msch %2\n" + "ipm %0\n" + "srl %0,28\n" + : /* output */ + "=d" (cc) + : /* input */ + "d" (sch), + "m" (*schib) + : /* clobbered */ + "cc", "r1" + ); + + if (cc == 1 || cc == 2) + return -EBUSY; + if (cc == 3) + return -EINVAL; + return 0; +} + +extern void unload_archive(void); + +/* + * EDF related structs & macros + */ +#define EDF_LABEL_BLOCK_NO 3 +#define EDF_SUPPORTED_BLOCK_SIZE 4096 + +struct ADT { + u32 IDENT; /* VOL START / LABEL IDENTIFIER */ +#define __ADTIDENT 0xC3D4E2F1 /* 'CMS1' in EBCDIC */ + u8 ID[6]; /* VOL START / VOL IDENTIFIER */ + u8 VER[2]; /* VERSION LEVEL */ + u32 DBSIZ; /* DISK BLOCK SIZE */ + u32 DOP; /* DISK ORIGIN POINTER */ + u32 CYL; /* NUM OF FORMATTED CYL ON DISK */ + u32 MCYL; /* MAX NUM FORMATTED CYL ON DISK */ + u32 NUM; /* Number of Blocks on disk */ + u32 USED; /* Number of Blocks used */ + u32 FSTSZ; /* SIZE OF FST */ + u32 NFST; /* NUMBER OF FST'S PER BLOCK */ + u8 DCRED[6]; /* DISK CREATION DATE (YYMMDDHHMMSS) */ + u8 FLGL; /* LABEL FLAG BYTE (ADTFLGL) */ +#define ADTCNTRY 0x01 /* Century for disk creation date (0=19, 1=20), + * corresponds to ADTDCRED. */ + u8 reserved[1]; + u32 OFFST; /* DISK OFFSET WHEN RESERVED */ + u32 AMNB; /* ALLOC MAP BLOCK WITH NEXT HOLE */ + u32 AMND; /* DISP INTO HBLK DATA OF NEXT HOLE */ + u32 AMUP; /* DISP INTO USER PART OF ALLOC MAP */ + u32 OFCNT; /* Count of SFS open files for this ADT */ + u8 SFNAM[8]; /* NAME OF SHARED SEGMENT */ +}; + +struct FST { + u8 FNAME[8]; /* filename */ + u8 FTYPE[8]; /* filetype */ + u8 DATEW[2]; /* DATE LAST WRITTEN - MMDD */ + u8 TIMEW[2]; /* TIME LAST WRITTEN - HHMM */ + u16 WRPNT; /* WRITE POINTER - ITEM NUMBER */ + u16 RDPNT; /* READ POINTER - ITEM NUMBER */ + u8 FMODE[2]; /* FILE MODE - LETTER AND NUMBER */ + u16 RECCT; /* NUMBER OF LOGICAL RECORDS */ + u16 FCLPT; /* FIRST CHAIN LINK POINTER */ + u8 RECFM; /* F*1 - RECORD FORMAT - F OR V */ +#define FSTDFIX 0xC6 /* Fixed record format (EBCDIC 'F') */ +#define FSTDVAR 0xE5 /* Variable record format (EBCDIC 'V') */ + u8 FLAGS; /* F*2 - FST FLAG BYTE */ +#define FSTRWDSK 0x80 /* READ/WRITE DISK */ +#define FSTRODSK 0x00 /* READ/ONLY DISK */ +#define FSTDSFS 0x10 /* Shared File FST */ +#define FSTXRDSK 0x40 /* EXTENSION OF R/O DISK */ +#define FSTXWDSK 0xC0 /* EXTENSION OF R/W DISK */ +#define FSTEPL 0x20 /* EXTENDED PLIST */ +#define FSTDIA 0x40 /* ITEM AVAILABLE */ +#define FSTDRA 0x01 /* PREVIOUS RECORD NULL */ +#define FSTCNTRY 0x08 /* Century for date last written (0=19, 1=20),\\ + corresponds to FSTYEARW, FSTADATI. */ +#define FSTACTRD 0x04 /* ACTIVE FOR READING */ +#define FSTACTWR 0x02 /* ACTIVE FOR WRITING */ +#define FSTACTPT 0x01 /* ACTIVE FROM A POINT */ +#define FSTFILEA 0x07 /* THE FILE IS ACTIVE */ + u32 LRECL; /* LOGICAL RECORD LENGTH */ + u16 BLKCT; /* NUMBER OF 800 BYTE BLOCKS */ + u16 YEARW; /* YEAR LAST WRITTEN */ + u32 FOP; /* ALT. FILE ORIGIN POINTER */ + u32 ADBC; /* ALT. NUMBER OF DATA BLOCKS */ + u32 AIC; /* ALT. ITEM COUNT */ + u8 NLVL; /* NUMBER OF POINTER BLOCK LEVELS */ + u8 PTRSZ; /* LENGTH OF A POINTER ELEMENT */ + u8 ADATI[6]; /* ALT. DATE/TIME(YY MM DD HH MM SS) */ + u8 REALM; /* Real filemode */ + u8 FLAG2; /* F*3 - FST FLAG BYTE 2 FSTFLAG2 */ +#define FSTPIPEU 0x10 /* Reserved for CMS PIPELINES usage */ + u8 reserved[2]; +}; + +extern void init_malloc(void *ptr); +extern void *malloc(u32 size); + +extern void mount_fs(); +extern int find_file(char *fn, char *ft, struct FST *fst); +extern int create_file(char *fn, char *ft, int lrecl, struct FST *fst); +extern void append_record(struct FST *fst, u8 *buf); + +extern void writeback_buffers(); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/loader_asm.S Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,218 @@ +# +# Copyright (c) 2007-2011 Josef 'Jeff' Sipek +# + +#include "loader.h" + +.text + .align 4 +.globl __wait_for_attn + .type __wait_for_attn, @function +__wait_for_attn: + LARL %r4,WAITPSW # wait for the interrupt + LPSWE 0(%r4) + +# int __do_io(u32 sch); + .align 4 +.globl __do_io + .type __do_io, @function +__do_io: + LGR %r1,%r2 # load subsystem ID + + LA %r2,0xfff # error return code + + LARL %r4,ORB + SSCH 0(%r4) # issue IO + BCR 7, %r14 # return on error + + LARL %r4,WAITPSW # wait for the interrupt + LPSWE 0(%r4) + +# +# The IO interrupt handler; it's very much like a continuation of __do_io +# +.globl IOHANDLER +IOHANDLER: + # is this for us? + LARL %r1,MAGICVAL + L %r1,0(%r1) + C %r1,0xbc + BRC 7,IONOTDONE + + # it is! + + LLGF %r1,0xb8 # load subsystem ID + + LARL %r4,IRB + TSCH 0(%r4) + + # check the Channel Status for != 0 + XGR %r2,%r2 + IC %r2,9(%r4) + NILL %r2,0xbf # get rid of SLI + LTR %r2,%r2 + BCR 7,%r14 # error, let's bail + + # check the Device Status + XGR %r1,%r1 + IC %r1,8(%r4) + + # unit check, unit except? + LR %r2,%r1 + NILL %r2,0x03 + BCR 4,%r14 # error return + + # attention, DE? + XGR %r2,%r2 + NILL %r1,0x84 + BCR 4,%r14 # ok return + +IONOTDONE: + LPSWE 0x170 + +# +# The PGM interrupt handler +# +.globl PGMHANDLER +PGMHANDLER: + STMG %r1,%r3,0x200 + + # r3 = 0x80000000 + XGR %r3, %r3 + LHI %r3, 0x8 + SLL %r3, 20 + + # is ILC == 3? + LGH %r2,0x8C + CGHI %r2,0x0006 + BNE ERR(%r3) + + # grab the old PSW address, subtract length of TPROT, and compare it + # with the TPROT opcode (0xe501) + LG %r1,0x158 + AGHI %r1,-6 + LLGH %r2,TPROTOP(%r3) + LLGH %r1,0(%r1) + CGR %r2,%r1 + BNE ERR(%r3) + + # set CC=3 + OI 0x152,0x30 + + LMG %r1,%r3,0x200 + + LPSWE 0x150 + +ERR: +.byte 0x00, 0x00 + + +# +# Useful data +# +.data +.globl TPROTOP +TPROTOP: +.byte 0xe5, 0x01 + + .align 8 +.globl IOPSW +IOPSW: + .byte 0x00 + # bits value name desc + # 0 0 <zero> + # 1 0 PER Mask (R) disabled + # 2-4 0 <zero> + # 5 0 DAT Mode (T) disabled + # 6 0 I/O Mask (IO) enabled + # 7 0 External Mask (EX) disabled + + .byte 0x00 + # bits value name desc + # 8-11 0 Key + # 12 0 <one> + # 13 0 Machine-Check Mask (M) disabled + # 14 0 Wait State (W) executing + # 15 0 Problem State (P) supervisor state + + .byte 0x00 + # bits value name desc + # 16-17 0 Address-Space Control (AS) disabled + # 18-19 0 Condition Code (CC) + # 20-23 0 Program Mask exceptions disabled + + .byte 0x01 + # bits value name desc + # 24-30 0 <zero> + # 31 1 Extended Addressing (EA) EA + BA = 64 mode + + .byte 0x80, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + # bits value name desc + # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 + # 33-63 0 <zero> + # 64-127 addr Instruction Address Address to exec + +.globl WAITPSW +WAITPSW: + .byte 0x02 + # bits value name desc + # 0 0 <zero> + # 1 0 PER Mask (R) disabled + # 2-4 0 <zero> + # 5 0 DAT Mode (T) disabled + # 6 1 I/O Mask (IO) enabled + # 7 0 External Mask (EX) disabled + + .byte 0x02 + # bits value name desc + # 8-11 0 Key + # 12 0 <zero> + # 13 0 Machine-Check Mask (M) disabled + # 14 1 Wait State (W) not executing + # 15 0 Problem State (P) supervisor state + + .byte 0x00 + # bits value name desc + # 16-17 0 Address-Space Control (AS) disabled + # 18-19 0 Condition Code (CC) + # 20-23 0 Program Mask exceptions disabled + + .byte 0x01 + # bits value name desc + # 24-30 0 <zero> + # 31 1 Extended Addressing (EA) EA + BA = 64 mode + + .byte 0x80, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + # bits value name desc + # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 + # 33-63 0 <zero> + # 64-127 addr Instruction Address Address to exec + +.globl IRB +IRB: + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + + .align 4 +.globl ORB +ORB: + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + +.globl MAGICVAL +MAGICVAL: + .4byte 0x12345678
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/loader_c.c Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2007-2011 Josef 'Jeff' Sipek + */ + +#include "loader.h" +#include <binfmt_elf.h> +#include <string.h> +#include <ebcdic.h> + +static unsigned char seek_data[6]; +static unsigned char search_data[5]; + +extern struct orb ORB; + +static u8 *buf = (u8*) (16 * 1024); +static u32 *ptrbuf = (u32*) (20 * 1024); + +static u64 pgm_new_psw_diswait[2] = { + 0x0002000180000000ULL, 0, +}; + +static u64 io_new_psw[2] = { + 0x0000000180000000ULL, (u64) &IOHANDLER, +}; + +static u64 pgm_new_psw[2] = { + 0x0000000180000000ULL, (u64) &PGMHANDLER, +}; + +u64 ipl_sch; +u64 con_sch; +u64 dasd_sch; + +void __readwrite_blk(void *ptr, u32 lba, int rwccw) +{ + struct ccw ccw[4]; + + u16 cc, hh, r; + + if (lba < 1) + die(); + + memset(ccw, 0, sizeof(ccw)); + + lba--; + cc = lba / RECORDS_PER_CYL; + hh = (lba % RECORDS_PER_CYL) / RECORDS_PER_TRACK; + r = (lba % RECORDS_PER_CYL) % RECORDS_PER_TRACK; + r++; + + ORB.addr = ADDR31(ccw); + + /* SEEK */ + ccw[0].cmd = 0x07; + ccw[0].flags = CCW_FLAG_CC | CCW_FLAG_SLI; + ccw[0].count = 6; + ccw[0].addr = ADDR31(seek_data); + + seek_data[0] = 0; /* zero */ + seek_data[1] = 0; /* zero */ + seek_data[2] = cc >> 8; /* Cc */ + seek_data[3] = cc & 0xff; /* cC */ + seek_data[4] = hh >> 8; /* Hh */ + seek_data[5] = hh & 0xff; /* hH */ + + /* SEARCH */ + ccw[1].cmd = 0x31; + ccw[1].flags = CCW_FLAG_CC | CCW_FLAG_SLI; + ccw[1].count = 5; + ccw[1].addr = ADDR31(search_data); + + search_data[0] = cc >> 8; + search_data[1] = cc & 0xff; + search_data[2] = hh >> 8; + search_data[3] = hh & 0xff; + search_data[4] = r; + + /* TIC */ + ccw[2].cmd = 0x08; + ccw[2].flags = 0; + ccw[2].count = 0; + ccw[2].addr = ADDR31(&ccw[1]); + + /* READ/WRITE DATA */ + ccw[3].cmd = rwccw; + ccw[3].flags = 0; + ccw[3].count = 4096; + ccw[3].addr = ADDR31(ptr); + + /* + * issue IO + */ + if (__do_io(dasd_sch)) + die(); +} + +struct senseid_struct { + u8 __reserved; + u16 cu_type; + u8 cu_model; + u16 dev_type; + u8 dev_model; +} __attribute__((packed)); + + +static int dev_dasd(void) +{ + int ret; + struct ccw ccw; + struct senseid_struct id; + + ccw.cmd = 0xe4; + ccw.flags = CCW_FLAG_SLI; + ccw.count = sizeof(struct senseid_struct); + ccw.addr = ADDR31(&id); + + ORB.param = 0x12345678, + ORB.f = 1, + ORB.lpm = 0xff, + ORB.addr = ADDR31(&ccw); + + ret = __do_io(dasd_sch); + if (ret) + die(); + + if ((id.dev_type == 0x3390) && + (id.dev_model == 0x0A) && + (id.cu_type == 0x3990) && + (id.cu_model == 0xC2)) + return 0; // ECKD 3390-3 that we know how to use + + return -1; // not a DASD +} + +static u64 atoi(char *s, int len) +{ + u64 i = 0; + + while(len) { + if ((*s >= '0') && (*s <= '9')) + i = (i * 16) + (*s - '0'); + else if ((*s >= 'A') && (*s <= 'F')) + i = (i * 16) + (*s - 'A' + 10); + else if ((*s >= 'a') && (*s <= 'f')) + i = (i * 16) + (*s - 'a' + 10); + else + break; + len--; + s++; + } + + return i; +} + +static u64 find_devnum(u64 devnum) +{ + struct schib schib; + u64 sch; + + if (devnum > 0xffff) + die(); + + memset(&schib, 0, sizeof(struct schib)); + + /* + * For each possible subchannel id... + */ + for(sch = 0x10000; sch <= 0x1ffff; sch++) { + /* + * ...call store subchannel, to find out whether or not + * there is a device + */ + if (store_sch(sch, &schib)) + continue; + + if (!schib.pmcw.v) + continue; + + if (schib.pmcw.dev_num != devnum) + continue; + + schib.pmcw.e = 1; + + if (modify_sch(sch, &schib)) + die(); + + return sch; + } + + return ~0; +} + +void wto(char *str) +{ + int ret; + struct ccw ccw; + char buf[160]; + + strncpy(buf, str, 160); + buf[159] = '\0'; + + ascii2ebcdic((u8*)buf, 160); + + ccw.cmd = 0x01; + ccw.flags = 0; + ccw.count = strlen(str); + ccw.addr = ADDR31(buf); + + ORB.param = 0x12345678, + ORB.f = 1, + ORB.lpm = 0xff, + ORB.addr = ADDR31(&ccw); + + ret = __do_io(con_sch); + if (ret) + die(); +} + +void wtor(char *str, char *inp, int buflen) +{ + int ret; + struct ccw ccw; + + wto(str); + + /* wait for user input */ + __wait_for_attn(); + + /* read user input */ + ccw.cmd = 0x0a; + ccw.flags = CCW_FLAG_SLI; + ccw.count = buflen; + ccw.addr = ADDR31(inp); + + ORB.param = 0x12345678, + ORB.f = 1, + ORB.lpm = 0xff, + ORB.addr = ADDR31(&ccw); + + ret = __do_io(con_sch); + if (ret) + die(); + + ebcdic2ascii((u8*)inp, buflen); +} + +static void init_io(void) +{ + u64 cr6; + + /* enable all I/O interrupt classes */ + asm volatile( + "stctg 6,6,%0\n" /* get cr6 */ + "oi %1,0xff\n" /* enable all */ + "lctlg 6,6,%0\n" /* reload cr6 */ + : /* output */ + : /* input */ + "m" (cr6), + "m" (*(u64*) (((u8*)&cr6) + 4)) + ); +} + +void load_nucleus(void) +{ + char inp[160]; + + /* Save the IPL device subchannel id */ + ipl_sch = *((u32*) 0xb8); + + memcpy((void*) 0x1d0, pgm_new_psw_diswait, 16); + memcpy((void*) 0x1f0, io_new_psw, 16); + + init_io(); + + /* + * try to find the console on 0009 + */ + con_sch = find_devnum(CON_DEVNUM); + if (con_sch > 0x1ffff) + die(); + + /* + * greet the user on the console + */ + wto("HVF installer\n\n"); + + for(;;) { + /* + * ask the user for target dasd + */ + wtor("Specify target device (1-4 hex digits):\n", inp, 160); + + dasd_sch = find_devnum(atoi(inp, 160)); + if ((dasd_sch < 0x10000) || (dasd_sch > 0x1ffff)) { + wto("Invalid device number.\n\n"); + continue; + } + + wto("Device found.\n\n"); + if (dev_dasd()) { + wto("Need a DASD.\n\n"); + continue; + } + + break; + } + + inp[0] = 'n'; + wtor("Format volume? [y/n]\n", inp, 160); + + if ((inp[0] == 'y') || (inp[0] == 'Y')) { + wto("Formating volume...\n"); + + /* + * FIXME: + * 1) format the volume + * 2) setup EDF + */ + + wto("done. (Not yet implemented)\n"); + die(); + } else + wto("Formatting skipped.\n"); + + /* + * initialize the memory allocator + */ + init_malloc(TEMP_BASE); + + /* + * mount the EDF volume + */ + mount_fs(); + + /* + * read through the archive and decide what to do with each file + */ + unload_archive(); + + /* + * currently, we haven't written anything to disk; flush everything + */ + writeback_buffers(); + + /* + * FIXME: inform the user that we're done, and load a psw with the + * right magic + */ + + wto("\nInstallation complete.\n"); + wto("You can now IPL from the DASD.\n"); + + for(;;); + die(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/malloc.c Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Josef 'Jeff' Sipek + */ +#include "loader.h" + +static char *top; + +void init_malloc(void *ptr) +{ + top = ptr; +} + +void *malloc(u32 size) +{ + char *t; + + t = top; + top += size; + + return t; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer/setmode.S Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,49 @@ +# +# Copyright (c) 2007-2011 Josef 'Jeff' Sipek +# + +.globl MAIN + .type MAIN, @function +MAIN: +# +# At this point, the machine is running in ESA390 mode. Let's load a new +# PSW, making it switch to 64-bit mode +# + + # switch to 64-bit mode + # + # Signal Processor + # Order 0x12: Set Architecture + # R1 bits 56-63 = 0x01 (switch all CPUs to z/Arch) + SR %r1, %r1 + LHI %r1, 0x1 # switch all to z/Arch + SR %r3, %r3 # CPU Address (CPU0000) + SIGP %r1, %r3, 0x12 # Signal, order 0x12 + SAM64 + # On error: + # Bit 55 = 1, cc1 (inval param) + # Bit 54 = 1, cc1 (incorrect state) + + # FIXME: check for errors? + +# +# At this point, we should be in 64-bit mode +# + + # + # It is unfortunate that the below code is required. + # + # Let's set the stack pointer to make gcc happy + # + # A standard stack frame is 160 bytes. + # + + # r15 = 0x100000 + # = (1 << 20) + # + SGR %r15, %r15 + LGHI %r15, 0x1 + SLLG %r15, %r15, 20 + AGHI %r15, -160 + + BRC 15,load_nucleus
--- a/lib/string.c Sat Feb 26 17:58:57 2011 -0500 +++ b/lib/string.c Wed Apr 20 20:50:32 2011 -0400 @@ -40,6 +40,23 @@ } /** + * strncmp - Compare two strings + * @cs: One string + * @ct: Another string + * @len: max length + */ +int strncmp(const char *cs, const char *ct, int len) +{ + signed char __res; + + while (1) { + if ((__res = *cs - *ct++) != 0 || !*cs++ || len--) + break; + } + return __res; +} + +/** * strcasecmp - Compare two strings ignoring case * @s1: One string * @s2: Another string @@ -81,6 +98,35 @@ return dest; } +/** + * memmove - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * Unlike memcpy(), memmove() copes with overlapping areas. + */ +void *memmove(void *dest, const void *src, size_t count) +{ + char *tmp; + const char *s; + + if (dest <= src) { + tmp = dest; + s = src; + while (count--) + *tmp++ = *s++; + } else { + tmp = dest; + tmp += count; + s = src; + s += count; + while (count--) + *--tmp = *--s; + } + return dest; +} + /* ASCII character info */ unsigned char _ascii_ctype[] = { _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/.gitignore Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,2 @@ +*.o +*.rto
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/Makefile Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,28 @@ +AS=$(CROSS_COMPILE)as +OBJCOPY=$(CROSS_COMPILE)objcopy +CC=$(CROSS_COMPILE)gcc +LD=$(CROSS_COMPILE)ld +CFLAGS=-g -fno-strict-aliasing -fno-builtin -nostdlib -Wall -m64 -I ../include/ -O2 -include ../include/types.h +NUCLEUSCFLAGS= + +include ../cp/scripts/Makefile.commands + +all: eckd.rto loader.rto + +clean: + rm -f *.o + rm -f *.rto + +loader.o: setmode.o loader_c.o loader_asm.o + $(call link-ipl,$^,$@) + +%.o: %.c + $(call c-to-o,$<,$@) + +%.rto: %.o + $(call objcopy-tdr,$<,$@) + +%.o: %.S + $(call s-to-o,$<,$@) + +.PRECIOUS: %.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/eckd.S Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,76 @@ +# During the system IPL, 24 bytes are read from the device. +# +# NOTE: zArch IPLs in ESA/390 mode. +# + +# +# Bytes 0-7 contain PSW to be loaded after IO operation completes +# + .byte 0x00 + # bits value name desc + # 0 0 <zero> + # 1 0 PER Mask (R) disabled + # 2-4 0 <zero> + # 5 0 DAT Mode (T) disabled + # 6 0 I/O Mask (IO) disabled + # 7 0 External Mask (EX) disabled + + .byte 0x08 + # bits value name desc + # 8-11 0 Key + # 12 1 <one> + # 13 0 Machine-Check Mask (M) disabled + # 14 0 Wait State (W) executing + # 15 0 Problem State (P) supervisor state + + .byte 0x00 + # bits value name desc + # 16-17 0 Address-Space Control (AS) disabled + # 18-19 0 Condition Code (CC) + # 20-23 0 Program Mask exceptions disabled + + .byte 0x00 + # bits value name desc + # 24-30 0 <zero> + # 31 0 Extended Addressing (EA) ! 64 mode + + .byte 0x80 # bits 32-39 + .byte 0x80 # bits 40-47 + .byte 0x00 # bits 48-55 + .byte 0x00 # bits 56-63 + # bits value name desc + # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 + # 33-63 addr Instruction Address Address to exec + +# +# The remaining 16 bytes should contain CCW to read data from device +# + +# CCW format-0: +# bits name +# 0-7 Cmd Code +# 8-31 Data Address +# 32 Chain-Data (CD) +# 33 Chain-Command (CC) +# 34 Sup.-Len.-Inditcation (SLI) +# 35 Skip (SKP) +# 36 Prog.-Contr.-Inter. (PCI) +# 37 Indir.-Data-Addr. (IDA) +# 38 Suspend (S) +# 39 Modified I.D.A. (MIDA) +# 40-47 <ignored> +# 48-63 number of bytes to read + +# +# CCW 1 (bytes 8-15): format-0 +# + # READ DATA 4 kB to 0x800000 + .byte 0x86, 0x80, 0x00, 0x00 + .byte 0x00, 0x00, 0x10, 0x00 + +# +# CCW 2 (bytes 16-23): format-0 +# + # invalid (unused) + .byte 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/layout.txt Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,8 @@ +dasd layout: + +0,0,1 eckd.S +0,0,2 setmode.S + loader.c + loader_asm.S + +<on fs> hvf.elf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/linker.script Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,10 @@ +SECTIONS +{ + ENTRY(MAIN) + . = 0x800000; + .text : { *(.text) } + .data : { *(.data) } + .rodata : { *(.rodata) } + .rodata.str1.2 : { *(.rodata.str1.2) } + .bss : { *(.bss) } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/loader.h Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,167 @@ +#ifndef __LOADER_H +#define __LOADER_H + +/* + * "Config" values + */ +#define TEMP_BASE ((unsigned char*) 0x400000) /* 4MB */ + +/* 3390 with 0 key length, and 4096 data length */ +#define RECORDS_PER_CYL (15*12) +#define RECORDS_PER_TRACK 12 + +/* the nucleus fn ft (in EBCDIC) => HVF ELF */ +#define CP_FN "\xC8\xE5\xC6\x40\x40\x40\x40\x40" +#define CP_FT "\xC5\xD3\xC6\x40\x40\x40\x40\x40" + +/* + * string manipulation + */ +#define memcpy(d,s,l) __builtin_memcpy((d), (s), (l)) +#define memcmp(d,s,l) __builtin_memcmp((d), (s), (l)) +#define memset(s,c,n) __builtin_memset((s),(c),(n)) + +/* + * I/O related structs, macros & variables + */ +struct ccw { + u8 cmd; /* Command code */ + u8 flags; /* Flags */ + u16 count; /* Count */ + u32 addr; /* Data Address */ +} __attribute__((packed,aligned(8))); + +#define CCW_FLAG_CD 0x80 /* Chain-Data */ +#define CCW_FLAG_CC 0x40 /* Chain-Command */ +#define CCW_FLAG_SLI 0x20 /* Suppress-Length-Indication */ +#define CCW_FLAG_SKP 0x10 /* Skip */ +#define CCW_FLAG_PCI 0x08 /* Program-Controlled-Interruption */ +#define CCW_FLAG_IDA 0x04 /* Indirect-Data-Address */ +#define CCW_FLAG_S 0x02 /* Suspend */ +#define CCW_FLAG_MIDA 0x01 /* Modified-Indirect-Data-Address */ + +struct orb { + /* word 0 */ + u32 param; /* Interruption Parameter */ + + /* word 1 */ + u8 key:4, /* Subchannel Key */ + s:1, /* Suspend */ + c:1, /* Streaming-Mode Control */ + m:1, /* Modification Control */ + y:1; /* Synchronization Control */ + u8 f:1, /* Format Control */ + p:1, /* Prefetch Control */ + i:1, /* Initial-Status-Interruption Control */ + a:1, /* Address-Limit-Checking control */ + u:1, /* Suppress-Suspend-Interruption Control */ + __zero1:1, + h:1, /* Format-2-IDAW Control */ + t:1; /* 2K-IDAW Control */ + u8 lpm; /* Logical-Path Mask */ + u8 l:1, /* Incorrect-Length-Suppression Mode */ + d:1, /* Modified-CCW-Indirect-Data-Addressing Control */ + __zero2:5, + x:1; /* ORB-Extension Control */ + + /* word 2 */ + u32 addr; /* Channel-Program Address */ + + /* word 3 */ + u8 css_prio; /* Channel-Subsystem Priority */ + u8 __reserved1; + u8 cu_prio; /* Control-Unit Priority */ + u8 __reserved2; + + /* word 4 - 7 */ + u32 __reserved3; + u32 __reserved4; + u32 __reserved5; + u32 __reserved6; +} __attribute__((packed,aligned(4))); + +#define ADDR31(x) ((u32) (u64) (x)) + +extern void __do_io(); +extern void PGMHANDLER(); + +extern void load_nucleus(void); + +extern struct orb ORB; + +/* + * EDF related structs & macros + */ +#define EDF_LABEL_BLOCK_NO 3 +#define EDF_SUPPORTED_BLOCK_SIZE 4096 + +struct ADT { + u32 IDENT; /* VOL START / LABEL IDENTIFIER */ +#define __ADTIDENT 0xC3D4E2F1 /* 'CMS1' in EBCDIC */ + u8 ID[6]; /* VOL START / VOL IDENTIFIER */ + u8 VER[2]; /* VERSION LEVEL */ + u32 DBSIZ; /* DISK BLOCK SIZE */ + u32 DOP; /* DISK ORIGIN POINTER */ + u32 CYL; /* NUM OF FORMATTED CYL ON DISK */ + u32 MCYL; /* MAX NUM FORMATTED CYL ON DISK */ + u32 NUM; /* Number of Blocks on disk */ + u32 USED; /* Number of Blocks used */ + u32 FSTSZ; /* SIZE OF FST */ + u32 NFST; /* NUMBER OF FST'S PER BLOCK */ + u8 DCRED[6]; /* DISK CREATION DATE (YYMMDDHHMMSS) */ + u8 FLGL; /* LABEL FLAG BYTE (ADTFLGL) */ +#define ADTCNTRY 0x01 /* Century for disk creation date (0=19, 1=20), + * corresponds to ADTDCRED. */ + u8 reserved[1]; + u32 OFFST; /* DISK OFFSET WHEN RESERVED */ + u32 AMNB; /* ALLOC MAP BLOCK WITH NEXT HOLE */ + u32 AMND; /* DISP INTO HBLK DATA OF NEXT HOLE */ + u32 AMUP; /* DISP INTO USER PART OF ALLOC MAP */ + u32 OFCNT; /* Count of SFS open files for this ADT */ + u8 SFNAM[8]; /* NAME OF SHARED SEGMENT */ +}; + +struct FST { + u8 FNAME[8]; /* filename */ + u8 FTYPE[8]; /* filetype */ + u8 DATEW[2]; /* DATE LAST WRITTEN - MMDD */ + u8 TIMEW[2]; /* TIME LAST WRITTEN - HHMM */ + u16 WRPNT; /* WRITE POINTER - ITEM NUMBER */ + u16 RDPNT; /* READ POINTER - ITEM NUMBER */ + u8 FMODE[2]; /* FILE MODE - LETTER AND NUMBER */ + u16 RECCT; /* NUMBER OF LOGICAL RECORDS */ + u16 FCLPT; /* FIRST CHAIN LINK POINTER */ + u8 RECFM; /* F*1 - RECORD FORMAT - F OR V */ +#define FSTDFIX 0xC6 /* Fixed record format (EBCDIC 'F') */ +#define FSTDVAR 0xE5 /* Variable record format (EBCDIC 'V') */ + u8 FLAGS; /* F*2 - FST FLAG BYTE */ +#define FSTRWDSK 0x80 /* READ/WRITE DISK */ +#define FSTRODSK 0x00 /* READ/ONLY DISK */ +#define FSTDSFS 0x10 /* Shared File FST */ +#define FSTXRDSK 0x40 /* EXTENSION OF R/O DISK */ +#define FSTXWDSK 0xC0 /* EXTENSION OF R/W DISK */ +#define FSTEPL 0x20 /* EXTENDED PLIST */ +#define FSTDIA 0x40 /* ITEM AVAILABLE */ +#define FSTDRA 0x01 /* PREVIOUS RECORD NULL */ +#define FSTCNTRY 0x08 /* Century for date last written (0=19, 1=20),\\ + corresponds to FSTYEARW, FSTADATI. */ +#define FSTACTRD 0x04 /* ACTIVE FOR READING */ +#define FSTACTWR 0x02 /* ACTIVE FOR WRITING */ +#define FSTACTPT 0x01 /* ACTIVE FROM A POINT */ +#define FSTFILEA 0x07 /* THE FILE IS ACTIVE */ + u32 LRECL; /* LOGICAL RECORD LENGTH */ + u16 BLKCT; /* NUMBER OF 800 BYTE BLOCKS */ + u16 YEARW; /* YEAR LAST WRITTEN */ + u32 FOP; /* ALT. FILE ORIGIN POINTER */ + u32 ADBC; /* ALT. NUMBER OF DATA BLOCKS */ + u32 AIC; /* ALT. ITEM COUNT */ + u8 NLVL; /* NUMBER OF POINTER BLOCK LEVELS */ + u8 PTRSZ; /* LENGTH OF A POINTER ELEMENT */ + u8 ADATI[6]; /* ALT. DATE/TIME(YY MM DD HH MM SS) */ + u8 REALM; /* Real filemode */ + u8 FLAG2; /* F*3 - FST FLAG BYTE 2 FSTFLAG2 */ +#define FSTPIPEU 0x10 /* Reserved for CMS PIPELINES usage */ + u8 reserved[2]; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/loader_asm.S Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,249 @@ +# +# Copyright (c) 2007 Josef 'Jeff' Sipek +# + +#include "loader.h" + +.text + .align 4 +.globl __do_io + .type __do_io, @function +__do_io: + # + # r4 = 0x80000000 + # + XGR %r4, %r4 + LHI %r4, 0x8 + SLL %r4, 20 + # + # r14 = r14 & 0x7fffffff don't ask, it's strangely retarded + # + L %r1,ADDRMASK(%r4) + NR %r14, %r1 # mask out the bit + + # set up the interrupt handler + MVC 0x1f0(16),IOPSW(%r4) # SET NEW IO PSW + LA %r1,IOHANDLER(%r4) # GET HANDLER ADDRESS + STG %r1,0x1f0+8 # SAVE IN NEW PSW + + L %r1, 0xb8 # load subsystem ID + + SSCH ORB(%r4) # issue IO + + # Load Control Register 6 with I/O interrupt subclass mask + STCTG 6,6,TMPVAR(%r4) # GET CR6 + OI TMPVAR+4(%r4),0xFF # enable all + LCTLG 6,6,TMPVAR(%r4) # RELOAD MODIFIED CR6 + +/* +7) Enable the PSW for I/O interrupts and go into wait state (you need bits 6, 12 & 14 set to 1 in the PSW : X'020A000000000000' is a good example) +*/ + LPSWE WAITPSW(%r4) + +# +# The IO interrupt handler +# +.globl IOHANDLER +IOHANDLER: + # is this for us? + L %r1, MAGICVAL(%r4) + C %r1, 0xbc + BNE IONOTDONE(%r4) + + # it is! + + L %r1, 0xb8 # load subsystem ID + + TSCH IRB(%r4) + +/* +FIXME: we should do more checking! + +11) If Unit check or Channel Status|=0 : An I/O error occurred and act accordingly +12) If unit exception : End of media (for tape & cards) and act accordingly +13) If device end : I/O Completed.. Perform post I/O stuff (like advancing your pointers) and back to step 3 +*/ + + # unit check? (end of media?) + L %r1,IRB+5(%r4) + LA %r0,0x02 + NR %r0,%r1 + LA %r2,1 # return 1 - end of medium + BCR 4,%r14 # unit chk => return + + # check the SCSW.. If CE Only : LPSW Old I/O PSW + LA %r0,0x04 + NR %r0,%r1 + LA %r2,0 # means IO done + BCR 4,%r14 # device end => return + +IONOTDONE: + LPSWE 0x170 + +# +# The PGM interrupt handler +# +.globl PGMHANDLER +PGMHANDLER: + STMG %r1,%r3,0x200 + + # r3 = 0x80000000 + XGR %r3, %r3 + LHI %r3, 0x8 + SLL %r3, 20 + + # is ILC == 3? + LGH %r2,0x8C + CGHI %r2,0x0006 + BNE ERR + + # grab the old PSW address, subtract length of TPROT, and compare it + # with the TPROT opcode (0xe501) + LG %r1,0x158 + AGHI %r1,-6 + LLGH %r2,TPROTOP(%r3) + LLGH %r1,0(%r1) + CGR %r2,%r1 + BNE ERR(%r3) + + # set CC=3 + OI 0x152,0x30 + + LMG %r1,%r3,0x200 + + LPSWE 0x150 + +ERR: +.byte 0x00, 0x00 + + +# +# Useful data +# +.data +.globl TPROTOP +TPROTOP: +.byte 0xe5, 0x01 + + .align 8 +.globl IOPSW +IOPSW: + .byte 0x00 + # bits value name desc + # 0 0 <zero> + # 1 0 PER Mask (R) disabled + # 2-4 0 <zero> + # 5 0 DAT Mode (T) disabled + # 6 0 I/O Mask (IO) enabled + # 7 0 External Mask (EX) disabled + + .byte 0x00 + # bits value name desc + # 8-11 0 Key + # 12 0 <one> + # 13 0 Machine-Check Mask (M) disabled + # 14 0 Wait State (W) executing + # 15 0 Problem State (P) supervisor state + + .byte 0x00 + # bits value name desc + # 16-17 0 Address-Space Control (AS) disabled + # 18-19 0 Condition Code (CC) + # 20-23 0 Program Mask exceptions disabled + + .byte 0x01 + # bits value name desc + # 24-30 0 <zero> + # 31 1 Extended Addressing (EA) EA + BA = 64 mode + + .byte 0x80 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + # bits value name desc + # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 + # 33-63 0 <zero> + # 64-127 addr Instruction Address Address to exec + +.globl WAITPSW +WAITPSW: + .byte 0x02 + # bits value name desc + # 0 0 <zero> + # 1 0 PER Mask (R) disabled + # 2-4 0 <zero> + # 5 0 DAT Mode (T) disabled + # 6 1 I/O Mask (IO) enabled + # 7 0 External Mask (EX) disabled + + .byte 0x02 + # bits value name desc + # 8-11 0 Key + # 12 0 <zero> + # 13 0 Machine-Check Mask (M) disabled + # 14 1 Wait State (W) not executing + # 15 0 Problem State (P) supervisor state + + .byte 0x00 + # bits value name desc + # 16-17 0 Address-Space Control (AS) disabled + # 18-19 0 Condition Code (CC) + # 20-23 0 Program Mask exceptions disabled + + .byte 0x01 + # bits value name desc + # 24-30 0 <zero> + # 31 1 Extended Addressing (EA) EA + BA = 64 mode + + .byte 0x80 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + # bits value name desc + # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 + # 33-63 0 <zero> + # 64-127 addr Instruction Address Address to exec + +.globl TMPVAR +TMPVAR: + .8byte 0x0 + +.globl ADDRMASK +ADDRMASK: + .4byte 0x7fffffff + +.globl MAGICVAL +MAGICVAL: + .4byte 0x12345678 + +.globl IRB +IRB: + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/loader_c.c Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2007-2009 Josef 'Jeff' Sipek + */ + +#include "loader.h" +#include <binfmt_elf.h> + +static unsigned char seek_data[6]; +static unsigned char search_data[5]; +static struct ccw ccw[4]; + +struct orb ORB = { + .param = 0x12345678, + .f = 1, + .lpm = 0xff, + .addr = 0xffffffff, +}; + +static u8 *buf = (u8*) (16 * 1024); +static u32 *ptrbuf = (u32*) (20 * 1024); + +/* + * halt the cpu + * + * NOTE: we don't care about not clobbering registers as when this + * code executes, the CPU will be stopped. + */ +static inline void die(void) +{ + asm volatile( + "SR %r1, %r1 # not used, but should be zero\n" + "SR %r3, %r3 # CPU Address\n" + "SIGP %r1, %r3, 0x05 # Signal, order 0x05\n" + ); + + /* + * Just in case SIGP fails + */ + for(;;); +} + +static u64 pgm_new_psw[2] = { + 0x0000000180000000ULL, (u64) &PGMHANDLER, +}; + +/* + * determine amount of storage + */ +static u64 sense_memsize(void) +{ + u64 size; + int cc; + +#define SKIP_SIZE (1024*1024ULL) + + /* set new PGM psw */ + memcpy((void*)0x1d0, pgm_new_psw, 16); + + for(size = 0; size < ((u64)~SKIP_SIZE)-1; size += SKIP_SIZE) { + asm volatile( + "lg %%r1,%1\n" + "tprot 0(%%r1),0\n" + "ipm %0\n" + "srl %0,28\n" + : /* output */ + "=d" (cc) + : /* input */ + "m" (size) + : /* clobber */ + "cc", "r1" + ); + + /* + * we cheat here a little...if we try to tprot a location + * that isn't part of the configuration, a program exception + * fires off, but our handler sets the CC to 3, and resumes + * execution + */ + if (cc == 3) + break; + } + + /* invalidate new PGM psw */ + memset((void*)0x1d0, 0, 16); + + return size; +} + +static void read_blk(void *ptr, u32 lba) +{ + u16 cc, hh, r; + + if (lba < 1) + die(); + + memset(ccw, 0, sizeof(ccw)); + + lba--; + cc = lba / RECORDS_PER_CYL; + hh = (lba % RECORDS_PER_CYL) / RECORDS_PER_TRACK; + r = (lba % RECORDS_PER_CYL) % RECORDS_PER_TRACK; + r++; + + ORB.addr = ADDR31(ccw); + + /* SEEK */ + ccw[0].cmd = 0x07; + ccw[0].flags = CCW_FLAG_CC | CCW_FLAG_SLI; + ccw[0].count = 6; + ccw[0].addr = ADDR31(seek_data); + + seek_data[0] = 0; /* zero */ + seek_data[1] = 0; /* zero */ + seek_data[2] = cc >> 8; /* Cc */ + seek_data[3] = cc & 0xff; /* cC */ + seek_data[4] = hh >> 8; /* Hh */ + seek_data[5] = hh & 0xff; /* hH */ + + /* SEARCH */ + ccw[1].cmd = 0x31; + ccw[1].flags = CCW_FLAG_CC | CCW_FLAG_SLI; + ccw[1].count = 5; + ccw[1].addr = ADDR31(search_data); + + search_data[0] = cc >> 8; + search_data[1] = cc & 0xff; + search_data[2] = hh >> 8; + search_data[3] = hh & 0xff; + search_data[4] = r; + + /* TIC */ + ccw[2].cmd = 0x08; + ccw[2].flags = 0; + ccw[2].count = 0; + ccw[2].addr = ADDR31(&ccw[1]); + + /* READ DATA */ + ccw[3].cmd = 0x86; + ccw[3].flags = 0; + ccw[3].count = 4096; + ccw[3].addr = ADDR31(ptr); + + /* + * issue IO + */ + __do_io(); +} + +/* + * read the entire nucleus into TEMP_BASE + */ +static inline void readnucleus(void) +{ + struct ADT *ADT = (struct ADT*) buf; + struct FST *FST = (struct FST*) buf; + struct FST fst; + int i, found; + u32 nfst; + + read_blk(buf, EDF_LABEL_BLOCK_NO); + + if ((ADT->IDENT != __ADTIDENT) || + (ADT->DBSIZ != EDF_SUPPORTED_BLOCK_SIZE) || + (ADT->OFFST != 0) || + (ADT->FSTSZ != sizeof(struct FST))) + die(); + + nfst = ADT->NFST; + + read_blk(buf, ADT->DOP); + + if (FST->NLVL != 0) + die(); // FIXME + + for(i=0,found=0; i<nfst; i++) { + if ((!memcmp(FST[i].FNAME, CP_FN, 8)) && + (!memcmp(FST[i].FTYPE, CP_FT, 8))) { + memcpy(&fst, &FST[i], sizeof(struct FST)); + found = 1; + break; + } + } + + if (!found) + die(); + + if (fst.PTRSZ != 4 || + fst.LRECL != 4096 || + fst.RECFM != FSTDFIX) + die(); + + /* Don't allow more than 3MB to be read */ + if ((FST->AIC * FST->LRECL) > (3ULL * 1024 * 1024)) + die(); + + /* Since we're assuming that NLVL==1, there's only 1 pointer block */ + read_blk(ptrbuf, fst.FOP); + + /* Read all the blocks pointed to by the ptr block */ + for(i=0; i<fst.AIC; i++) + read_blk(TEMP_BASE + (4096 * i), ptrbuf[i]); +} + +void load_nucleus(void) +{ + /* + * These are all stored in registers + */ + register u32 iplsch; + register int i; + register Elf64_Ehdr *nucleus_elf; + register Elf64_Shdr *section; + register void (*start_sym)(u64, u32); + + /* Save the IPL device subchannel id */ + iplsch = *((u32*) 0xb8); + + /* + * Read entire ELF to temporary location + */ + readnucleus(); + + nucleus_elf = (Elf64_Ehdr*) TEMP_BASE; + + /* + * Check that this looks like a valid ELF + */ + if (nucleus_elf->e_ident[0] != '\x7f' || + nucleus_elf->e_ident[1] != 'E' || + nucleus_elf->e_ident[2] != 'L' || + nucleus_elf->e_ident[3] != 'F' || + nucleus_elf->e_ident[EI_CLASS] != ELFCLASS64 || + nucleus_elf->e_ident[EI_DATA] != ELFDATA2MSB || + nucleus_elf->e_ident[EI_VERSION] != EV_CURRENT || + nucleus_elf->e_type != ET_EXEC || + nucleus_elf->e_machine != 0x16 || // FIXME: find the name for the #define + nucleus_elf->e_version != EV_CURRENT) + die(); + + /* + * Iterate through each section, and copy it to the final + * destination as necessary + */ + for (i=0; i<nucleus_elf->e_shnum; i++) { + section = (Elf64_Shdr*) (TEMP_BASE + + nucleus_elf->e_shoff + + nucleus_elf->e_shentsize * i); + + switch (section->sh_type) { + case SHT_PROGBITS: + if (!section->sh_addr) + break; + + /* + * just copy the data from TEMP_BASE to + * where it wants to be + */ + memcpy((void*) section->sh_addr, + TEMP_BASE + section->sh_offset, + section->sh_size); + break; + case SHT_NOBITS: + /* + * No action needed as there's no data to + * copy, and we assume that the ELF sections + * don't overlap + */ + memset((void*) section->sh_addr, + 0, section->sh_size); + break; + case SHT_SYMTAB: + case SHT_STRTAB: + /* TODO: relocate */ + break; + default: + /* Ignoring */ + break; + } + } + + /* + * Now, jump to the nucleus entry point + */ + start_sym = (void*) nucleus_elf->e_entry; + start_sym(sense_memsize(), iplsch); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/setmode.S Wed Apr 20 20:50:32 2011 -0400 @@ -0,0 +1,54 @@ +# +# Copyright (c) 2007-2009 Josef 'Jeff' Sipek +# + +.globl MAIN + .type MAIN, @function +MAIN: +# +# At this point, the machine is running in ESA390 mode. Let's load a new +# PSW, making it switch to 64-bit mode +# + + # switch to 64-bit mode + # + # Signal Processor + # Order 0x12: Set Architecture + # R1 bits 56-63 = 0x01 (switch all CPUs to z/Arch) + SR %r1, %r1 + LHI %r1, 0x1 # switch all to z/Arch + SR %r3, %r3 # CPU Address (CPU0000) + SIGP %r1, %r3, 0x12 # Signal, order 0x12 + SAM64 + # On error: + # Bit 55 = 1, cc1 (inval param) + # Bit 54 = 1, cc1 (incorrect state) + + # FIXME: check for errors? + +# +# At this point, we should be in 64-bit mode +# + + # + # It is unfortunate that the below code is required. + # + # Let's set the stack pointer to make gcc happy + # + # A standard stack frame is 160 bytes. + # + # NOTE: Once this thread of execution turns into the idle thread, + # the stack can be reused for something else. Since it's allocated + # in the 128th processor's PSA, we have to make sure that it won't + # get initialized until after the idle thread kicks in. + # + + # r15 = 0x100000 + # = (1 << 20) + # + SR %r15, %r15 + LHI %r15, 0x1 + SLL %r15, 20 + AHI %r15, -160 + + BRC 15,load_nucleus