201
Universidad de Las Palmas de Gran Canaria Kernel OS9 Tiempo Real Kernel OS9 Tiempo Real PIPEMAN PIPEMAN NFM NFM SBF SBF RBF RBF SCF SCF ACIA ACIA PIA PIA PIPE PIPE NET NET Cintas Cintas FD FD HD HD Aplicaciones de usuario Aplicaciones de usuario Utilidades del Sistema Utilidades del Sistema Librería CIO Librería CIO Librería Matemática Librería Matemática Departamento de Ingeniería Electrónica y Automática Aurelio Vega Martínez

Universidad de Las Palmas de Gran Canaria - IUMA - …nunez/clases-sed-mai-68ppc/Curso_OS9.pdfUniversidad de Las Palmas de Gran Canaria Kernel OS9 Tiempo Real Kernel OS9 Tiempo Real

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Universidad de

Las Palmas de Gran Canaria

Kernel OS9Tiempo RealKernel OS9Tiempo Real PIPEMANPIPEMAN

NFMNFM

SBFSBF

RBFRBF SCFSCF ACIAACIA

PIAPIA

PIPEPIPE

NETNET

CintasCintas

FDFD

HDHD

Aplicaciones de usuario

Aplicaciones de usuario

Utilidadesdel Sistema

Utilidadesdel Sistema

LibreríaCIO

LibreríaCIO

LibreríaMatemática

LibreríaMatemática

Departamento de Ingeniería Electrónica y Automática

Aurelio Vega Martínez

Sistema Operativo OS-9 Autor:

Aurelio Vega Martínez Dr. Ingeniero Industrial Escuela Técnica Superior de Ingenieros de Telecomunicación Departamento de Ingeniería Electrónica y Automática Universidad de Las Palmas de Gran Canaria

Todos los nombre propios de programas, sistemas operativos, equipos hardware, etc. que aparecen en este libro son marcas registradas de sus respectivas compañías u organizaciones. Reservados todos los derechos de publicación. Ninguna parte de este libro puede ser reproducida, grabada en sistema de almacena-miento o transmitida en forma alguna ni por cualquier procedimiento, ya sea electrónico, mecánico, reprográfico o de cualquier otro tipo, sin la autorización expresa de sus autores. 1º Edición: Diciembre 1998 Depósito Legal: ISBN: Impreso en España Imprime:

Servicio de Reprografía y Encuadernación Universidad de Las Palmas de Gran Canaria Las Palmas de Gran Canaria - España

INDICE

1 VISIÓN GENERAL DEL ENTORNO DE TRABAJO DEL OS-9......................................................... 9

2 PLANTEAMIENTO DEL CURSO ............................................ ¡ERROR! MARCADOR NO DEFINIDO.

3 INTRODUCCIÓN AL OS-9...................................................................................................................... 13

3.1 ARRANQUE DEL OS-9.............................................................................................................................. 13 3.2 DIRECTORIOS PRINCIPALES ................................................................................................................... 16 3.3 INTRODUCCIÓN AL SHELL. ...................................................................................................................... 17 3.4 EDICIÓN DE LA LÍNEA DE COMANDOS. ................................................................................................... 17 3.5 COMANDOS BÁSICOS Y UTILIDADES. ..................................................................................................... 18 3.6 FORMATEO DE UN DISCO Y BACKUP...................................................................................................... 22 3.7 EJERCICIOS. ........................................................................................................................................... 25

4 EL SISTEMA DE ARCHIVOS. ................................................................................................................ 27

4.1 TIPOS DE ARCHIVOS............................................................................................................................... 27 4.2 ESTRUCTURA DE DIRECTORIOS DEL OS-9............................................................................................ 28 4.3 ACCESO A LOS ARCHIVOS Y DIRECTORIOS. .......................................................................................... 29 4.4 COMANDOS ORIENTADOS A LA MANIPULACIÓN DE ARCHIVOS. ............................................................ 30 4.5 REGLAS PARA LA ASIGNACIÓN DE NOMBRES DE FICHEROS. ................................................................ 31 4.6 ATRIBUTOS DE LOS FICHEROS. .............................................................................................................. 32 4.7 EJERCICIOS. ........................................................................................................................................... 32

5 EL SHELL. ................................................................................................................................................. 33

5.1 LA FUNCIÓN DEL SHELL. ........................................................................................................................ 33 5.2 OPCIONES DEL SHELL. ............................................................................................................................. 33 5.3 VARIABLES DE ENTORNO. ...................................................................................................................... 34 5.4 COMANDOS INTERNOS DEL SHELL......................................................................................................... 36 5.5 SINTAXIS DE LA LÍNEA DE COMANDOS DEL SHELL. ............................................................................... 37

5.5.1 Modificadores.............................................................................................................................. 37 5.5.2 Separadores................................................................................................................................ 38 5.5.3 Wildcards. .................................................................................................................................... 39 5.5.4 Agrupadores de Comandos. ..................................................................................................... 40

5.6 FICHEROS DE PROCEDIMIENTOS. .......................................................................................................... 40 5.7 SISTEMAS MULTIUSUARIO. ..................................................................................................................... 41 5.8 EJERCICIOS. ........................................................................................................................................... 42

6 UTILIDADES DEL SISTEMA. ................................................................................................................. 42

7 ESTRUCTURA INTERNA DE OS-9. ..................................................................................................... 55

7.1 ESTRUCTURA DE UN MÓDULO BÁSICO. ................................................................................................... 58 7.2 EL KERNEL.............................................................................................................................................. 64

7.2.1 Responsabilidades del Kernel. ...................................................................................................... 64 7.2.2 Llamadas al Sistema...................................................................................................................... 64 7.2.3 Gestión de la Memoria.................................................................................................................. 65 7.2.4 El módulo Init. .............................................................................................................................. 71 7.2.5 El Módulo Sysgo........................................................................................................................... 77 7.2.6 Creación de Procesos.................................................................................................................... 79 7.2.7 Process Scheduling. ...................................................................................................................... 80 7.2.8 Excepciones e Interrupciones........................................................................................................ 81

8 EL SISTEMA DE ENTRADAS/SALIDAS. ............................................................................................ 82

8.1 LOS FILE MANAGERS. ............................................................................................................................. 83

8.2 LOS DRIVERS. .......................................................................................................................................... 84 8.2.1 Estructura General de un Driver OS-9. ........................................................................................ 84

8.3 LOS DESCRIPTORES DE DISPOSITIVOS...................................................................................................... 86

9 COMUNICACIONES ENTRE PROCESOS. ......................................................................................... 86

9.1 SEÑALES. ................................................................................................................................................. 87 9.2 ALARMAS. ............................................................................................................................................... 87 9.3 EVENTOS. ................................................................................................................................................ 88 9.4 PIPES........................................................................................................................................................ 89 9.5 MÓDULOS DE DATOS. .............................................................................................................................. 90

10 LOS TRAPS. .............................................................................................................................................. 92

11 EL EDITOR UMACS................................................................................................................................ 93

11.1 CARACTERÍSTICAS GENERALES. ......................................................................................................... 93 11.2 LOS COMANDOS DE UMACS. ............................................................................................................. 93

12 LA UTILIDAD MAKE................................................................................................................................. 96

13 EL COMPILADOR C................................................................................................................................. 99

13.1 INTRODUCCIÓN................................................................................................................................... 99 13.2 FICHEROS EJECUTABLES................................................................................................................... 99 13.3 FICHEROS DE LIBRERÍAS. ................................................................................................................ 100 13.4 FICHEROS DE DEFINICIONES. .......................................................................................................... 100 13.5 OPCIONES DEL COMPILADOR. ......................................................................................................... 101 13.6 FUNCIONES DE LIBRERÍAS. .............................................................................................................. 104 13.7 LA LIBRERÍA TERMCAP. ................................................................................................................... 109

14 EL ENSAMBLADOR Y LINKER. .......................................................................................................... 111

14.1 INTRODUCCIÓN................................................................................................................................. 111 14.2 FORMATO DEL FICHERO DE ENTRADA............................................................................................. 111 14.3 LOS MACROS. .................................................................................................................................. 112 14.4 LAS SECCIONES DE UN PROGRAMA REUBICABLE........................................................................... 113 14.5 LAS DIRECTIVAS DEL ENSAMBLADOR.............................................................................................. 116 14.6 OPCIONES DEL ENSAMBLADOR. ...................................................................................................... 117

15 PAQUETE DE COMUNICACIONES OS-9/ESP. ............................................................................... 121

15.1 INTRODUCCIÓN................................................................................................................................. 121 15.2 INICIALIZACIÓN DEL PAQUETE OS-9/ESP. ..................................................................................... 122 15.3 USANDO OS-9/ESP. ....................................................................................................................... 122 15.4 LIBRERÍAS C..................................................................................................................................... 123

Prólogo

Este libro sobre el Sistema Operativo OS-9 pretende cubrir las facetas más importantes involucradas en el OS-9. Está planteado para poder ser seguido por cualquier persona que no haya trabajo previamente en entornos de este tipo. El aprendizaje será por supuesto mucho más rápido en aquellas personas que sepan trabajar en los tres campos siguientes: * Entornos UNIX * Programación C * Ensamblador de la familia 68000 Para poder seguir el curso se parte de la idea de que disponemos de un equipo capaz de correr el OS-9 y de los disquetes del sistema operativo que suministra Microware. En función del equipo que disponga cada usuario, pueden existir diferencias en los contenidos de los distintos fichero del sistema, aunque en líneas generales, la filosofía de trabajo es independiente de la máquina sobre la que trabajemos. Todos los ejemplos y listados de fichero o explicación de utilidades del sistema operativo se hacen con referencia a la versión OS_9/68030 Force CPU-30/ISCSI Professional V2.3 que corre sobre la placa VME SYS68K/CPU-30 que suministra FORCE. El curso comienza enseñando a cargar el sistema operativo desde el floppy del equipo. A lo largo del curso se suministran numerosos ejemplos y listados de los ficheros más importantes, que son los que el usuario puede modificar para adaptar el sistema operativo a sus necesidades de trabajo. El curso se ha dividido en tres partes bien diferenciadas. Primera Parte: La primera parte del curso está orienta a estudiar las características básicas del OS-9. Se

explica como cargar el sistema, como es la estructura de ficheros y directorios, las funciones del shell y en general los comandos y utilidades básicos de trabajo.

Segunda Parte: En la segunda parte se estudia la estructura interna del OS-9, y todo el manejo de procesos y

comunicaciones entre ellos. Aquí veremos como poder utilizar el OS-9 como una potente herramienta de trabajo en tiempo real.

Tercera Parte: En la última parte del curso veremos una serie de utilidades adicionales como el compilador

de C, el ensamblador, el editor de textos o la utilidad Make.

1 Entorno de Trabajo del OS-9.

El sistema operativo OS-9 es un producto desarrollado por Microware Systems Corporation. Esta compañía fue fundada en 1979 y desde el principio orientó su labor al desarrollo de sistemas industriales basados en ROM y sistemas hardware de tamaño mediano orientados a aplicaciones en tiempo real. Sistema Completo

El OS-9 es un sistema operativo en tiempo real completo, esto significa que además del Kernel y los módulos del sistema dispone de los gestionadores de ficheros y drivers de dispositivos para soportar todo tipo de procesos de E/S. El OS-9 maneja múltiples solicitudes de E/S, utilizando "time-sharing" y "multitasking". La interfaz de usuario incluye un shell tipo UNIX, estructura de ficheros y directorios jerárquicos y más de 70 utilidades que permiten al usuario acceder a las funciones de manejo del sistema. Además se dispone de un entorno de programación con compiladores de alto nivel, depuradores y herramientas de desarrollo y comunicaciones.

Diseño Modular

El OS-9 está desarrollado sobre una colección de módulos independientes. El concepto de módulos de memoria organiza datos y programas en memoria. El diseño modular del OS-9 permite a cada usuario modificar y configurar el sistema operativo en función de sus necesidades particulares. Cada componente modular del OS-9, excepto el Kernel, puede ser dinámicamente añadido o eliminado del sistema.

El núcleo del OS-9 es el Kernel, el cual se encarga del manejo de los servicios del sistema, memoria, E/S y ejecución de procesos. Además del Kernel hay que añadir los gestionadores de ficheros y los respectivos sistemas de E/S.

El OS-9 ha sido usado en un amplio espectro de sistemas desarrollados sobre la familia 68000 de Motorola, en un abanico de equipos que van desde pequeños ordenadores basados en ROM hasta grandes sistemas multiusuarios. El tipo de aplicaciones en las cuales se ha empleado comprenden temas tan variados como * Control de procesos. * Tratamiento de imágenes. * Proceso de datos. * Comunicaciones. * Ordenadores Personales. * Robótica. Configuraciones Debido a esta filosofía de diseño, nuevos dispositivos pueden ser incorporados al sistema añadiendo nuevos drivers y nuevos descriptores. Esta filosofía queda reflejada en las tres configuraciones del sistema operativo que se suministran.

Industrial: Está diseñado para aplicaciones basadas en ROM que necesiten un Kernel pero

no soporte de disco o de cintas. Personal: Provee un completo entorno basado en disco para ordenadores personales.

Incluye un compilador de BASIC con un editor/depurador incorporado. Profesional: Provee un completo entorno de programación. Este incluye soporte de discos y

cintas, un completo compilador de C, un ensamblador y un depurador de ensamblador. El OS-9 combina conceptos de los nuevos sistemas operativos con capacidades de tiempo real con la arquitectura del UNIX, pero con las ventajas que significa el necesitar menos memoria y el ser más eficiente.

Características del OS-9

• Multiusuario. • Multitarea. • Software Modular y Reentrante. • Soporte de coprocesadores aritméticos. • Soporte de controladores de E/S. • Independiente del Hardware, modelo de E/S tipo UNIX. • Control de tareas tipo UNIX. • 100% capaz de instalarse en ROM. • Gestionadores de ficheros independientes, capaces de

soportar todo tipo de dispositivos de E/S. • Compatible con entornos UNIX al nivel de programas

desarrollados en C (K&R). • Soporta lenguajes de alto nivel. • Depuradores de código ensamblador y C.

OS-9: Entorno Completo

HERRAMIENTAS DE DESARROLLO Depurador de código fuente C. Depurador simbólico. Depurador "System State". Editor de texto uMACS. Correo electrónico. COM UniBridge PcBridge SmartWare OPCIONES DEL KERNEL Soporte de MMU Soporte de coprocesador matemático. LENGUAJES DE PROGRAMACION C BASIC Pascal FORTRAN Assembler OPCIONES DE E/S Soporte de discos Soporte de cintas magnéticas Internet - TCP/IP OS-9/NET - Arcnet RAVE - Audio/Video

2 Introducción al OS-9.

2.1 Arranque del OS-9. Antes de poder usar el OS-9 es necesario realizar el "boot" del sistema. El procedimiento para arrancar el sistema variará un poco en función del equipo que se disponga. El fabricante del equipo se encargará de suministrar la información sobre el procedimiento a seguir. Normalmente al conectar nuestro sistema nos aparecerá el programa monitor desde el cual podremos invocar al OS-9. Este programa monitor es en realidad el ROM-debugger. Para comenzar a correr el sistema operativo debemos escribir g <return> Conexión del equipo. OS-9/68K System Bootstrap called debugger Rel: 00000000 Dn: 00000000 00002000 00000000 0000000 00000000 00000001 FFFFE000 000013F8 An: FF000906 FF000478 FF040000 FF04000 00002400 00000400 00000400 000013F8 SR: 2708 (--S--7----N---) SSP: 000013F8 USP: 00000000 PC: FF000818 - 43FAFCAA lea.l $FCAA(pc),a1 debug: g <return> BOOTING PROCEDURE AVAILABLE -- <INPUT> Boot from floppy drive ------- <Floppy> Boot from SCSI hard drive ---- <Hard> Restart the system ----------- <Q> Select a boot method from the above menu: floppy <return>

En este momento se procede a intentar cargar el sistema operativo desde el disco indicado. Un disco de sistema debe contener todos los módulos necesarios para inicializar el sistema. Los ficheros básicos que podremos encontrar en el directorio raíz del disco de arranque son: OS9boot: Contiene los módulos de OS-9 que son cargados en memoria. startup: Este fichero ASCII es ejecutado después de cargar los distinto módulos en memoria

y contiene la información necesaria para configurar el sistema. Cuando el sistema encuentra un fichero OS9boot válido nos aparecerá un mensaje de que la operación ha sido correcta. A continuación, dentro del fichero startup, se ejecutan los comandos de inicialización del sistema operativo, entre los que suele figurar el comando para inicializar la fecha y la hora del sistema.

Cuando todo el proceso de arranque concluye nos aparece el "prompt" del sistema, el cual se queda esperando hasta que entremos una línea de comandos.

Ejecución del Fichero STARTUP. Now trying default floppy format (Universal)... Illegal sync code in sector zero. Now trying floppy format (58W7)... A valid OS-9 bootfile was found. -t -np * * OS-9/68030 Version 2.3 Force CPU30 * Copyright 1989 by Microware Systems Corporation * * The commands in this file are highly system dependent and should * be modified by the user. * setime ;* start system clock ] yy/mm/dd hh:mm:ss [am/pmTime: 90/05/18 1:05 pm <return> link shell cio ;* make "shell" and "cio" stay in memory iniz d0 ;* iniz device d0 * iniz r0 h0 t1 t2 p1 ;* initialize devices * load utils ;* make some utilities stay in memory * load bootobjs/dd.r0 ;* get the default device descriptor * init.ramdisk >/nil >>/nil& ;* initialize it if its the ram disk * tsmon /t1 /t2 & ;* start other terminals list sys/motd * ****** WELCOME TO PROFESSIONAL OS-9/68000 V2.3 ****** * * * * Thank you for selecting Microware's OS-9/68000 Operating System. * * We recommend that you familiarize yourself with OS-9 and its * * commands by reading "Using Professional OS-9". Release notes for * * this version of the operating system are at the front of this * * manual. Please read those release notes if you are already * * familiar with OS-9/68000. * * * * To start with, attempt just a few simple commands by typing in * * the following lines: * * * * dir (listing of current directory) * * dir -x (listing of OS-9/68000 utilities) * * procs -e (status of all processes) * * * * These are just two of the utilities supplied with OS-9. The OS-9 * * utilities are fully explained in the "Using Professional OS-9". * * * * The next thing you should do is FORMAT a new disk, and BACKUP * * this disk. With that completed, you are ready to enjoy the * * exciting world of OS-9. * $

2.2 Directorios Principales. En todo disco de sistema, podremos encontrar un conjunto de directorio básicos utilizados por el OS-9. Los nombres de los directorio y fichero pueden estár indistintamente escritos en mayúsculas o minúsculas, aunque es norma general dentro del OS-9 que los nombre de los directorio se escriban con todas sus letras en mayúsculas, mientras que los nombres de los ficheros utilizan las minúsculas. /h0 ──┬─── C ────── SOURCE ├─── CMDS ─── BOOTOBJS ├─── DEFS ─── MACHINE ├─── GCLOCK ├─── IO ─┬─── ISCSI │ ├─── ISIO │ ├─── RB1772 │ ├─── RBISCSI │ ├─── RBSCCS │ ├─── RBVIPER │ ├─── SCSI8703 │ └─── WFC ├─── LIB ├─── MACROS ├─── SYS ├─── SYSCACHE ├─── SYSMODS └─── USERS Descripción de los directorios principales: C Contiene el código fuente Cstart y un ejemplo de un "trap handler" con fines

didácticos. CMDS Contiene los códigos ejecutables de todas las utilidades del sistema. Es el directorio

en donde encontraremos por lo tanto todos los comandos del sistema. DEFS Contiene los ficheros de definiciones que son utilizadas por los distintos lenguajes de

programación. IO Contiene los códigos fuentes de los descriptores que son utilizados para configurar el

sistema. LIB Contiene las librerías del sistema. MACROS Contiene distintos macros como drivers y file manager. Estos macros están

diseñados para ser de propósito general. SYS Contiene ficheros del sistema Errmsg Son los textos asociados a cada mensaje de error. password Define los usuarios y grupos del sistema.

termcap Base de datos tipo ASCII que contiene una descripción de las

características de los terminales. motd Mensaje de bienvenida. SYSMODS Contiene los códigos fuente de los módulos "init" y "sysgo" con los cuales podremos

configurar el sistema según nuestras necesiadades.

2.3 Introducción al Shell. Cada sistema operativo tiene un interpretador de comandos. Este interpretador de los comandos escritos por el usuario es el Shell. Las misiones básicas son dos 1) Aceptar comandos interactivamente desde el teclado. 2) Leer un fichero texto en el cual se encuentran los comandos que desean ser ejecutados

(fichero de procedimiento). Los comandos serán ejecutados como si se escribiesen directamente desde el teclado.

Cuando el shell está listo para recibir un comando mostrará el "prompt" que por defecto posee el valor ($), pudiendo ser éste modificable por el usuario. La primera palabra de cualquier línea de comandos es el nombre del propio comando. Es indistinto que se escriba el nombre del fichero en mayúsculas. Existen tres tipos de comandos: * una utilidad del OS-9. * un programa de usuario. * un fichero de procedimiento. La mayoría de los comandos pueden manejar parámetros adicionales y opciones. $ comando [-opciones] [parámetros] [-opciones] Parámetros: son separados por espacios. Opciones: son precedidas por el símbolo '-'. Al invocar cualquier comando con la

opción '-?' nos presentará un help en pantalla. Ejemplos: a) $ dir -e *.c b) $ dir -x c) $ list /h0/startup

2.4 Edición de la Línea de Comandos.

El OS-9 al igual que la mayoría de los sistemas operativos está orientado a trabajar en modo línea. Esto significa que podremos editar una línea de comandos y al presionar <return> pasará a ser ejecutada. Las teclas de control de edición son: <Ctrl>A Repite la línea previa. <Ctrl>D Realiza el redisplay de la línea actual. <Ctrl>H Borra el carácter anterior. <Ctrl>Q Reactiva la entrada y salida parada por <Ctrl>S. <Ctrl>S Detiene las entradas y salidas hasta presionar <Ctrl>Q. <Ctrl>W Detiene temporalmente la salida para que pueda ser leida la pantalla. <Ctrl>X Borra toda la línea en curso. <Esc> <Ctrl>[ Indica el final de un fichero <Ctrl>C Envía una interrupción al programa más reciente. Habitualmente para el programa o

lo envía a background. <Ctrl>E Aborta el programa en curso.

2.5 Comandos Básicos y Utilidades. En función de la frecuencia de uso de los distintos comando y utilidades del sistema, podemos clasificar a éstos en cuatro grupos. Comandos Básicos: Son aquellos comandos indispensables que se van a manejar con mayor frecuencia por

cualquier tipo de usuario. Comandos Frecuentes: Son comandos de uso relativamente corriente, y que son necesarios conocer. Utilidades de Programación Avanzada: Estas utilidades son propias de los usuarios que desarrollen programas ya sean en C o en

Ensamblador. Utilidades para la Gestión del Sistema: Estas utilidades son propias del "System Manager". Por lo tanto un usuario normal no las

utilizará. El OS-9 incluye un comando help que nos permite obtener información sobre cada uno de los comandos y utilidades del sistema. Su forma de utilización es muy simple, basta con escribir help y a continuación el nombre del comando.

$ help comando Una segunda forma de obtener una información de ayuda de un comando es invocar al comando con la opción (-?). El mensaje de ayuda que nos muestra el sistema es el mismo que en el caso anterior. $ comando -? Utilización del Shell $ help dir <return> Syntax: dir [<opts>] {<dir names> [<opts>]} Function: display directory contents Options: -a show all files -d show directories with a slash -e extended dir listing -n treat dirs like files -r recursive dir listings -r=<num> recursive dir listing to depth <num> -s unsorted dir listing -u unformatted listing -x directory is execution dir -z read dir names from stdin

Comandos Básicos backup chd chx copy date del deldir dir dsave format help list rename setime Comandos Frecuentes attr build echo edt free kill logout makdir merge mfree pd procs set shell w wait Utilidades de Programación Avanzada. binex cfp cmp code compress count dump

ex exbin expand frestore fsave grep load make pr printenv qsort save setenv tape tee tmode touch tr unsetenv

Utilidades de Gestión del Sistema break dcheck devs deiniz events fixmod ident iniz irqs link login mdir moded os9gen romsplit setpr sleep tsmon unlink xmode

2.6 Formateo de un Disco y Backup. La manera de formatear un disco es mediante la utilización del comando format. Este comando nos permite formatear tanto disco duros como floppys. Los parámetros que podemos utilizar son los siguientes:

Información de ayuda del comando format. $ format -? <return> Syntax: format [<opts>] <devname> [<opts>] Function: format disk media Options: -c=<num> cluster size (1) -dd double density disk -ds double sided disk -e display elapsed verify time -i=<num> interleave offset value -np inhibit physical format -nv inhibit physical verify -nf inhibit fast mode verify -r ready (don't ask) -sd single density -ss single sided -t=<num> number of cylinders (tracks) -v=<name> volume name

Para sistemas con un sólo floppy debemos cargar el comando en memoria antes de formatear el disco. $ load format $ format /d0 -ds -dd Para asignar un volumen al disco debemos utilizar la opción -v. Se permite un máximo de 32 caracteres en el nombre de volumen, permitiendose que contengan también caracteres de espacio. $ format /d0 -ds -dd -v="Disco_de_sistema" $ format /d0 -ds -dd "-v=Disco de sistema" Una vez que comienza al ejecutarse el comando, presenta en pantalla la información sobre los pasos seguidos.

Formateo de un floppy

$ format /d0 -dsdd "-v=Curso OS-9" -t=77 <return> Disk Formatter OS-9/68K V2.3 Force SYS68K/CPU-30 - 68030 ------------ Format Data ------------ Fixed values: Disk type: 5" floppy Sectors/track: 16 Track zero sect/trk: 16 Minimum sect allocation: 8 Variables: Recording format: MFM all tracks Track density in TPI: 96 Number of cylinders: 77 Number of surfaces: 2 Sector interleave offset: 1 Formatting device: /d0 proceed? y <return> [[q para abortar]] verifying media, building bitmap... 000 001 002 003 004 005 006 007 008 009 00a 00b 00c 00d 00e 00f 010 011 012 013 014 015 016 017 018 019 01a 01b 01c 01d 01e 01f 020 021 022 023 024 025 026 027 028 029 02a 02b 02c 02d 02e 02f 030 031 032 033 034 035 036 037 038 039 03a 03b 03c 03d 03e 03f 040 041 042 043 044 045 046 047 048 049 04a 04b 04c 04d 04e 04f 050 051 052 053 054 055 056 057 058 059 05a 05b 05c 05d 05e 05f 060 061 062 063 064 065 066 067 068 069 06a 06b 06c 06d 06e 06f 070 071 072 073 074 075 076 077 078 079 07a 07b 07c 07d 07e 07f 080 081 082 083 084 085 086 087 088 089 08a 08b 08c 08d 08e 08f 090 091 092 093 094 095 096 097 098 099 quantity good $000009a0 2464 ( 0630784 bytes) quantity bad $00000000 0 ( 0 bytes) quantity unusable $00000000 0 ( 0 bytes) sectors verified $000009a0 2464 ( 630784 bytes) writing root directory structure

BACKUP El procedimiento de backup sólo puede realizarse sobre disco que han sido previamente formateados. Este comando permite copiar cualquier cosa desde un disco a otro que tenga su misma estructura. Existen otras formas para copiar ficheros pero esta es la más simple. El proceso de backup tiene dos etapas: 1) Lectura de una porción del disco fuente en un buffer en memoria y escritura en el disco de

destino.

2) Verificación de los datos copiados en el disco de destino. Las opciones que permite este comando son las siguientes:

Información de ayuda del comando backup

$ backup -? <return> Syntax: backup [<opts>] [<srcpath> <dstpath>] [<opts>] Function: backup disks Options: -b=<size> use larger buffer (default is 4k) -r don't exit if read error occurs -v do not verify

2.7 Ejercicios. 3.a.- Proceder al arranque del equipo siguiendo las directrices indicadas en el apartado 3.1.-

Arranque del OS-9. Arrancar el equipo desde el floppy número 1 del sistema operativo y proceder a comprobar la existencia de los directorios principales del OS-9 en los distintos floppys del sistema. Utiliar el comando $ dir -e -r.

3.b.- Formatear un floppy y realizar una copia de seguridad de los de los discos del sistema

operativo. Seguir las indicaciones del apartado 3.6.- Formateo de Discos y Backups 3.c.- Utilizando el comando list ver el contenido del fichero startup.

3 El Sistema de Archivos.

3.1 Tipos de Archivos. La manipulación física de los archivos, en cualquier tipo de sistema operativo depende del tipo de éstos. En OS-9 existen cuatro tipos de archivos: Ficheros de texto: Contienen líneas de caracteres ASCII de longitud variable, terminando cada línea con un

retorno de carro ($0D). Ficheros con módulos de programa ejecutable: Son los ficheros en donde se almacenan los programas creados por los ensambladores o

compiladores. Pueden contener uno o más módulos con un formato especial que utiliza el OS-9. Se caracterizan por ser módulos reubicables y poseer código reentrante.

Ficheros de datos: Estos ficheros contienen datos de acceso aleatorio. Son creados fundamentalmente por los

lenguajes de alto nivel como el C, Pascal o Fortran para almacenar variables de programa. Directorios: Los directorios son ficheros especiales que son tratados de manera distinta a los demás. Cuando un fichero o un directorio es creado automáticamente se almacena en él un identificador del usuario que lo ha creado (group.user ID). Este identificador está formado por el número del grupo del usuario y por el número que identifica al usuario. En OS-9 existen dos clases de usuarios: Propietario (Owner): Es cualquier usuario que pertenezca al mismo grupo de la persona que creó el fichero. Público (Public): Es cualquier usuario que pertenezca a un grupo distinto al de persona que creo el fichero. Como en otros sistemas operativos, la persona que tiene por identificador 0.0 se la denomina super usuario del sistema, y tiene prioridad para acceder a todos los ficheros y recursos del sistema. Además del identificador del usuario, cada fichero posee ocho atributos en los que se basa la seguridad del sistema. Estos atributos son representados en una línea de ocho caracteres. Entendemos por permiso cuando uno de estos atributos está activado con lo que nos aparecerá una letra en la lista. Si por el contrario ese atributo está desactivado encontraremos un guión (-).

Aquí tenemos la lista de atributos de un directorio que posee todos los permisos: dsewrewr │││││││└> r El propietario puede leer (Read) el fichero. ││││││└─> w El propietario puede escribir (Write) el fichero. │││││└──> e El propietario puede ejecutar (Execute) el fichero. ││││└───> pr El público puede leer. │││└────> pw El público puede escribir. ││└─────> pe El público puede ejecutar el fichero. │└──────> s Sólo puede estar abierto por un usuario a la vez. └───────> d Es un directorio.

Permisos

$ dir -e <return> Directory of /d0 15:51:37 Owner Last modified Attributes Sector Bytecount Name ------- ------------- ---------- ------ --------- ---- 0.0 89/11/15 1117 d-ewrewr 1EA 1824 CMDS 0.0 89/11/15 0818 ------wr 5 60484 OS9Boot 0.0 89/11/15 0819 ------wr F3 60484 OS9Boot.h0 0.0 89/11/15 1121 d-ewrewr 87F 288 SYS 0.0 89/07/21 1302 ------wr 1E1 912 init.ramdisk 0.0 89/07/21 1350 ------wr 1E6 694 startup

3.2 Estructura de Directorios del OS-9. El OS-9 utiliza una organización de ficheros jerárquica o en árbol. Para cada dispositivo que almacena información como los discos existe un directorio principal que se le denomina root. De este directorio "cuelgan" los distintos subdirectorios. El número de subdirectorio permitidos en un disco depende exclusivamente de la cantidad de espacio disponible.

ROOT │ ┌─────────────────┬───────────┴───────────────┬──────────────────┐ │ │ │ │ fichero SUBDIRECTORIO SUBDIRECTORIO fichero │ │ ┌────────────┬──┴────────┐ ┌─────────┴─┬───────────┐ │ │ │ │ │ │ fichero SUBDIRECTORIO fichero fichero SUBDIRECTORIO fichero │ │ fichero fichero Cada usuario o proceso siempre tiene asociado dos directorios Directorio de datos actual: Es el directorio en donde uno almacena y crea ficheros de texto. Se denomina actual porque

es posible moverse a través de la estructura de arbol de los directorios. Directorio de ejecución actual: El el directorio en donde se van cargando los ficheros ejecutables tales como comando o

utilidades que cada usuario va creando. Por defecto es el directorio CMDS, pero puede ser modificado como veremos más adelante.

3.3 Acceso a los Archivos y Directorios. Todos los ficheros y directorios pueden ser accedidos especificando el nombre del fichero o directorio después del comando oportuno. Existen dos formas de acceder a los ficheros o directorios Forma absoluta: /h0/SYSMODS/init.a /h0/CMDS/dir Forma relativa: .../file1 . Se refiere al directorio actual .. Se refiere al directorio padre del actual. ... Directorio de dos niveles de jerarquía superior. .... Directorio de tres niveles de jerarquía superior. etc. / Se avanza un nivel en la jerarquía.

3.4 Comandos Orientados a la Manipulación de Archivos.

Los comandos básicos para la manipulación de archivos permiten ser utilizados conjuntamente con las formas absolutas y relativas que vimos en el apartado anterior y son los siguientes: DIR El comando dir permite mostrar el contenido de los directorios. Permite especificar el

directorio indicando éste de forma absoluta o relativa. las opciones más utilizadas son dir -e Nos muestra el directorio de forma extendida dir -r Con esta opción podremos ver el contenido del directorio en cuestión y el de los

subdirectorios. dir -x Muestra el contenido del directorio de ejecución. CHD Y CHX Con el comando chd podemos movernos a través de la jerarquía de directorios, es decir

cambiamos el directorio de datos actual. Con el comando chx podremos cambiar el directorio de ejecución, es decir el directorio en

donde se van a buscar los comandos que se tecleen. PD Muestra el directorio en el cual estamos situados. MAKDIR Nos permite crear nuevos directorios. LIST Permite ver el contenido de los ficheros ASCII, Este comando es por lo tanto equivalente al

"cat" de UNIX. COPY Permite duplicar ficheros. Por defecto se utiliza un buffer de 4K de memoria. A la hora de

trabajar se recomienda por lo tanto ajustar este valor en función de la disponibilidad de memoria del sistema.

DSAVE

Este comando es utilizado para copiar todos los ficheros y directorios en el directorio

especificado mediante la generación de un fichero de procedimientos. Para que se ejecute ese comando automáticamente hay que utiliza la opción "-e".

DEL y DELDIR Estos comandos nos permiten borrar ficheros y directorios respectivamente. ATTR Permite examinar y modificar los atributos de un fichero. CREANDO FICHEROS BUILD Es utiliza para crear pequeños ficheros de texto. Se invoca al comando con el nombre del

fichero que se desea crear y se escribe el texto detrás del prompt "?". Al escribir un carriage return detrás del prompt se termina la creación del fichero.

EDT Es un editor de línea. UMACS Es un editor de pantalla que permite la utilización de múltiples buffers, pudiendo presentar

varios ficheros simultáneamente en pantalla.

3.5 Reglas para la Asignación de Nombres de Ficheros. Las reglas para la creación de nombres de ficheros y directorios son las mismas: 1 Un nombre de fichero puede contener de 1 a 28 letras mayúsculas o minúsculas. Se puede

comenzar con una letra o con un número. 2 Los símbolos permitidos son: Mayúsculas A <-> Z Minúsculas a <-> z Dígitos 0 <-> 9 Underscore _ Punto . Dolar $ 3 Los nombres en mayúsculas y minúsculas son considerados iguales file == FILE 4 No pueden contener espacios, en lugar de eso se pueden incluir puntos "." y underscore "_".

5 Los ficheros que comienzan con un punto se encuentran ocultos al realizar un "dir", a no ser

que se utilice la opción "-a".

3.6 Atributos de los Ficheros. Cuando se crea un fichero los permisos que están válidos por defecto son la lectura y escritura por parte del propietario. Es este punto hay que recordar que los usuarios que poseen el mismo grupo que la persona que ha creado el fichero se consideran propietarios de éste.

Información de ayuda del comando attr

$ attr -? <return> Syntax: attr [<opt>] {<path> [<opts>] <permissions>} Function: display or change file attributes Attributes: d s pe pw pr e w r '-' turns attribute on '-n' turns attribute off Options: -a do not print attributes after changes -x directory to search is execution directory -z get list of file names from standard input -z=<path> get list of file names from <path>

Ejemplos: $ attr fichero ------wr $ attr fichero -pw -pr -ne -npe -pw permite escritura pública -pr permite lectura pública -ne Anula permiso de ejecución al usuario. -npe Anula permiso de ejecución pública.

3.7 Ejercicios. 4.7.a.- Comprobar que nuestro equipo de trabajo dispone de disco duro y que se encuentra

adecuadamente formateado. En caso contrario formatear el disco duro siguiendo las instrucciones del manual de instalación del equipo y proceder luego a cargar el sistema operativo.

4.7.b.- Crear los directorios de trabajo /h0/USERS/CURSO y /h0/USERS/CURSO/CMDS. 4.7.c.- Copiar en el directorio /h0/USERS/CURSO/CMDS los comandos del sistema que se

encuentran en el directorio /h0/CMDS y utilizar el comando chx para indicar que este será nuestro nuevo directorio de ejecución.

4.7.d.- Utilizar el comando attr para cambiar los atributos de los comandos que hemos copiado en

nuestro directorio particular de ejecución.

4 El Shell.

4.1 La Función del Shell. El Shell es el programa interpretador de comandos del OS-9. Su función principal es la de permitir la edición de la línea de comandos para convertirlos en comandos que entiende el sistema operativo y ejecutarlos. De esta forma podemos utilizar comandos tales como procs o dir sin necesidad de conocer la estructura interna del OS-9. El Shell también permite configurar el entorno de trabajo de un usuario.

4.2 Opciones del Shell. -e=<fichero> Utiliza el fichero indicado para la impresión de los mensajes de error. Este fichero

ASCII usado por defecto es /h0/SYS/errmsg. Si no se indica ningún fichero de mensajes de error, siempre que se produzca un error se imprimirá en pantalla el número que le corresponde. En caso contrario el sistema operativo lee en este fichero el mensaje que corresponde con cada número y lo imprime en pantalla.

-ne No imprime mensajes de error. -l Obliga a que para terminar una sesión del shell se ejecute el comando logout. -nl La presencia del código <eof> provoca la conclusión de la sesión. La forma

normal de provocar un <eof> es presionando la tecla <Esc> (defecto).

-p Muestra el prompt. El valor por defecto es "$". -p=<string> Actualiza el prompt al string indicado. -np No muestra el prompt. -t Fuerza el echo de la línea de entrada. -nt No realiza el echo de la línea de entrada (defecto). -v Modo Verboso: muestra un mensaje de cada directorio buscado cuando se

ejecuta un comando. -nv Desactiva el Modo Verboso (defecto). -x Aborta un proceso cuando se produce un error (defecto). -nx No aborta un proceso cuando se produce un error. Las opciones del shell pueden ser cambiadas mediante dos métodos 1) Invocando a la opción directamente. 1.a) Sobre el propio shell: $ -np 1.b) Creado un shell nuevo: $ shell -np 2) Utilizando el comando especial set del shell. 2.a) Sobre el propio shell: $ set np 2.b) Creado un shell nuevo: $ shell set np Al crear un shell nuevo sobre otro actual conseguimos tener un entorno nuevo que al salirnos de él, retornamos al anterior.

4.3 Variables de Entorno. El shell mantiene una lista única de variables de entorno para cada uno de los usuario del sistema. Todas la variables de entorno pueden ser accedidas por cualquier proceso que corra sobre el shell actual o sobre shells descendientes. De esta forma conseguimos tener variables globales. Los comandos con los que podemos manipular esta variables son tres: setenv Declara variables y actualiza sus valores. unsetenv Limpia el valor de la variable y elimina a ésta de la lista de las variables activadas. printenv Imprime la variables existente y sus valores actuales.

Cuatro variables de entorno son inicializadas automáticamente cuando nos conectamos en un sistema multiusuario PORT Especifica el nombre del terminal. Esta variable es automáticamente inicializada por

la utilidad tsmon. Los valores suelen ser /term para la consola del sistema y /t1, /t2, ... para el resto de los terminales.

$ printenv PORT <return> PORT /term HOME Especifica el directorio raíz de cada usuario. Es el directorio indicado el

fichero password y el directorio de datos cuando nos conectamos al sistema. $ printenv HOME <return> HOME /h0/users/username SHELL Indica el primer proceso ejecutado al conectarnos al sistema. USER Nombre del usuario. $ printenv <return> .... USER username .... Otras variables PATH Indica los directorio en los que se buscarán los comandos a ejecutar. Es una lista de

directorio separados por dos puntos (:). $ setenv PATH ..:/h0/cmds:/d0/cmds:/h0/users/username/cmds PROMPT Especifica el prompt actual. Si en el prompt introducimos el carácter especial (@) al

verlo en pantalla será sustituido por la variable de entorno _sh que nos indica el número de nivel del shell en el cual nos encontramos.

$ set p=newprompt $ -p="@newprompt: " _sh Especifica el número de niveles de shell. $ setenv _sh 0 <return> $ -p="@user: " <return> user: shell <return> 1.user: shell <return> 2.user: logout <return> 1.user: logout <return> user:

TERM Esta variable especifica el tipo de terminal que se está empleando. Es utilizada por los editores de textos que trabajan en modo pantalla y por todos aquellos programas que accedan a la librería termcap.

$ setenv TERM=vt100

4.4 Comandos Internos del Shell. Hemos visto hasta el momento un variado número de comandos. Existen dos grandes grupos de comandos 1) Los comandos internos del shell que no necesitan ser cargados desde ningún directorio ya

que se encuentran implementados en el propio módulo del shell. 2) Los comandos externos que son cargados desde un directorio en memoria y posteriormente

ejecutados. Aquí presentamos la lista completa de los comandos internos del shell, aunque muchos de ellos ya son conocidos. * <texto> Es el carácter que indica que lo que viene a continuación es un

comentario. Es usado en los ficheros de procedimientos. chd <path> Cambia el directorio de datos actual. chx <path> Cambia el directorio de ejecución actual. ex <nombre> Ejecuta directamente el programa indicado. El programa corre sobre

un nuevo shell. kill <proc ID> Aborta los procesos indicados por <proc ID>. logout Termina el shell actual. Si al salir se termina un shell de login, se busca el

fichero .logout en el directorio indicado por la variable HOME y se ejecuta si existe.

set <opción> Cambia las opciones del shell. setenv <var> <val> Cambia las variables de entorno al valor indicado. setpr <proc ID> <pri> Cambia las prioridades de los procesos. unsetenv <var> Elimina variables del entorno. w Espera hasta que un proceso hijo termine. wait Espera hasta que todos los procesos hijos terminen.

4.5 Sintaxis de la Línea de Comandos del Shell. Aquí vamos a ver como el shell lee y procesa la línea de comandos. En toda línea de comandos el shell podrá identificar y procesar cualquiera de la distintas partes que pueden estar presentes: Palabras clave Es un nombre de programa, fichero de procedimientos, comando interno del

shell o pathlist. Parámetros Son nombres de ficheros, programas, valores, variables o cualquier otro dato

que se pasa a un programa ejecutable. Modificadores # tamaño de memoria adicional ^ prioridad de procesos > redireccionamiento de la salida < redireccionamiento de la entrada >> redireccionamiento de la salida de errores Separadores ; ejecución secuencial & ejecución concurrente ! construcción de un pipe Wildcards * indica cualquier carácter ? indica un carácter simple Agrupadores ( Comienzo agrupación ) Final agrupación

4.5.1 Modificadores. Modificadores de Memoria Adicional: Cuando un programa ejecutable es procesado por el shell, se reserva una cantidad mínima de memoria de trabajo. Es posible aumentar la cantidad de memoria que se la asigna a un proceso en múltiplos de 1k byte. Para ello de utiliza el modificador (#), seguido de un número que indica la cantidad de k bytes: #10k o #10. Modificadores de Redirección: Estos modificadores son utilizados para redireccionar la salida y entrada estándar de un programa a un fichero o a un dispositivo. > redireccionamiento de la salida (pantalla por defecto) < redireccionamiento de la entrada (teclado por defecto) >> redireccionamiento de la salida de errores (pantalla por defecto) >- redirecciona a un fichero. Si éste existe lo vuelve a crear. >+ redirecciona a un fichero. Si éste existe añade al final.

Los nombres de los dispositivos físicos de E/S soportados por el sistema son los siguientes: term Consola del sistema t1, t2, etc. Terminales serie adicionales. p Impresora paralela. p1 Impresora serie. dd Disco por defecto. d0, d1, etc. Floppys. h0, h1, etc. Discos duros. h0fmt, h1fmt, etc Discos duros (se utilizan para formatear). n0, n1, etc. Nodos de red. mt0, mt1 Cintas. r0 Ram disk. Ejemplos: $ list fichero >/p $ dir -e >/h0/USERS/directorio $ shell <>>>/t1 Los modificadores de redirección pueden ser utilizados antes y/o después de los parámetros del programa, pero sólo pueden ser utilizados una vez en la línea de comandos. Entre el modificador de redirección y el dispositivo indicado no se deben dejar espacios en blanco. Modificadores de Prioridad de los Procesos: Estos modificadores asignan una edad determinada a un proceso a la hora de su creación. La edad de un proceso es un número entre 0 y 65535, e indica cuanto tiempo ha esperado un proceso para ejecutarse y si prioridad inicial. Ejemplos: $ format /d1 ^255 En un sistema multiusuario, el system manager asigna la prioridad inicial de cada usuario en el fichero password. En un sistema de un solo usuario la prioridad se asigna en el módulo init. Todos los procesos hijo adquieren la prioridad de sus proceso padre. A la hora de utilizar este modificador hay que tener en cuenta que si asignamos una edad muy alta a un proceso, por ejemplo 2000, si existen otros con prioridad baja, éstos quedarán parados hasta que nuestro proceso termine o hasta que otros procesos alcancen esta edad.

4.5.2 Separadores. En una línea de entrada pueden estar incluidos más de una línea de comandos. Esta líneas de comandos pueden ser ejecutadas secuencial (separador ;) o concurrentemente (separador &). Además existen otro tipo de separadores concurrentes denominados pipes.

Ejecución Secuencial: Aquí los comandos son ejecutados uno detrás de otro, no apareciendo el prompt hasta que

no se termina de procesar toda la línea. $ dir >/h0/fichero1 ; list /h0/fichero1 >/p1 ; del /h0/fichero1 Ejecución Concurrente: El separador (ampersand &) permite correr a un programa simultáneamente con otros,

incluyendo el shell. $ dir >/p1& list fichero1& del fichero2 Los separadores (&) y (;) pueden ser utilizados simultáneamente en la misma línea Las pipes y los filtros: Una tercera clase de separador es el carácter de exclamación (!). Este separador permite

construir pipelines, que son dos o más procesos corriendo concurrentemente cuyas entradas y salidas estándar está conectadas por unos buffers tipo FIFO (First Input First Output) especiales denominados pipes. Las pipes automáticamente sincronizan la salida de un programa con la entrada de otro.

Pipes sin nombre: Son creados automáticamente por el shell cuando encuentra uno o más separadores (!) en la

línea de entrada. $ list fichero1 ! sort ! escribe_informe >/p1 Pipes con nombre: Son similares a las anteriores con la diferencia de que la información transitoria se almacena

en un buffer intermedio (directorio /pipe) que luego puede ser leido por cualquier otro proceso. El directorio /pipe puede ser tratado como cualquier otro directorio.

$ list fichero1 >/pipe/fichero1 $ copy /pipe/fichero1 /h0/USERS/CURSO/fichero1 Cuando el pipe /pipe/fichero1 está vacio (ha sido leido) es automáticamente eliminado. Filtros: Son programas especialmente para procesar datos como componente de un pipeline. Por

ejemplo el programa sort del ejemplo anterior.

4.5.3 Wildcards.

Son usados por el shell como manera alternativa para identificar los nombres de ficheros y directorios. (*) sustituye a un grupo de cero o más caracteres. (?) sustituye a un único carácter. Ejemplos: $ dir s* Lista todos los ficheros que comienzan con s. $ dir *.c Lista todos los ficheros fuentes del C. $ del * Borra todos los ficheros del directorio actual. $ del s?? Borra todos los ficheros que comiencen con s y que tengan en total tres

caracteres.

4.5.4 Agrupadores de Comandos. Podemos utilizar paréntesis para agrupar comandos. Estos permite a los modificadores y separadores ser aplicados sobre un conjunto de programas. $ (dir /h0; dir /d0) >/p1 $ dir /h0 >/p1 ; dir /d0 >/p1

4.6 Ficheros de Procedimientos. Los ficheros de procedimientos son fichero texto que contiene una o varias líneas de comandos que son idénticas a las introducidas en el teclado. El shell ejecuta cada línea como si fueran introducidas secuencialmente a través del teclado. Los objetivos de este tipo de ficheros son los siguientes: 1) Eliminar tareas repetitivas. 2) Permitir ejecutar una serie larga de programas que han de correr en background

mientras el usuario ejecuta otros programas en foreground. 3) Inicializar el entorno mediante ficheros de login . Los ficheros de procedimiento pueden correr también en background si utilizamos (&). Los procesos que corren en background no deben tener E/S a través del terminal, ya que causa confusión ya que pueden hacer varios procesos accediendo a éste concurrentemente. $ fichero_proc&

+4 Al correr un proceso en background el sistema devuelve un número que es el identificador del proceso. Cuando presionamos <control>C durante la ejecución de un fichero de este tipo el sistema automáticamente lo pone en modo background siempre y cuando el proceso no haya realizado aún ningún acceso de E/S al terminal. La utilización del <control>C puede provocar el aborto del proceso si se está efectuando alguna operación crítica en ese momento. Los Ficheros .login y .logout: Los ficheros .login y .logout son dos ficheros de procedimiento que poseen una misión especial dentro del sistema. Al ser ficheros que comienzan con un punto se encuentran ocultos al realizar un dir sin la opción -a. El fichero .login se ejecuta de forma automática (si existe) cuando un usuario en un sistema

multiusuario entra en su cuenta a través del comando login. El fichero .logout se ejecuta cuando el comando logout es ejecutado para abandonar el

sistema.

4.7 Sistemas Multiusuario. Para la instalación de un entorno multiusuario es necesaria la utilización del comando tsmon. El comando tsmon lo podemos encontrar típicamente como parte del fichero startup y se mantiene activo hasta que el sistema se cae. Tsmon es usado normalmente para crear los procesos de comunicación bidireccionales como los terminales. $ tsmon /t1 /t2 /t3& En la línea anterior se han instalado tres terminales, en los cuales ya podremos conectarnos como usuarios del sistema siempre y cuando el fichero /h0/SYS/password esté correctamente creado. El fichero Password El fichero password es un fichero especial que se encuentra en el directorio SYS. Mediante la introducción de nuevas líneas en este fichero podemos definir nuevos usuarios. Cada línea de este fichero debe tener siete campos los cuales pueden contener un punto (.), lo cual indica que el campo está vacio. Los campos son los siguientes: Nombre del usuario: Nombre del usuario que puede contener un máximo de 32 caracteres incluyendo espacios. Password: Clave del usuario que puede contener un máximo de 32 caracteres incluyendo espacios. Si

se omite este campo no se necesita password. Identificador de grupo y usuario: Grupo de dos números de 0 a 65535 que indica el grupo y el usuario respectivamente. El

identificador 0.0 es el superusuario.

Prioridad Inicial del Proceso: Indica la prioridad del proceso inicial. Directorio de Ejecución Inicial: Indica el directorio de comandos inicial. Por defecto su valor es /d0/CMDS. Directorio de Datos Inicial: Contiene el directorio que va a tener el usuario domo HOME. Por defecto es el root. Programa de Inicialización: Este campo contiene el nombre y los parámetros del programa que será ejecutado

inicialmente. Este programa es el shell por defecto. Ejemplos: superusuario,clave,0.0,255,.,.,shell -p="@Super: "

4.8 Ejercicios. 5.9.a.- Estudiar el editor de textos uMACS que se explica en el apartado 12. 5.9.b.- Utilizando el editor uMACS, modificar el fichero de password para crear un usuario

denominado curso, cuyo password será os9. El directorio raíz de trabajo de este nuevo usuario será:

DIRECTORIO HOME: /h0/USERS/CURSO Utilizando el fichero .login, configurar el prompt para que aparezca "curso: ". El terminal

por defecto sera vt100 y el fichero de errores que se va a utilizar ha de ser: MENSAJES DE ERROR: /h0/SYS/errmsg 5.9.c.- Crear un fichero denominado /h0/USERS/CURSO/listado que contenga un listado de toda la

estructura de directorios del disco duro y luego enviarlo a la impresora utilizando el comando list con el oportuno redireccionamiento.

5 Utilidades del Sistema. ATTR Syntax: attr [<opt>] {<path> [<opts>] <permissions>}

Function: display or change file attributes Attributes: d s pe pw pr e w r '-' turns attribute on '-n' turns attribute off Options: -a do not print attributes after changes -x directory to search is execution directory -z get list of file names from standard input -z=<path> get list of file names from <path> BACKUP Syntax: backup [<opts>] [<srcpath> <dstpath>] [<opts>] Function: backup disks Options: -b=<size> use larger buffer (default is 4k) -r don't exit if read error occurs -v do not verify BINEX Syntax: binex [<opts>] [<inpath>] [<outpath>] [<opts>] Function: convert file to S record format Options: -a=<num> specify load address -x get file from execution directory -s[=]<n> specify S-record type (1 is default) CFP Syntax: cfp [<opts>] [<procfile>] [<opts>] Function: command file arg replacement processor Options: -d delete procedure file -nd don't delete procedure file -e execute the procedure file -ne don't execute - just dump to stdout -s=<string> use <string> instead of reading proc. file -z get list of modules from standard input -z=<file> get list of modules from <file> -t=<path> path list for temporary files CMP Syntax: cmp [<opts>] <path1> <path2> [<opts>] Function: compare two files Options: -b=<size> buffer size -s silent mode/aborts with error on first mismatch -x defaults to current execution directory COMPRESS Syntax: compress [<opts>] {<path> [<opts>]}

Function: compress an ascii file Options: -d delete original file -n create output file -z get list of file names from standard input -z=<path> get list of file names from <path> COPY Syntax: copy [<opts>] <srcpath> [<dstpath>] [<opts>] Function: copy data from one path to another Options: -a abort on error -b=<size> buffer size -p don't print file names copied (with -w option only) -r rewrite destination -v verify integrity of files written -w=<dir name> wild card copy to <dir name> -x look in execution directory for source COUNT Syntax: count [<opt>] {<path> [<opts>]} Function: count characters, lines, and words in a file Options: -b count characters with breakdown -c count characters -l count lines (default) -w count words -z read filenames from standard input -z=<path> reads filenames from <path> DATE Syntax: date [<opts>] Function: display system date and time Options: -j print day, seconds past midnight in julian time -m print hour:minute:sec in military format DCHECK Syntax: dcheck [<opts>] <devnam> Function: check directory/file integrity Options: -d=<num> print path to dir <num> deep DEINIZ Syntax: deiniz [<opts>] {<devname> [<opts>]} Function: detach devices Options: -z get list of device names from standard input

-z=<path> get list of device names from <path> DEL Syntax: del [<opts>] {<file> [<opts>]} Function: delete files Options: -p show file name and ask before deleting -x delete files from execution directory -z read file names from standard input -z=<path> read file names from <path> DELDIR Syntax: deldir [<opts>] {<dir> [<opts>]} Function: delete a directory Options: -q delete directories without asking questions -f delete files with no write permission -z get list of file names from standard input -z=<path> get list of file names from <path> DEVS syntax: devs [<opts>] function: print system device table options: (none available) DIR Syntax: dir [<opts>] {<dir names> [<opts>]} Function: display directory contents Options: -a show all files -d show directories with a slash -e extended dir listing -n treat dirs like files -r recursive dir listings -r=<num> recursive dir listing to depth <num> -s unsorted dir listing -u unformatted listing -x directory is execution dir -z read dir names from stdin DSAVE Syntax: dsave [<opts>] [<to path>] [<opts>] Function: copy directory structure Options: -a don't copy files beginning with '.' -b[<=>]<n> copy memory size

-d only copy files with newer dates -d=<date> copy files newer than <date> -e execute output -i indent directory levels -l current directory only -m omit makdirs -n don't load copy -o OS9Gen on boot file -o=<n> OS9Gen with given bootfile name <n> -r use rewrite option on copy -s skip file on error; no 'continue?' prompt -v verify files with cmp DUMP Syntax: dump [<opts>] <path> [<starting byte>] [<opts>] Function: formatted display of contents of a device Options: -c don't compress duplicate lines -x path implies execution directory ECHO Syntax: echo [<opts>] [<text>] [<opts>] Function: echo text to output path and convert hex to ASCII Options: -n separate text with carriage returns -r don't send out a return on exit -z get text from standard input -z=<file> get text from <file> EDT Syntax: edt [<opts>] <path> [<opts>] Function: line editor Options: -b=<size> use larger buffer (default is 2k larger than file size) Commands: <cr> - move line pointer down one line <num> - move to line <num> +[<num>] - move line pointer down <num> lines(default: 1) -[<num>] - move line pointer up <num> lines(default: 1) c - search/replace from current line d[<num>] - delete lines(default: 1) l[<num>] - list <num> lines(default: 1) s - search from current line <space> - insert line <esc> or q - write file and return to shell EVENTS syntax: events function: display active events

options: none EXBIN Syntax: exbin [<opts>] [<inpath>] [<outpath>] Function: converts S record to binary file EXPAND Syntax: expand [<opts>] {<path>} [<opts>] Function: expand a compressed file Options: -d delete original file -n create output file -z get list of file names from standard input -z=<path> get list of file names from <path> FIXMOD Syntax: fixmod [<opts>] {<modname> [<opts>]} Function: fix module CRC and parity Options: -ua[=]<att.rev> fix module attribute/revision word -ub fix sysrev field for BASIC subroutine modules -uo[=]<grp.usr> change the module owner id -up[=]<hex perm> change module permissions -u update invalid module parity and CRC -x fix module in execution directory -z get list of module names from standard input -z=<path> get list of module names from <path> FORMAT Syntax: format [<opts>] <devname> [<opts>] Function: format disk media Options: -c=<num> cluster size (1) -dd double density disk -ds double sided disk -e display elapsed verify time -i=<num> interleave offset value -np inhibit physical format -nv inhibit physical verify -nf inhibit fast mode verify -r ready (don't ask) -sd single density -ss single sided -t=<num> number of cylinders (tracks) -v=<name> volume name FREE

Syntax: free [<opts>] {<device> [<opts>]} Function: report free space on disk Options: -b=<size> buffer size RESTORE Syntax: frestore [-opts] [to-path] [-opts] Function: Restores a directory structure from multiple volumes of tape or disk media. Options: -d[=]<devpath>: restore from alternate device -f[=]<path> : restore from a file. -b[=]<number> : set buffer size for writing files -x[=]<number> : pre-extend temporary file (kilo-bytes) -t[=]<dirpath>: specifies alternate location for temporary index file -v : just identify backup (volume) and terminate -i : identify backup and check for index on volume -e : echo index structure as it is read -s : restore without interactive shell -c : check validity of files without interactive shell -q : with "-s" option overwrite already existing files -p : supress prompt for first volume FSAVE Syntax: fsave [<opts>] [<dir names>] [<opts>] Function: Backs up directory structures to multiple volumes of tape or disk media. Options: -d[=]<devpath>: save to an alternate device (default is /mt0) -f[=]<path> : save to a file -m[=]<path> : specifies alternate backup dates file -t[=]<dirpath>: specifies alternate location for temporary index file -g[=]<number> : only save files owned by group -u[=]<number> : only save files owned by user -l[=]<number> : backup level between 0-9 -b[=]<number> : specifies buffer size in kilo-bytes -x[=]<number> : pre-extend temporary file (kilo-bytes) -e : don't echo file pathlists as they are saved -s : echo file names without doing the backup -p : turn off mount volume prompt for the first volume -v : turn off disk verify GREP Syntax: grep [<opts>] [<expression>] [<path>] [<opts>]} Function: searches input module for lines matching expression Options: -c count match lines -e=expr same as simple expression -f=file read 'file' for expression(s)

-l print only filenames with matches -n number each output line (file relative) -s silent mode -v invert sense of compare (list non-matches) -z accept search filenames from standard input -z=<path> accept search filenames from <path> HELP Syntax: help [<file>] {[<file>]} Function: Provide Help for OS-9/68000 Utilities To get help for a specific utility type: "help <filename>". IDENT syntax: ident [<opts>] {<modname> [<opts>]} Function: display module information Options: -m ident module in memory -q quick mode, only one line per module -s silent mode: quick, but only displays bad crcs -x ident module in execution directory -z get list of module names from standard input -z=<file> get list of module names from <file> INIZ Syntax: iniz [<opts>] {<devname> [<opts>]} Function: attach devices Options: -z get list of device names from standard input -z=<path> get list of device names from <path> DEVS syntax: devs [<opts>] function: display entries on system IRQ polling table options: (none available) LINK Syntax: link [<opts>] {<modname> [<opts>]} Function: link a module in memory Options: -z get list of module names from standard input. -z=<path> get list of module names from <path> LIST Syntax: list [<opts>] {<path> [<opts>]} Function: list a file Options:

-z get file names from standard input -z=<path> get list of file names from <path> LOAD Syntax: load [<opts>] {<module> [<opts>]} Function: load a module into memory Options: -d load file from data directory -l print pathlist of file loaded -z get list of module names from standard input -z=<path> get list of module names from <path> LOGIN Syntax: login [<opts>] <name> [,] <password> Function: to provide login security MAKDIR syntax: makdir [<opts>] {<dir name> [<opts>]} Function: create a directory Options: -x create directory in execution directory -z get list of dir names from standard input -z=<file> get list of dir names from <file> MAKE Syntax: make {[<-opts>] [< target file >] [< macros >]} Function: keep track of modules for a file Options: -b don't use built-in rules -bo don't use built-in rules for object files -d debug mode, print out the file dates in makefile -dd double debug mode, very verbose -f[=]<xxx> use <xxx> as the makefile (default: makefile) -f- reads the makefile from stdin -i ignore errors on commands and keep going -n don't execute commands, just print them out -s silent mode, execute commands without echoing them -t update the dates without executing the commands -u do the make whether it needs it or not -x use the cross compiler -z[=<path>] get list of files to make from stdin or path MDIR Syntax: mdir [<opts>] [<mod names>] Function: display module directory Options: -a print language instead of type -e print extended directory listing

-t=<type> list modules only of type <type> -u print unformatted listing MERGE Syntax: merge [<opts>] {<path> [<opts>]} Function: merge file to standard output Options: -b=<size> buffer size -x look in execution directory for files -z get list of modules from standard input -z=<path> get list of modules from <path> MFREE Syntax: mfree [<opt>] Function: display system memory information Options: -e extended free memory description MODED Syntax: moded [<opts>] <module name> [<opts>] Function: edit OS-9 modules. Options: -f=<file name> = look for module in file. default file name is same as module's. OS9GEN Syntax: os9gen {<opts>} <device> {<path>} {<opts>} Function: create boot on disk Options: -b=<size> copy buffer size -q=<path> quick gen .. set sector zero pointing to <path> -x pathlists relative to execution directory -z[=<path>] read list of files from standard input or <path> PD Syntax: pd [<opt>] Function: print path to data or execution directory Options: -x display execution dir path PR Syntax: pr [<opts>] {<path> [<opts>]} Function: display file in specified format Options : -c=char pick column separation character -f do not use form feed

-h=num set number of lines after header -k=num set number of columns -l=num set left margin -m print all open files one per column -n=num set starting line number and incr -o truncate lines longer than rmarg -p=num set number of lines per page -r=num set right margin -t do not print title -u=title use specified title (48 characters maximum) -x=num set starting page number -z[<=path>] read file names from stdin or <path> if given PROCS Syntax: procs [<opts>] Function: display user processes Options: -a display alternate data

-b display both normal and alternate data -e display every valid process QSORT Syntax: qsort [<opt>] {<file> [<opt>]} Function: in-memory quick sort Options: -c=<char> specify field separation character -f=<num> specify field to sort on -z read standard input for file names -z=<path> read path for file names

RENAME Syntax: Rename [<opts>] <path> <name> [<opts>] Function: rename a file or directory Options: -x path starts from execution dir

SAVE Syntax: save [<opts>] {<modname> [<opts>]} Function: save given modules to files Options: -f=<path> save list of modules to <path> -r rewrite files -x create output in execution directory -z get list of modules from standard input -z=<path> get list of modules from <path>

SETIME Syntax: setime [<opt>] [yy mm dd hh mm ss] [am/pm] Function: set system date and time Options: -d don't display time -s setime for battery backed-up clocks

SHELL Shell options: -e[=<path>] print error explanations. -ne don't print error explanations. -p[=<prompt>] print prompt. -np don't print prompt. -t echo input lines. -nt don't echo input lines. -x exit on error.

-nx don't exit on error. -l require "logout" to logout. -nl <eof> on input will logout. -v print attempts to execute command. -nv don't print attempts to execute command.

SLEEP Syntax: Sleep [<opt>] [count] Function: suspend process for ticks/seconds/until signalled Options: -s count represents seconds Note: Count defaults to 0 if not specified

TAPE Syntax: tape {<opts>} [<file>] {<opts>} Syntax: tape <device> Function: tape special functions, default device is /mt0 Options: -b[=<num>] skip 1 or <num> blocks (negative <num> is reverse) -e=<num> erase <num> blocks of tape ('*' is to EOT) -f[=<num>] skip 1 or <num> tapemarks (negative <num> is reverse) -o put tape offline -r rewind tape -s determine block size of device -t retension tape -w[=<num>] write 1 or <num> tapemarks -z[=<file>] read list of units from standard input or <file>

TEE Syntax: tee {<path>} Function: copy input to multiple output paths

TMODE Syntax: tmode [<opt>] {<parameter>} [<opts>] Function: display and/or change terminal operating characteristics Options: -w=<#path> specify path to perform operations on [no]upc - upper case only [no]bsb - erase on backspace [no]bsl - backspace over line [no]echo - echo input to terminal [no]lf - auto line feed [no]pause - screen pause null=n - number of null chars after CR pag=n - display page length bsp=h - input backspace char (in hex) bse=h - output backspace char (in hex) del=h - input delete char (in hex) eor=h - end of record char (in hex) eof=h - end of file char (in hex) reprint=h - reprint line character (in hex) dup=h - duplicate last line char (in hex) psc=h - pause char (in hex) abort=h - abort char (in hex) quit=h - quit char (in hex) bell=h - bell output char (in hex) type=h - ACIA initialization value (in hex) par=s - set parity (s=odd,even,none) cs=n - character size in bits (n=8,7,6,5) stop=n - number of stop bits (n=1,1.5,2) baud=n - software settable baud rate (in decimal) xon=h - DC1 resume output char (in hex) xoff=h - DC2 suspend output char (in hex) tabc=h - tab char (in hex) tabs=d - number of spaces per tab normal - return to default values

TOUCH Syntax: touch [<opts>] {<path> [<opts>]} Function: update the date of a file Options: -c don't create files

-q don't quit on error -x search execution directory -z get file names from standard input -z=<path> get list of file names from <path>

TR Syntax: tr [<opts>] <str1> [<str2>] [<path1>] [<path2>] [<opts>] Function: convert all occurrences of chars in <str1> to corresponding chars in <str2> -c : invert (complement) sense of characters in str1 -d : delete all characters matching str1 characters -s : squeeze repeated output chars from str2 into a single char -v : identical to 'c' option above -z : read input file names from standard input -z=<path> : read input file names from <path>

TSMON syntax: tsmon [<opts>] {<devname> [<opts>]} Function: monitor timesharing terminals for activity, start login Options: -d displays statistics when '^\' character is typed -l=<prog> forks an alternate "login" program -p displays an online prompt to each monitored terminal -r=<prog> forks an alternate "shell" for remote commands -z reads the device names from standard input -z=<path> reads the device names from <path>

UNLINK Syntax: unlink [<opts>] {<modname> [<opts>]} Function: unlink modules from memory Options: -z get list of module names from standard input -z=<path> get list of module names from <path>

XMODE Syntax: xmode [<opts>] <SCF descriptor name> {<SCF descr.> [<opts>]} Function: display/change options section of device descriptor Options: -z - get file names from standard input -z=<path> - get file names from <path> [no]upc - upper case only [no]bsb - erase on backspace [no]bsl - backspace over line [no]echo - echo input to terminal [no]lf - auto line feed [no]pause - screen pause on null=n - number of null chars after CR pag=n - display page length bsp=h - input backspace char (in hex) bse=h - output backspace char (in hex) del=h - input delete char (in hex) eor=h - end of record char (in hex) eof=h - end of file char (in hex) reprint=h - reprint line character (in hex) dup=h - duplicate last line char (in hex) psc=h - pause char (in hex) abort=h - abort char (in hex) quit=h - quit char (in hex) bell=h - bell output char (in hex) type=h - ACIA initialization value (in hex) par=s - set parity (s=odd,even,none) cs=n - character size in bits (n=8,7,6,5) stop=n - number of stop bits (n=1,1.5,2) baud=n - software settable baud rate (in decimal) xon=h - DC1 resume output char (in hex) xoff=h - DC2 suspend output char (in hex) tabc=h - tab char (in hex) tabs=d - number of spaces per tab normal - return to default values

6 Estructura Interna de OS-9. Introducción. El sistema operativo OS-9 tiene cuatro niveles de modularidad, tal como podemos ver en la Fig. 7.1.a. Estos niveles están compuestos por los siguientes módulos: NIVEL-1 El Kernel, el Clock y el módulo Init. Kernel: Maneja las E/S. Controla los procesos. Maneja los recursos del sistema. Clock: Es un manejador software del reloj hardware en tiempo real del sistema.

Init: Es una tabla de inicialización usada por el Kernel durante el arranque del

sistema. NIVEL-2 File Managers. Gestiona las solicitudes de E/S para dispositivos de E/S de una misma clase. NIVEL-3 Drivers de dispositivos. Los drivers manejan las funciones de E/S físicas para controladores específicos. Los

drivers típicos son los que manejan los discos, terminales e impresoras. NIVEL-4 Descriptores de dispositivos. Los descriptores son pequeñas tablas que asocian un puerto E/S específico con sus

nombre lógico, driver y file manager. Estos módulos contienen la direccción física del puerto y los datos de inicialización.

ORGANIZACION DE LOS MODULOS DEL OS-9 En realidad el Kernel no procesa las solicitudes de E/S directamente, sino que las pasa a los File Managers apropiados, siendo éstos los que acceden a los drivers correspondientes. Los File Managers básicos del OS-9 son los siguientes: RBF Random Block File Manager. Gestiona todos los dispositivos con estructura de bloque de acceso

random, como los diskettes y discos duros. SCF Sequential Character File Manager. Gestiona los dispositivos secuenciales tales como terminales,

impresoras y modems. SBF Sequential Block File Manager. Gestiona los dispositivos con estructura de bloque de acceso

secuencial como las cintas. PIPEMAN Pipe File Manager. Gestiona las comunicaciones entre procesos a través de buffers en memoria, lo que

se conoce como "pipes".

Fig. 7.1.a.

Fig. 7.1.b. Además de los File Managers básicos, existen otros que son suministrados de forma opcional por Microware. PCF PC File manager. Gestiona los procesos de lectura/escritura en diskettes en

formato PC-DOS. NFM Network File Manager. Procesa las solicitudes de datos a través de una Network

OS-9. ENPMAN ENP10 Socket File Manager. Se encarga de la transferencia a/desde tarjetas

CMC ENP10. Este File Manager está incluido dentro del Ethernet Support Package (OS-9/ESP).

SOCKMAN Socket File Manager. Crea y gestiona el interface a los protocolos de comunicación (sockets). Este File Manager está incluido dentro del Ethernet Support Package (OS-9/ESP).

IFMAN Communications Interface File Manages. Gestiona el interface de la Network.

Este File Manager está incluido dentro del Ethernet Support Package (OS-9/ESP).

PKMAN Pseudo-Keyboard File Manager. Provee un interface al SCF para permitir al

software emulador un terminal. Este File Manager está incluido dentro del Ethernet Support Package (OS-9/ESP).

PROCESO DE SOLICITUD DE UNA E/S En la Fig. 7.1.b. podemos ver cuales son los pasos que se realizan durante el procesos de solicitud de una operación de E/S. 1) El usuario a través de un proceso realiza una solicitud de E/S. 2) El Kernel identifica y valida la solicitud de E/S e identifica al File Manager, Driver y Descriptor apropiados para atenderla. A continuación pasa esa solicitud de E/S al File Manager correspondiente. 3) El File Manager valida la solicitud enviada por el Kernel y realiza la parte del proceso que es independiente del hardware. La parte del proceso dependiente del hardware se realizará mediante una llamada al Driver correspondiente. 4) El Driver realiza la operación de E/S que depende del dispositivo empleado y transfiere el dato al File Manager. 5) El File Manager recibe y procesa el dato enviado por el Driver y realiza si fuera necesario llamadas al Kernel para reservar memoría dinámicamente. 6) El Kernel envía al usuario el dato que había solicitado.

6.1 Estructura de un Módulo Básico. Un módulo de memoria puede ser una colección de datos, un segmento de un programa, un programa completo, etc. El OS-9 soporta hasta un total de diez tipos distinto de módulos, permitiendo al usuario definirse sus propios tipos de módulos. Las características primordiales de cualquier tipo de módulo son tres: 1) Poseer código reentrante. Lo que significa que no se permite que un código se modifique asimismo. 2) Ser independiente de la posición. Es decir, que no se utilicen modos de direccionamiento absolutos.

3) Poseer una estructura básica de módulo OS-9. Todo módulo ha de poseer una estructura compuesta de tres partes: Cabecera del módulo, Cuerpo del módulo y valor de CRC (Cyclic Redundancy Check). A la hora de programar el usuario no tiene que saber que todos los compiladores e interpretes que trabajan sobre OS-9 de encargan de generar código independiente de la posición. Lo único que tiene que tener en cuenta el programador es el de no utilizar modos de direccionamiento absoluto. Todos los módulos en OS-9 tienen siempre la misma estructura básica que se compone de: Cabecera del módulo: Contiene información que describe el módulo y su uso. Podremos encontrar información sobre tamaño, tipo de módulo, nombre del módulo, etc.. Cuerpo del módulo: El cuerpo del módulo puede contener datos de inicialización, programas, tablas de constantes, etc.. Valor de CRC: Los últimos tres bytes contienen el valor de CRC.

CABECERA DEL MODULO

PROGRAMAS O

DATOS CRC

Cuando comienza a ejecutarse el OS-9 después de un reset, el Kernel busca módulos OS-9 en ROM. Si detecta alguno, éste es incluido en la memoria. El proceso de detección se basa en buscar el código de sincronismo con que comienza todo módulo OS-9, luego se verifica toda la cabecera y se procede luego a comprobar el CRC del módulo. Si el proceso es correcto el módulo es incluido en el directorio de módulos. CAMPOS QUE COMPONEN LA CABECERA DE UN MODULO A continuación encontraremos una tabla en donde se describen todos los campos que componen la cabecera de un módulo OS-9. Hay que destacar que todos los tipos de módulos poseen una sección común de cabecera, existiendo luego una parte variable que dependerá del tipo del módulo. Los offset de cada uno de los campos de un módulo son siempre relativo al comienzo del módulo. Al ensamblar un código los offset de los campos del módulo son resueltos al "linkar" con las librerías sys.l y usr.l.

CABECERA DE UN MODULO OS-9 Offset Nombre Descripción del Campo ┌──────────┬────────────────────────────────────────┬────────────┐ $00 │ M$ID │ Byte de Sincronismo ($4AFC) │ │ ├──────────┼────────────────────────────────────────┤ │ $02 │ M$SysRev │ Identificación del formato del módulo │ │ ├──────────┼────────────────────────────────────────┤ │ $04 │ M$Size │ Tamaño del Módulo │ │ ├──────────┼────────────────────────────────────────┤ │ $08 │ M$Owner │ Identificación del Propietario │ │ ├──────────┼────────────────────────────────────────┤ │ $0C │ M$Name │ Offset al string del nombre del módulo │ │ ├──────────┼────────────────────────────────────────┤ │ $10 │ M$Accs │ Permisos de acceso │ │ ├──────────┼────────────────────────────────────────┤ │ $12 │ M$Type │ Tipo de módulo (oskdefs.d)│ CABECERA │ ├──────────┼────────────────────────────────────────┤ │ $13 │ M$Lang │ Lenguaje del módulo (oskdefs.d)│ STANDARD │ ├──────────┼────────────────────────────────────────┤ │ $14 │ M$Attr │ Atributos (reentrante,sticky,system)│ │ ├──────────┼────────────────────────────────────────┤ │ $15 │ M$Revs │ Nivel de revisión │ │ ├──────────┼────────────────────────────────────────┤ │ $16 │ M$Edit │ Release de la edición │ │ ├──────────┼────────────────────────────────────────┤ │ $18 │ M$Usage │ Offset a un string de comentarios │ │ ├──────────┼────────────────────────────────────────┤ │ $1C │ M$Symbol │ Tabla de símbolo (Reservado uso futuro)│ │ ├──────────┼────────────────────────────────────────┤ │ $20 │ │ Reservado │ │ ├──────────┼────────────────────────────────────────┤ │ $2E │ M$Parity │ Paridad cabecera (C'1 palabra previa)│<───────────┘ ╞══════════╪════════════════════════════════════════_──────┬─┬─┬─┐ $30 │ M$Exec │ Offset de ejecución │File │ │ │ │ ├──────────┼────────────────────────────────────────┤Mana./│ │ │ │ $34 │ M$Excpt │ Entrada User Trap │System│ │ │ │ ├──────────┼────────────────────────────────────────┤<─────┘ │ │ │ $38 │ M$Mem │ Tamaño de la memoria de datos │Driver │ │ │ ├──────────┼────────────────────────────────────────┤<───────┘ │ │ $3C │ M$Stack │ Tamaño mínimo del Stack │ │ │ ├──────────┼────────────────────────────────────────┤ │ │ $40 │ M$IData │ Offset a los datos inicializados │ │ │ ├──────────┼────────────────────────────────────────┤ │ │ $44 │ M$IRefs │ Offset a las referencias inicializadas │Programa │ │ ├──────────┼────────────────────────────────────────┤<─────────┘ │ $48 │ M$Init │ Offset ejecución de la inicialización │ │ ├──────────┼────────────────────────────────────────┤ │ $4C │ M$Term │ Offset ejecución de la terminación │Trap Manager│ ╞══════════╪════════════════════════════════════════_<───────────┘ │ │ │ │ │ │ │ │ │ │ │ Cuerpo del módulo │ │ │ │ │ │ │ │ │ │ ╞══════════╪════════════════════════════════════════╡ │ │ CRC │ └──────────┴────────────────────────────────────────┘

A la hora de programar las definiciones de los offsets de los distintos campos las podemos encontrar el los ficheros module.a (ensamblador) y module.h (C).

Fichero modules.a: Definición de los offsets de los módulos

* Universal Module Offsets org 0 M$ID: do.w 1 ID code M$SysRev: do.w 1 system revision check value M$Size: do.l 1 module size M$Owner: do.l 1 owner ID M$Name: do.l 1 name offset M$Accs: do.w 1 access permissions M$Type: do.b 1 type M$Lang: do.b 1 language M$Attr: do.b 1 attributes M$Revs: do.b 1 revision level M$Edit: do.w 1 edition number M$Usage: do.l 1 comment string offset M$Symbol: do.l 1 symbol table offset do.b 14 reserved M$Parity: do.w 1 header parity M$IDSize: equ . module ID size ** Type-Dependent Module Offsets * System, Program, Trap Handler, File Manager, Device Driver M$Exec: do.l 1 execution entry offset M$Excpt: do.l 1 exception entry offset * Program, Trap Handler, Device Driver M$Mem: do.l 1 data area requirement * Program, Trap Handler M$Stack: do.l 1 stack area requirement M$IData: do.l 1 initialized data ptr M$IRefs: do.l 1 initialized reference lists ptr * User Trap Handler M$Init: do.l 1 initialization execution offset M$Term: do.l 1 termination execution offset

Fichero module.h -- Definición de la estructura de la cabecera de un módulo /* OS-9/68k module header definitions */ #define VHPCNT (sizeof(struct modhcom)-2) /* sizeof common header */ #define MODSYNC 0x4afc /* module header sync code */ #define CRCCON 0x800fe3 /* crc polynomial constant */ /* Module access permission values */ #define MP_OWNER_READ 0x0001 #define MP_OWNER_WRITE 0x0002 #define MP_OWNER_EXEC 0x0004 #define MP_GROUP_READ 0x0010 #define MP_GROUP_WRITE 0x0020 #define MP_GROUP_EXEC 0x0040 #define MP_WORLD_READ 0x0100 #define MP_WORLD_WRITE 0x0200 #define MP_WORLD_EXEC 0x0400 #define MP_OWNER_MASK 0x000f #define MP_GROUP_MASK 0x00f0 #define MP_WORLD_MASK 0x0f00 #define MP_SYSTM_MASK 0xf000 /* Module Type/Language values */ #define MT_ANY 0 #define MT_PROGRAM 1 #define MT_SUBROUT 2 #define MT_MULTI 3 #define MT_DATA 4 #define MT_CSDDATA 5 #define MT_TRAPLIB 11 #define MT_SYSTEM 12 #define MT_FILEMAN 13 #define MT_DEVDRVR 14 #define MT_DEVDESC 15 #define ML_ANY 0 #define ML_OBJECT 1 #define ML_ICODE 2 #define mktypelang(type,lang) (((type)<<8)|(lang)) /* Module Attribute values */ #define MA_REENT 0x80 #define MA_GHOST 0x40 #define MA_SUPER 0x20 #define mkattrevs(attr, revs) (((attr)<<8)|(revs)) typedef unsigned short ushort; struct modhcom { short _msync, /* sync bytes ($4afc) */ _msysrev; /* system revision check value */ long _msize, /* module size */ _mowner, /* owner id */ _mname; /* offset to module name */ short _maccess, /* access permission */ _mtylan, /* type/lang */ _mattrev, /* rev/attr */ _medit; /* edition */ long _musage, /* comment string offset */ _msymbol; /* symbol table offset */ short _mident; /* ident code for ident program */ char _mspare[12]; /* reserved bytes */ short _mparity; /* header parity */ }; /* Executable memory module */ typedef struct { struct modhcom _mh; /* common header info */ long _mexec, /* offset to execution entry point */ _mexcpt, /* offset to exception entry point */ _mdata, /* data storage requirement */ _mstack, /* stack size */ _midata, /* offset to initialized data */ _midref; /* offset to data reference lists */ } mod_exec; /* device driver module */ typedef struct {

struct modhcom _mh; /* common header info */ long _mexec, /* offset to execution entry point */ _mexcpt, /* offset to exception entry point */ _mdata; /* data storage requirement */ short _mdinit, /* offset to init routine */ _mdread, /* offset to read routine */ _mdwrite, /* offset to write routine */ _mdgetstat, /* offset to getstat routine */ _mdsetstt, /* offset to setstat routine */ _mdterm, /* offset to terminate routine */ _mderror; /* offset to exception error routine */ } mod_driver; /* Device descriptor module */ typedef struct { struct modhcom _mh; /* common header info */ char * _mport; /* device port address */ unsigned char _mvector; /* trap vector number */ unsigned char _mirqlvl; /* irq interrupt level */ unsigned char _mpriority; /* irq polling priority */ unsigned char _mmode; /* device mode capabilities */ short _mfmgr; /* file manager name offset */ short _mpdev; /* device driver name offset */ short _mdevcon; /* device configuration offset */ unsigned short _mdscres[4]; /* (reserved) */ unsigned short _mopt; /* option table size */ unsigned char _mdtype; /* device type code */ } mod_dev; /* Configuration module */ typedef struct { struct modhcom _mh; /* common header info */ long _mmaxmem; /* top limit of free ram (unused) */ ushort _mpollsz, /* number of IRQ polling tbl entries */ _mdevcnt, /* number of device table entries */ _mprocs, /* number of process table entries */ _mpaths, /* number of path table entries */ _mioman, /* I/O manager name offset (unused) */ _msysgo, /* offset to initial module name */ _msysdrive, /* offset to system device name */ _mconsol, /* offset to system consol terminal name */ _mextens, /* offset to customization module name */ _mclock, /* offset to clock module name */ _mslice, /* number of clock ticks per time slice */ _musract; /* offset to user accounting module name */ long _msite; /* installation site code */ ushort _minstal; /* installation name offset */ long _mcputyp; /* cpu class (68000/68010/68020) */ char _mos9lvl[4]; /* operating system level/version/edition */ ushort _mos9rev, /* offset to OS-9 level/revision string */ _msyspri, /* initial system priority */ _mminpty, /* initial minimum executable priority */ _maxage; /* initial maximum natural process age */ long _mmdirsz; /* number of module dir entries (unused) */ ushort _mevents; /* number of system event table entries */ ushort _mreserved[14]; /* reserved space */ } mod_config;

6.2 El Kernel.

6.2.1 Responsabilidades del Kernel. El núcleo del sistema operativo es el Kernel. Es un módulo administrador del sistema, está escrito en lenguaje ensamblador del 68000 y cuyas funciones son: 1) Procesar las rutinas de servicio (llamadas al sistema). 2) Manejador de la memoria. 3) Inicializar el sistema después de Reset. 4) Manejo de la MPU (multiprogramación). 5) Manejo de las capacidades de Entrada/Salida. 6) Procesar las Interrupciones y Excepciones.

6.2.2 Llamadas al Sistema. Las llamadas al Sistema (System Call) se usan para comunicaciones entre el sistema operativo y los programas en lenguaje ensamblador. Existen tres tipos de llamadas: 1) Llamadas en estado de usuario (user-state). 2) Llamadas en estado de sistema (system-state). 3) Llamadas de E/S. Con estas llamadas al sistema, el usuario puede acceder a funciones básicas del sistema aprovechando así los recursos del mismo. Cada llamada tiene un nemotécnico para más fácil uso de ellas, estos nombres se definen en la librería "usr.l" que se lincará junto con el programa del usuario. 1) El Estado de Usuario (User-State) es el entorno de programación normal en el cual un programa es ejecutado. Los procesos que corren en este estado no acceden directamente a la configuración hardware del sistema. * En un entorno multiusuario, los procesos User-State comparten el tiempo de CPU mediante un proceso denominado "time-sliced". * La protecciones de memoria previenen a las rutina que corren en User-State de dañar accidentalmente a estructuras de datos que no les pertenecen. * Estos procesos pueden ser abortados. * Los programas user-state son fáciles de escribir y depurar. * Los nombres simbólicos de las llamadas al sistema en User-State comienzan con "F$". Por ejemplo F$Link. 2) El Estado de Sistema (System-State) es el entorno en el cual se ejecutan llamadas de sistema y rutinas de servicio de interrupciones. Todo proceso que corre en System State, está

corriendo realmente en estado supervisor (Supervisor State) de la familia 68000. Con lo que se puede acceder al hardware físico presente en el sistema. * Una rutina system-stae puede acceder a todas las capacidades del procesador. Por ejemplo, acceder a memoria protejida, enmascarar interrupciones o tomar control directo de los vectores de interrupción hardware. * Una rutina system-state nunca corre en "time-sliced", sino que corre hasta que finaliza o se va a dormir. Por esta razón es importante que todas estas rutinas sean tan cortas y rápidas como sea posible. * Si una rutina system-state pierde el control, el sistema completo se irá con casi total seguridad a pique. * El proceso de depuración de un rutina system-state es muy difícil y peligroso para la integridad del sistema. * Los nombres simbólicos de las llamadas al sistema en System-State también comienzan con "F$". 3) Llamadas de E/S. Estas llamadas realizan solicitudes de E/S y son procesadas por los File

Manager y los Drivers para un dispositivo particular. * Pueden ser usadas en system-state y user-state. * Los nombres simbólicos de estas funciones comienzan por con "I$". Formas de Instalar una rutina system-state. Existen cuatro formas de instalar una rutina system-state 1) Instalar un módulo OS-9 llamado "OS9P2" que se debe de encontrar en ROM o en fichero

de bootstrap. Si este fichero es encontrado por el OS-9 durante el arranque lo linkara en memoria y lo ejecutará a partir del punto de ejecución.

2) Escribir un Driver en el cual se pueden utilizar las rutinas I$GetStt o I$SetStt. La razón de

ésto es que un File Manager o un Driver siempre corren en system-state. 3) Escribir un módulo gestionador de trap en modo user-state para depurarlas y luego

convertirlo a system-state activando el bit de estado supervisor de la cabecera del módulo. Es necesario crear este módulo como super usuario.

4) Un programa siempre se ejecutará en modo system-state si el bit de estado en la palabra

"attribute/revision" de la cabecera del módulo está activado.

6.2.3 Gestión de la Memoria. El manejo de la memoria es una función del sistema operativo muy importante. Los módulos de memoria son el fundamento del sistema operativo OS-9. Cualquier objeto que quiera cargarse en memoria tiene que seguir un formato fijo (programas, tablas de datos, etc.). Todos los Módulos de

memoria se dividen en tres partes: Una cabecera, un cuerpo y un valor de CRC (Valor para comprobación). Hay diferentes tipos de módulos, cada uno de los cuales tiene sus usos y funciones. Cada módulo puede ser compartido por diferentes procesos puesto que son de código reentrante. La cabecera de todos estos módulos tienen la misma estructura de campos definidas en las librerías "sys.l" y "usr.l".Existen otros campos para una cabecera adicional que dependen del tipo de módulo de memoria. El OS-9 usa una porción de la memoria interna para su propio uso en donde guarda direcciones a saltos de subrutinas y las variables globales del sistema. También esta área está definida simbólicamente en la librería "sys.l". Cuando un módulo es cargado en memoria, es añadido al directorio de módulos. Cada entrada en el directorio contiene un link count; que indica el número de procesos que están usando ese módulo. Cuando un proceso está utilizando un módulo incrementa el valor de este contador en uno, y cuando el proceso termina decrementa el contador en una unidad también. Cuando el valor del contador llega a ser cero, entonces el módulo es eliminado de la memoria a no ser que el módulo esté "sticky". Si un módulo está sticky no es eliminado de la memoria hasta el link count llegue a valer -1 o la memoria sea requerida por otro usuario. Para poner un módulo en este estado nos basta con poner a uno el sexto bit del campo de su cabecera M$Attr. Mapa de Memoria del OS-9. En la tabla siguiente vemos un plano de memoria típico de un sistema OS-9. Como vemos toda la memoria está contenida en un mapa simple. Las distintas secciones de memoria pueden ser contiguas o alternas, aunque se recomienda que sean contiguas. ┌──────────────────────────────────────┐ <- Posición más alta. │ Direcciones de dispositivo de E/S │ ├──────────────────────────────────────┤ <- ROM de arranque. │ ROM de boot del sistema. │ La dirección de arranque │ ROM opcional para aplicaciones │ viene indicada en el vector ├──────────────────────────────────────┤ de reset. │ Reservado para usos futuros │ ├──────────────────────────────────────┤ <- RAM en múltiplos de 8K. │ │ │ │ │ RAM (mín. 128K) │ │ │ │ │ ├──────────────────────────────────────┤ <- Dirección 000400 │ ROM o RAM para vectores de excepción │ ├──────────────────────────────────────┤ <- Dirección 000008 │ ROM para los vectores de reset. │ └──────────────────────────────────────┘ <- Dirección 000000 En sistemas desarrollados sobre el 68020 y 68030 VBR (Vector Base Register) puede estar situado en cualquier parte del sistema. Así, en estos sistemas no es necesario que exista ROM o RAM en la posición 0.

Durante la secuencia de arranque del OS-9, una función del Kernel se encarga de la búsqueda automática de bloques de ROM y RAM. Una zona de la RAM se la reserva el Kernel para almacenar estructuras de datos propias (8K mínimo), mientras que en la zona de ROM se busca módulos OS-9 válidos. En sistemas sin disco el tamaño típico del código objeto del sistema operativo ocupa entre 30K y 40K bytes. El tamaño total ocupado por el OS-9 dependerá del número de módulos (kernel, File Managers, Drivers, ...) que se necesiten. A la hora de hablar de los tipos de memoria tenemos que tener en cuenta los siguientes términos: Memoria Global del Sistema: El OS-9 usa un mínimo de 8K de memoria RAM para sus uso interno. Esta zona de memoria es cargada normalmente en la parte baja de la RAM. Los programas nunca deben acceder a las variables globales del sistema. Son la llamadas al sistema las que se encargan de leer esta zona de memoria. Memoria Dinámica del Sistema: El OS-9 mantiene una serie de estructuras de datos dinámica tales como buffers, descriptores de paths y procesos, que son cargadas en la RAM general cuando se necesitan. Los punteros a estas zonas están guardados en la zona de memoria global del sistema. Memoria de Usuario: Esta memoria es asignada automáticamente por el sistema en los siguientes casos: * Cuando se carga en memoria algún módulo. * Cuando un nuevo proceso es creado. * Cuando un proceso solicita memoria adicional. * Cuando el OS-9 requiere más buffers de E/S o las estructuras de datos internas deben ser expandidas. Colored Memory: Este término permite al usuario reconocer diferentes tipos de memoria y reservarla para usos específicos. Los tipos específicos de memoria o "colores" pueden ser solicitados por el usuario al reservar memoria para buffers, cargar módulos en memoria u otras aplicaciones. Si solicitamos un tipo especial de memoria que no existe el sistema nos devolverá un mensaje de error.

La lista de tipos (colores) de memoria de cada sistema en particular se encuentra definida en el fichero systype.d y este fichero es solicitado desde el módulo Init. En el fichero memory.h podemos encontrar las definiciones de los tipos de memoria. La línea que define una zona de memoria posee el siguiente formato: type,priority,attributes,blksiz,addr begin,addr end,name,DMA-offset

type Tipo de memoria (SYSRAM, VIDEO1 o VIDEO2). priority Prioridad de la memoria (0 - 255). attributes Permisos de acceso a la memoria. bit 0 - Utilizable por procesos de usuario. bit 1 - Parity memory. bit 2 - ROM (Es buscada durante el startup). blksiz Tamaño del bloque de memoria. addr begin Límite inferior de la memoria. addr end Límite superior de la memoria. name Offset al un string de descripción. DMA-offset Dirección del bus externo al inicio del bloque. A continuación tenemos el listado de un fichero systype.d en donde podremos encontrar como realizar las definiciones de las distintas zonas de memoria que acabamos de estudiar. En este fichero se realizan otras definiciones muy importantes que estudiaremos en las próximos apartados relativos a los módulos init y sysgo. SYSTYPE.D * System Definitions for Force SYS68K/CPU-30 opt -l pag ******************** * Edition History * date comments by * -------- ---------------------------------------------------- --- * 89/05/10 genesis kse * 89/07/05 added chkburst P2 module for cache burst mode check kse ******************** * Conditional Assembly Variables CPU30 equ $F0CE30 default value for Force CPU-30 SIO2 equ $5102 default value for Force SIO-2 ******************** * Hardware type definitions CPUTyp set 68030 define the processor in use CPUType set CPU30 define the cpu module in use pag ******************** * System Interrupt Structure * Interrupt Levels ABORTLevel equ 7 ABORT level FDCLevel equ 6 floppy disk controller level PITLevel equ 6 parallel interface/timer ClkLevel equ PITLevel clock irq level LANLevel equ 6 lance SCSILevel equ 5 scsi host controller level ClkPrior equ ClkLevel DMALev equ 3 dma device (force gate array) T1Level equ 2 t1 port level T2Level equ 2 t2 port level T3Level equ 2 t3 port level TermLev equ 2 console port level ******************** * Interrupt Vectors ABORTVECT equ 31 ABORT vector ABORTVect equ 104 Gate array abort switch vector FDCVect equ 113 floppy disk controller PITVect equ 114 PIT PIT2Vect equ 115 PIT ClkVect equ PITVect clock vector T2Vect equ 117 t2 T3Vect equ 116 t3

T1Vect equ 117 t1 TermVect equ 116 console LANVect equ 118 lance SCSIVect equ 119 SCSI host controller ******************** * Device Addresses PITBase equ $ff800c00 parallel interface/timer PIT2Base equ $ff800e00 parallel interface/timer ClkBase equ PITBase clock device address TermBase equ $ff802020 terminal device address: serial IO port 1 T1Base equ $ff802200 t1 device address: serial IO port 2 T2Base equ $ff802220 t2 device address: serial IO port 3 T3Base equ $ff802000 t3 device address: serial IO port 4 (P2 connector) RTCBase equ $ff803000 real time clock SCSIBase equ $ff803400 fujitsu 87031 scsi host chip FDCBase equ $ff803800 western digital 1772 floppy controller FGABase equ $ffd00000 force gate array ConsBase equ TermBase CommBase equ T1Base pag ******************** * Configuration module constants * used only by init module * CONFIG macro MainFram dc.b "Force SYS68K/CPU-30",0 SysStart dc.b "sysgo",0 name of initial module to execute SysParam dc.b 0 parameters to pass to initial module SysDev dc.b "/h0",0 initial system disk pathlist ConsolNm dc.b "/term",0 console terminal pathlist ClockNm dc.b "tk68230",0 clock module name * edition #2 change *Extens dc.b "OS9P2 syscache ssm",0 include burst check, caching, ssm. *Extens dc.b "OS9P2 chkburst syscache ssm",0 include burst check, caching, ssm. * end edition #2 change endm pag ******************* * SCF device descriptor definitions * used only by scf device descriptor modules * * SCFDesc: Port,Vector,IRQlevel,Priority,Parity,BaudRate,DriverName * TERM macro SCFDesc TermBase,TermVect,TermLev,2,$00,$0e,sc68562 * default descriptor values can be changed here DevCon set 0 endm T1 macro SCFDesc T1Base,T1Vect,T1Level,3,$00,$0e,sc68562 DevCon set 0 endm T2 macro SCFDesc T2Base,T2Vect,T2Level,3,$00,$0e,sc68562 DevCon set 0 endm T3 macro SCFDesc T3Base,T3Vect,T3Level,3,$00,$0e,sc68562 DevCon set 0 endm P1 macro SCFDesc T3Base,T3Vect,T3Level,3,$00,$0e,sc68562 DevCon set 0 Mode set ISize_+Write_ device capabilities endm pag ******************** * RBF device descriptor definitions * RBFDesc Port,Vector,IRQLevel,Priority,DriverName,DriveOptions

DiskD0 macro RBFDesc FDCBase,FDCVect,FDCLevel,2,rb1772,dd580 * Default disk values may be changed here BitDns set Double SectTrk0 set 16 DnsTrk0 set Double DrvNum set 2 logical device number Control set FmtEnabl format enable StepRate set 0 ScsiLun set 0 SectOffs set 1 Intrleav set 1 DevCon set 0 endm DiskH0 macro RBFDesc SCSIBase,SCSIVect,SCSILevel,2,rbsccs,autosize * Default disk values may be changed here DiskKind set Hard BitDns set Single Heads set 0 StepRate set 0 TrkDns set Single Cylnders set 0 NoVerify set ON SectTrk set 0 SectTrk0 set 0 SectSize set 512 DrvNum set 0 Intrleav set 1 SegAlloc set 32 DnsTrk0 set Single Density set BitDns+(TrkDns<<1) DiskType set DiskKind+(DnsTrk0<<5) Control set FmtDsabl+AutoEnabl+MultEnabl ScsiLun set 0 CtrlrID set 0 Trys set 7 WrtPrecomp set 0 DevCon dc.b "scsi30",0 endm DiskH0fmt macro RBFDesc SCSIBase,SCSIVect,SCSILevel,2,rbsccs,autosize * Default disk values may be changed here DiskKind set Hard BitDns set Single Heads set 0 StepRate set 0 TrkDns set Single Cylnders set 0 NoVerify set ON SectTrk set 0 SectTrk0 set 0 SectSize set 512 DrvNum set 0 Intrleav set 1 SegAlloc set 32 DnsTrk0 set Single Density set BitDns+(TrkDns<<1) DiskType set DiskKind+(DnsTrk0<<5) Control set AutoEnabl+MultEnabl ScsiLun set 0 CtrlrID set 0 Trys set 1 WrtPrecomp set 0 DevCon dc.b "scsi30",0 endm pag ******************************** * These definitions are only used by the bootstrap ROM source ConsType equ S68562 console debug port CommType equ S68562 communications port ClkPort equ ClkBase TicksSec equ 100 TClkRate equ $7a0000 BusWidth equ 1 VBRBase equ 0

FDBase equ FDCBase FD_Vct equ FDCVect FDsk_Vct equ FD_Vct SysDisk equ FDBase * memory list definitions: * Mem.Beg equ $000400 start of normal memory area to search *Mem.End equ $100000 end of normal memory area (1MB RAM) Mem.End equ $400000 end of normal memory area (4MB RAM) *Spc.Beg equ $0e0000 beginning of special RAM search area *Spc.End equ $100000 end of special RAM search area Spc1.Beg equ $ff000000 beginning of ROM area Spc1.End equ $ff040000 end of ROM area Cons_Adr equ TermBase console device address Comm_Adr equ T1Base auxilliary device address MemDefs macro dc.l Mem.Beg,Mem.End the normal memory search list dc.l 0 * dc.l Spc.Beg,Spc.End the special memory search list (RAM) dc.l Spc1.Beg,Spc1.End the special memory search list (ROM) dc.l 0 dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0 free bytes for patching endm opt l

6.2.4 El módulo Init. El módulo Init contiene una tabla de parámetros para la inicialización del sistema. Este módulo es un módulo no ejecutable del tipo Systm y es usado durante el proceso de arranque para especificar el tamaño de la tabla inicial y los nombres de los dispositivos del sistema. Debe estar en memoria cuando el Kernel es ejecutado y reside normalmente en el fichero OS9Boot. En la tabla que viene a continuación veremos cuales son los distintos campos adicionales que posee la cabecera del módulo init. El fichero fuente del módulo Init (init.a) se encuentra junto con el fichero fuente del módulo Sysgo (sysgo.a) en el directorio /dd/SYSMODS. En este directorio encontraremos el fichero Makefile que utilizaremos para generar ambos módulos. Para una mejor compresión de la funcionalidad de este módulo imprescindible en el sistema, a continuación tenemos el listado del fichero init.a y del fichero Makefile que se encarga de compilar el módulo

CAMPOS ADICIONALES EN EL MODULO INIT Offset Nombre Descripción del Campo $00 M$ID Byte de Sincronismo ($4AFC) $2E M$Parity Paridad cabecera(C'1 palabra previa) $30 $34 M$Pollsz Número de entradas a la tabla IRQ $36 $38 $3 Offset Nombre Descripción del Campo ┌──────────┬────────────────────────────────────────┬────────────┐ $00 │ │ │ │ ��� │ ���� │ ���������������������������������������│ CABECERA │ ��� │ ���� │ ���������������������������������������│ STANDARD │ $2E │ │ Paridad cabecera (C'1 palabra previa)│ │ ╞══════════╪════════════════════════════════════════_<───────────┘ $30 │ │ Reservado │ ├──────────┼────────────────────────────────────────┤ $34 │ M$Pollsz │ Número de entradas a la tabla IRQ │ ├──────────┼────────────────────────────────────────┤ $36 │ M$DevCnt │ Tamaño tabla de dispositivos │ ├──────────┼────────────────────────────────────────┤ $38 │ M$Procs │ Tamaño tabla de procesos iniciales │ ├──────────┼────────────────────────────────────────┤ $3A │ M$Paths │ Tamaño tabla de Paths iniciales │ ├──────────┼────────────────────────────────────────┤ $3C │ M$SParam │ String de parámetros para Sysgo │ ├──────────┼────────────────────────────────────────┤ $3E │ M$SysGo │ Offset nombre 1º módulo ejecutable │ ├──────────┼────────────────────────────────────────┤ $40 │ M$SysDev │ Offset al nombre Directorio (default) │ ├──────────┼────────────────────────────────────────┤ $42 │ M$Consol │ Offset al nombre del Path E/S Standard │ ├──────────┼────────────────────────────────────────┤ $44 │ M$Extens │ Offset al nombre módulo configuración │ ├──────────┼────────────────────────────────────────┤ $46 │ M$Clock │ Offset al nombre del módulo Clock │ ├──────────┼────────────────────────────────────────┤ $48 │ M$Slice │ Ticks por Time-slice │ ├──────────┼────────────────────────────────────────┤ $4A │ │ Reservado │ ├──────────┼────────────────────────────────────────┤ $50 │ M$Instal │ Offset al nombre de la instalación │ ├──────────┼────────────────────────────────────────┤ $52 │ M$CPUTyp │ Tipo de la CPU │ ├──────────┼────────────────────────────────────────┤ $56 │ M$OS9Lvl │ Nivel del Sistema Operativo │ ├──────────┼────────────────────────────────────────┤ $5A │ M$OS9Rev │ Offset al nombre de la revisión │ ├──────────┼────────────────────────────────────────┤ $5C │ M$SysPri │ Prioridad inicial del sistema │ ├──────────┼────────────────────────────────────────┤ $5E │ M$MinPty │ Prioridad mínima │ ├──────────┼────────────────────────────────────────┤ $60 │ M$MaxAge │ Edad Máxima │ ├──────────┼────────────────────────────────────────┤ $62 │ │ Reservado │ ├──────────┼────────────────────────────────────────┤ $66 │ M$Events │ Tamaño de la Tabla de Eventos Inicial │ ├──────────┼────────────────────────────────────────┤ $68 │ M$Compat │ Flag de compatibilidad │ ├──────────┼────────────────────────────────────────┤ $69 │ │ Reservado │ ├──────────┼────────────────────────────────────────┤ $6A │ M$MemList│ Offser a la lista de Memoria │

├──────────┼────────────────────────────────────────┤ $6C │ │ Reservado (24 bytes) │ └──────────┴────────────────────────────────────────┘

FICHERO INIT.A nam Init: OS-9 Configuration Module ******************************** * Edition History * # Date Comments by * -- -------- -------------------------------------------------------------------------------------- * 00 12-01-83 Initial test version developed. rfd * 01 01-20-84 Added code to process startup file. rfd * 02 11-01-84 Changed names and added new information. rfd * 03 12-20-84 Changed slice value from 1 to 2. rfd * 04 06-21-85 Minor changes for V1.2. rfd * ---- OS-9/68k V1.2 released ---- * 05 08-23-85 Added entries for M$BlkSiz and M$MinBlk. rfd * 06 01-31-86 Removed M$BlkSiz and M$MinBlk. rfd * Added SysParam string. rfd * 07 09-11-86 changed names to 2.0. rfd * 08 09-25-86 Added M$Compat byte for smoothing port problems. rfd * 09 10-03-86 Made OS9Rev string configurable by systype. rfd * ---- OS-9/68k V2.0 released ---- * 10 05-11-87 Removed SPU & UsrAct; added ifdef Extens. rfd * 11 05-26-87 Added Compat bit definitions. rfd * ---- OS-9/68k V2.1 released ---- * 12 10-21-87 Updated for 2.2 release. rfd * ---- OS-9/68k V2.2 released ---- * 13 04-28-88 Added memlist definitions. rfd * 14 06-13-88 Changed memlist table format. rfd * 15 07-18-88 Added IP_ID. rfd * 16 08-19-88 Remove obsolete memory definitions. rfd * 17 10-06-88 Added ZapMem compat bit definition. rfd * 18 11-02-88 Added IRQ stack size word rfd * 19 03-18-89 Added _INITMOD definition and comments. wwb * 20 03-31-89 Added NoClock definition. rfd * ---- OS-9/68k V2.3 released ---- Edition equ 20 current edition number Typ_Lang set (Systm<<8)+0 Attr_Rev set (ReEnt<<8)+0 psect init,Typ_Lang,Attr_Rev,Edition,0,0 * Configuration constants (default; changable in "systype.d" file) * * Constants that use VALUES (e.g. CPUTyp set 68020) may appear anywhere * in the "systype.d" file. * Constants that use LABELS (e.g. Compat set ZapMem) MUST appear OUTSIDE * the CONFIG macro and must be conditionalized such that they are * only invoked when this file (init.a) is being assembled. * If they are placed inside the CONFIG macro, then the over-ride will not * take effect. * If they are placed outside the macro and not conditionalized then * "illegal external reference" errors will result when making other files. * The label _INITMOD provides the mechanism to ensure that the desired * operations will result. * * example systype.d setup: * * CONFIG macro * * endm * Slice set 10 * ifdef _INITMOD * Compat set ZapMem patternize memory * endc * * flag reading init module (so that local labels can be over-ridden) _INITMOD equ 1 flag reading init module CPUTyp set 68000 cpu type (68008/68000/68010) Level set 1 OS-9 Level One Vers set 2 Version 2.3 Revis set 3 Edit set 1 Edition IP_ID set 0 interprocessor identification code Site set 0 installation site code MDirSz set 128 initial module directory size (unused) PollSz set 32 IRQ polling table size (fixed) DevCnt set 32 device table size (fixed) Procs set 64 initial process table size (divisible by 64)

Paths set 64 initial path table size (divisible by 64) Slice set 2 ticks per time slice SysPri set 128 initial system priority MinPty set 0 initial system minimum executable priority MaxAge set 0 initial system maximum natural age limit MaxMem set 0 top of RAM (unused) Events set 0 initial event table size (divisible by 8) Compat set 0 version smoothing byte StackSz set 1024 IRQ Stack Size in bytes (must be 1k <= StackSz < 256k) ColdRetrys set 0 number of retries for coldstart's "chd" before failing * Compat flag bit definitions SlowIRQ equ 1 xxxxxxx1 save all regs during IRQ processing NoStop equ 1<<1 xxxxxx1x don't use 'stop' instruction NoGhost equ 1<<2 xxxxx1xx don't retain Ghost memory modules NoBurst equ 1<<3 xxxx1xxx don't enable 68030 cache burst mode ZapMem equ 1<<4 xxx1xxxx wipe out memory that is allocated/freed NoClock equ 1<<5 xx1xxxxx don't start system clock during coldstart use defsfile (any above definitions may be overridden in defsfile) * Memory list definitions MemType macro dc.w \1,\2,\3,\4>>4 type, priority, access, search block size dc.l \5,\6 low, high limits (where it appears on local address bus) dc.w \7,0 offset to description string (zero if none), reserved dc.l \8,0,0 address translation adjustment (for DMA, etc.), reserved ifne \#-8 must have exactly eight arguments fail wrong number of arguments to MemType macro endc endm * Configuration module body dc.l MaxMem (unused) dc.w PollSz IRQ polling table dc.w DevCnt device table size dc.w Procs initial process table size dc.w Paths initial path table size dc.w SysParam parameter string for first executable module dc.w SysStart first executable module name offset dc.w SysDev system default device name offset dc.w ConsolNm standard I/O pathlist name offset dc.w Extens Customization module name offset dc.w ClockNm clock module name offset dc.w Slice number of ticks per time slice dc.w IP_ID interprocessor identification dc.l Site installation site code dc.w MainFram installation name offset dc.l CPUTyp specific 68000 family processor in use dc.b Level,Vers,Revis,Edit OS-9 Level dc.w OS9Rev OS-9 revision string offset dc.w SysPri initial system priority dc.w MinPty initial system minimum executable priority dc.w MaxAge maximum system natural age limit dc.l MDirSz module directory size (unused) dc.w Events initial event table size (number of entries) dc.b Compat version change smooth byte dc.b 0 dc.w MemList memory definitions dc.w StackSz/4 IRQ stack size (in longwords) dc.w ColdRetrys coldstart's "chd" retry count dc.w 0,0,0,0,0 reserved dc.w 0,0,0,0,0 reserved * Configuration name strings OS9Rev dc.b "OS-9/68K V",Vers+'0',".",Revis+'0',0 * The remaining names are defined in the "systype.d" macro CONFIG ifndef Extens Extens dc.b "OS9P2",0 endc ifndef MemList MemList equ 0 endc ends

FICHERO MAKEFILE # make file to produce system I/O modules SDIR = . RDIR = rels ODIR = ../cmds/bootobjs DEFS = ../defs/oskdefs.d ../defs/systype.d LIB = ../lib/sys.l FILES = init sysgo RFILES = init.r sysgo.r RFLAGS = -q -x make.date:$(FILES) touch make.date $(FILES): $(LIB) l68 -l=$(LIB) $(RDIR)/$*.r -gO=$(ODIR)/$* $(RFILES): $(DEFS)

6.2.5 El Módulo Sysgo.

Sysgo es el primer módulo de usuario que comienza a ejecutarse después de la secuencia de arranque del sistema. Los pasos seguidos durante este proceso son los siguientes: 1 Se cambia al directorio de ejecución /dd/CMDS. 2 Ejecuta el fichero startup como un script. 3 Arranca un shell en la consola del sistema (/term). 4 Espera a que el shell termine para volver a arrancarlo de nuevo, con lo que siempre tendremos un shell sobre la consola del sistema. El shell que se arranca a través de este proceso posee la característica de que nunca nos solicita el nombre de usuario y el password. Si en el fichero startup arrancamos un shell sobre la consola mediante el comando ex tsmon /term entonces al conectar el equipo, nunca se llegarán a ejecutar los pasos 3 y 4 de la secuencia anterior, pues el shell que arrancamos de esta manera siempre se estará regenerando cuando nos salgamos mediante un logout. Al configurar el sistema de esta forma siempre necesitaremos introducir el nombre de usuario y el password para poder conectarnos al sistema a través de la consola. El fichero fuente del módulo Sysgo (sysgo.a) podemos encontrarlo conjuntamente con el fichero fuente del módulo Init (init.a) en el directorio /dd/SYSMODS. Para mejorar la capacidad del OS-9, módulos adicionales pueden ser ejecutados por el Kernel durante el proceso de boot. Los nombres de estos módulos deben estar especificados en la Lista de Extensión del módulo Init. A estos módulos, sólo tienen permitida la modificación de los registros d0, d1 y ccr. Los pasos son: 1) Ensamblar y linkar el módulo (newmodule) de forma que el código objeto final aparezca en el directorio /h0/CMDS/BOOTOBJS 2) Crear un nuevo módulo Init, para lo cual se va al módulo CONFIG en el fichero /dd/DEFS/systype.d y se introduce el nombre del módulo en la lista de extensión. Se debe introducir una línea como la siguiente: ANTES: Extens dc.b "os9p2",0 endm DESPUES: Extens dc.b "os9p2 newmodule",0 endm Si esta lista no se encontrase el fichero systype.d, podremos encontrarla en el propio fichero Init.a.

3) Crear un nuevo fichero de boot. Para ello nos vamos al directorio /h0/CMDS/BOOTOBJS y editamos el fichero bootlist (bootlist.h0) y añadimos en nombre del nuevo módulo (newmodule). Ahora debemos crear el nuevo fichero /h0/OS9boot, para lo cual utilizamos el comando os9gen $ os9gen /h0fmt -z=bootlist 4) Hacemos un reset del sistema y comprobamos que el nuevo módulo está operativo. FICHERO SYSGO.A nam Sysgo ttl OS-9/68000 Initial (startup) module ******************************** * Editon History * # Date Comments by * -- --------- ------------------------------------------------ --- * 00 12-01-83 Initial test version developed. rfd * 00 01-20-84 Added code to process startup file. rfd * 01 10-24-84 Removed chd to root device. (done by cold.a) rfd * Made non-reentrant. rfd * 02 11-13-85 Changed startup file to be redirected shell input.rfd * 03 05-20-86 Fixed bug in above change (wrong reg for open). rfd * 04 10-15-86 Modified slightly for 2.0 release. rfd * <<<---- OS-9/68000 V2.0 Release ---->>> * <<<---- OS-9/68000 V2.1 Release ---->>> * <<<---- OS-9/68000 V2.2 Release ---->>> * <<<---- OS-9/68000 V2.3 Release ---->>> Edition equ 4 current edition number Typ_Lang set (Prgrm<<8)+Objct Attr_Rev set 0 (non-reentrant) psect sysgo,Typ_Lang,Attr_Rev,Edition,0,Entry use defsfile vsect ds.b 255 stack space ends Intercpt OS9 F$RTE return from intercept Entry lea Intercpt(pc),a0 OS9 F$Icpt lea CmdStr(pc),a0 default execution directory ptr moveq #Exec_,d0 execution mode OS9 I$ChgDir change execution directory (ignore errors) bcc.s Entry10 continue if no error moveq #1,d0 std output path moveq #ChdErrSz,d1 size º lea ChdErrMs(pc),a0 "Help, I can't find CMDS" OS9 I$WritLn output error message * Process startup file Entry10 moveq #0,d0 std input path OS9 I$Dup clone it move.w d0,d7 save cloned path number moveq #0,d0 std input path OS9 I$Close move.w #Read_,d0 lea Startup(pcr),a0 "startup" pathlist OS9 I$Open open startup file bcc.s Entry15 continue if no error moveq #1,d0 std output path moveq #StarErSz,d1 size of startup error msg lea StarErMs(pc),a0 "Help, I can't find 'startup'" OS9 I$WritLn output error message bra.s Entry25 Entry15 moveq #0,d0 any type module moveq #0,d1 no additional default memory size moveq #StartPSz,d2 size of startup shell params moveq #3,d3 copy three std I/O paths

moveq #0,d4 same priority lea ShellStr(pcr),a0 shell name lea StartPrm(pcr),a1 initial parameters OS9 F$Fork fork shell bcc.s Entry20 continue if no error moveq #1,d0 std output path moveq #FrkErrSz,d1 size lea FrkErrMs(pc),a0 "oh dear, can't fork Shell" OS9 I$WritLn output error message OS9 F$SysDbg crash system Entry20 OS9 F$Wait wait for it to die, ignore any error moveq #0,d0 std input path OS9 I$Close close redirected "startup" Entry25 move.w d7,d0 OS9 I$Dup restore original std input move.w d7,d0 OS9 I$Close remove cloned path Loop moveq #0,d0 any type module moveq #0,d1 default memory size moveq #1,d2 one parameter byte (CR) moveq #3,d3 copy std I/O paths moveq #0,d4 same priority lea ShellStr(pcr),a0 shell name lea CRChar(pcr),a1 null paramter string OS9 F$Fork fork shell bcs.s ForkErr abort if error OS9 F$Wait wait for it to die bcs.s ForkErr tst.w d1 zero status? beq.s Loop loop if so ForkErr OS9 F$PErr print error message bra.s Loop ShellStr dc.b "shell",0 FrkErrMs dc.b "Sysgo can't fork 'shell'",C$CR FrkErrSz equ *-FrkErrMs CmdStr dc.b "CMDS",0 ChdErrMs dc.b "Sysgo can't chx to 'CMDS'",C$CR ChdErrSz equ *-ChdErrMs Startup dc.b "startup",0 StarErMs dc.b "Sysgo can't open 'startup' file",C$CR StarErSz equ *-StarErMs StartPrm dc.b "-npxt" CRChar dc.b C$CR StartPSz equ *-StartPrm ends

6.2.6 Creación de Procesos. Dentro del OS-9 todos los programa corren como procesos o tareas. Los nuevos procesos son

asos para la Creación de un Nuevo Proceso:

) Cargar el módulo en memoria.

) Una vez cargado el módulo primario en memoria, una estructura de datos llamada "process

creados por la llamada al sistema F$Fork. Para crear un nuevo proceso hay que pasarle el nombre del módulo que se va a ejecutar inicialmente. Los pasos a seguir para la creación de un nuevo proceso son los siguientes: P 1 2descriptor" es asignada al nuevo proceso. Este descriptor contiene información acerca del proceso, como el estado, localización en memoria, etc.

3) El OS-9 reserva memoria para almacenar los datos y el stack del programa, para lo cual mira la cabecera del módulo primario para saber cuanta memoria necesita. 4) Los registros del nuevo proceso son actualizados para apuntar correctamente al área de datos y al código objeto del módulo. Si el programa usa variables inicializadas, éstas son copiadas desde la zona del código objeto a la zona de datos. A cada proceso se le asigna tres números denominados Process ID Identifica el proceso. Group ID Identifica el grupo del usuario. User ID Identifica el usuario del proceso. Si no se puede crear el nuevo proceso se notifica el error en F$Fork. Si no se produce ningún error, el proceso queda instalado. Para terminar un proceso hay que ejecutar F$Exit. Hay que señal aquí, que todo proceso está divido en dos zonas de memoria separadas: Código puede ser compartido por varios programas ya que estos módulos son reentrantes. Datos Cada proceso tiene una única zona de datos. Estado de los Procesos: Activo Cuando un proceso está activo y listo para ser ejecutado. La ejecución de estos procesos se realiza en función de sus prioridades relativas. Esperando El proceso está inactivo hasta que un proceso hijo termine o hasta que se reciba una señal. Un proceso entra en estado de espera cuando se ejecuta la llamada F$Wait. Durmiendo El proceso está inactivo por un periodo determinado de tiempo o hasta que se reciba una señal. Se utiliza la llamada F$Sleep.

6.2.7 Process Scheduling. 1 En un sistema multitarea pueden estar ejecutándose simultáneamente varios programas independientes. task-switching Es la acción que realiza el Kernel mediante la cual se pasa de estar ejecutando un proceso a otro en función de las prioridades de los procesos activos. tick Es el intervalo con que el reloj en tiempo real interrumpe a la CPU, y gracias a esta interrupción el Kernel es capaz de suspender la ejecución de un proceso para pasar el control de la CPU a otro. Por defecto, la duración de un tick son 10 milisegundos (1 seg = 100 tick), pero este valor puede ser modificado. time-slice Es la mayor cantidad de tiempo que un proceso controlará la CPU antes de que el Kernel vuelva a evaluar la cola de procesos activos. Por defecto, un slice son dos ticks.

Process age Es el número resultante de sumar la prioridad inicial del proceso más el número de veces que se ha conmutado procesos desde que el proceso entro en la cola activa. Los proceso más antiguos siempre están en la cabecera de la lista. La prioridad de los proceso siempre se incrementa sin superar el valor $FFFF. Las Variables D_MinPty y D_MaxAge son utilizables por el super usuario a través de la llamada al sistema F$SetSys para alterar la ejecución de los procesos. D_MinPty Mínima prioridad por debajo de la cual los procesos no son ejecutables. Su valor es cero normalmente. Ejemplo: Si ponemos D_MinPty = 500, a un proceso que se ejecute le signamos 600, con lo cual, todos los inferiores se paran hasta que se restablezca D_MinPty. En uso indiscriminado de esta variable puede producir la caída del sistema. D_MaxAge Define la máxima edad, por encima de la cual los procesos no pueden madurar. Por defecto el valor es cero, lo cual no afecta a los proceso en la CPU. En función del tipo de prioridad podemos clasificar los procesos en dos: Alta Prioridad Son los que poseen una prioridad superior al valor de D_MaxAge. Reciben todo el tiempo de CPU, pero no incrementan su prioridad. Baja Prioridad Poseen un prioridad inferior al valor de D_MaxAge. Su prioridad crece según se van ejecutando, pero este valor no puede pasar por encima de D_MaxAge mientras existan proceso de alta prioridad ejecutándose. Existen tres métodos para manejar procesos en un entorno de trabajo en tiempo real. 1) Manipulando la prioridad de los procesos. 2) Usando D_MinPty y D_MaxAge para alterar el scheduling de los procesos del sistema. 3) Teniendo procesos System State. Cuando un proceso que está en estado supervisor quiera usar la CPU espera hasta que tenga la mayor edad. Una vez que accede a la CPU correrá hasta que termine en lugar de correr en un determinado "time slice".

6.2.8 Excepciones e Interrupciones. Vector de Reset (0,1): Vector de reset inicial que contiene la dirección de inicio del sistema. Debajo de esta dirección deben de existir 4K de memoria para variables globales del sistema. Excepciones de Error (2-8, 10-24, 48-63):

Son utilizadas normalmente en casos de errores fatales en un programa. Se pueden instalar rutina que atiendan los errores considerados como no fatales. Vector de Trace (9): Permite ejecutar una simple instrucción. Es utilizada por el depurador. Interrupciones Autovectorizadas (25-31, 57-63[solo 68070]): Estas excepciones permiten el sondeo de dispositivos de E/S que no generan interrupciones vectorizadas. Internamente son manejadas exactamente igual que las vectorizadas. El nivel 7 de estas interrupciones no debe ser usado ya que no son enmascarables y pueden interrumpir al sistema en periodos de tiempo peligrosos. Por ejemplo durante el refresco de una RAM dinámica o funciones semejantes que son las que utilizan este nivel. Traps de Usuario (32-47): El trap 0 (vector 32) es usado por el OS-9 para solicitar servicios del sistema y no puede ser utilizado por el usuario. Los restantes 15 traps pueden ser utilizados para rutinas de librería a programas de usuario. Interrupciones Vectorizadas(64-255): Las 192 interrupciones vectorizadas producen una mínima cantidad de overhead en llamadas a drivers para manejar una interrupción. Las rutinas de servicio de la interrupción son ejecutadas en System State sin ningún proceso asociado. Los drivers deben proveer un punto de entrada de error para ser ejecutados por el sistema si un error de excepción ocurre durante el procesamiento de la interrupción (este punto no está implementado). La llamada del sistema F$IRQ es usada para instalar un gestionador en la tabla del sistema. Si es necesario, varios dispositivos pueden utilizar el mismo vector.

7 El Sistema de Entradas/Salidas. El sistema de E/S es modular y puede expandirse fácilmente por el usuario. El Kernel ejecuta algunos procesos de E/S (tales como localización de estructura de datos) y entonces llama al apropiado manejador de ficheros, el cual llama al correspondiente driver. Estos dos últimos son módulos estándar de memoria. El Kernel suministra el primer nivel de servicio para las llamadas al sistema de E/S, encaminando los datos entre los procesos y los file managers y drivers apropiados. Además mantiene dos importantes estructuras de datos: La tabla de dispositivo y la tabla de path.

7.1 Los File Managers. La función de los file managers es procesar el flujo de datos desde o hacia los drivers para una clase de dispositivos de similares características. RBF Random Block File Manager. Gestiona todos los dispositivos con estructura de bloque de acceso random, como los diskettes y discos duros. SCF Sequential Character File Manager. Gestiona los dispositivos secuenciales tales como terminales, impresoras y modems. SBF Sequential Block File Manager. Gestiona los dispositivos con estructura de bloque de acceso secuencial como las cintas. PIPEMAN Pipe File Manager. Gestiona las comunicaciones entre procesos a través de buffers en memoria, lo que se conoce como "pipes". Además de los file managers básicos, existen otros que son suministrados de forma opcional por Microware. PCF PC File manager. Gestiona los proceso de lectura/escritura en diskettes en formato PC-DOS. NFM Network File Manager. Procesa las solicitudes de datos a través de una Network OS-9. ENPMAN ENP10 Socket File Manager. Se encarga de la transferencia a/desde tarjetas CMC ENP10. Este File Manager está incluido dentro del Ethernet Support Package (OS-9/ESP). SOCKMAN Socket File Manager. Crea y gestiona el interface a los protocolos de comunicación (sockets). Este File Manager está incluido dentro del Ethernet Support Package (OS-9/ESP). IFMAN Communications Interface File Manager. Gestiona el interface de la Network. Este File Manager está incluido dentro del Ethernet Support Package (OS-9/ESP). PKMAN Pseudo-Keyboard File Manager. Provee un interface al SCF para permitir al software emulador un terminal. Este File Manager está incluido dentro del Ethernet Support Package (OS-9/ESP). El file manager es una colección de subrutinas accesibles desde una tabla de offset. Esta tabla contiene las direcciones de cada subrutina relativa al comienzo de dicha tabla. Cuando es llamada alguna rutina, se le pasan los parámetros adecuados en los registros definidos por el sistema. Las rutinas que tienen implementados estos gestionadores son: Create, Open, Makdir, Chgdir,

Delete, Seek, Read, Write, ReadLn, WriteLn, Getstat, Setstat, Close.

7.2 Los Drivers. Los módulos de drivers ejecutan las funciones de bajo nivel físico de E/S. Un driver es un paquete de rutinas que son llamadas por un file manager en estado de sistema. Un driver gestiona varios dispositivos físicos de iguales características, las diferencias que existen entre ellos están definidas en los descriptores de dispositivos. El sistema copia parte de la información contenida en los módulos descriptores en una estructura de datos llamada descriptor de path. Así, el sistema mantiene los datos de cada dispositivo que maneja en memoria para su mejor gestión. Esta estructura de datos está definida en las librerías "sys.l" y "usr.l". Todos los drivers tienen que seguir el formato de módulo de memoria. Las rutinas del driver son llamadas por el file manager pasándole los parámetros en los registros definidos por el sistema. Las funciones que están implementadas en el driver son: Init, Read, Write, Getstat, Setstat, Term y Irq. Estas funciones actuan directamente sobre el controlador físico del dispositivo que gestionan. Para cada dispositivo, el sistema crea una área de almacenamiento estático donde guarda variables que necesita para su correcto funcionamiento. Esta estructura de datos está también definida en las librerías "sys.l" y "usr.l".

7.2.1 Estructura General de un Driver OS-9. En este apartado queremos mostrar los pasos a realizar para desarrollar un driver del tipo SCF, es decir, que maneje dispositivos físicos orientados a carácter, como por ejemplo terminales, impresoras, modems ,etc. Para empezar, estudiaremos los drivers desarrollados por el sistema. Tomaremos como ejemplo el driver SC68562 que gestiona los controladores de comunicaciones serie de la placa de SYS68K/CPU-30, estos controladores son los DUSCC 68562. El fichero fuente del driver es el sc68562.a localizado en el subdirectorio /h0/IO. Este fichero está escrito en lenguaje ensamblador y para obtener definitivamente el driver, se unirá con la librería "sys.l". Hacemos esta operación porque en el fichero fuente, se hace referencia a formatos de módulos de memoria y estructuras de datos que utiliza el sistema para su correcta ejecución, y están definidas en dicha librería. Estas estructuras de datos son: formatos de los módulos, descriptor de procesos, descriptor de path, área de almacenamiento estático y datos globales del sistema. Los ficheros fuente que generan esta librería son: funcs.a, process.a, module.a, io.a, sysio.a, sysglob.a, scfstat.a, rbfstat.a, drvstat.a, ioglob.a, iodev.a, scfdev.a y rbfdev.a. Todos estos ficheros están localizados en el subdirectorio /h0/DEFS. En el principio del fichero fuente, colocamos la directiva PSECT del ensamblador, la cual indica que comienza el código del programa.

A continuación inicializa las variables que van a utilizar para el controlador DUSCC, que son los registros del mismo y los diferentes valores con los que se va a inicializar dicho controlador. A partir de la directiva de ensamblador VSECT, el programa declara una zona de variables estáticas que luego el sistema las utilizará para cada dispositivo en particular. Recordemos que en el OS-9, el módulo driver es de código reentrante, y eso significa que el código del driver es compartido por todos los dispositivos adecuados que lo soliciten; pero también, por cada dispositivo el sistema le crea una zona de variables por separado. Lo siguiente con lo que nos encontramos es la tabla de direcciones de las rutinas del driver. Rutina Init: Los parámetros que se le pasan a esta rutina son: (a1) = dirección del módulo descriptor de dispositivo. (a2) = dirección del área de almacenamiento estático (a4) = puntero al descriptor de proceso. (a6) = puntero a los datos globales del sistema. Esta rutina inicializa la zona de memoria estática del dispositivo, inicializa el controlador, localiza la rutina de servicio de interrupción y habilita las interrupciones. Rutina Read: Los parámetros que se le pasan a esta rutina son: (a1) = dirección del descriptor de path. (a2) = dirección del área de almacenamiento estático. (a4) = puntero al descriptor de proceso. (a6) = puntero a los datos globales del sistema. Obtenemos el carácter en d0.b Esta rutina obtiene el siguiente carácter desde el buffer de entrada. Si no hay datos, pone el proceso en estado de Sleep hasta que reciba un carácter. Cuando el carácter es recibido, la rutina de atención lo sitúa en el buffer de entrada. Rutina Write: Los parámetros que se le pasan son los mismos que en la rutina anterior. El dato a escribir lo situamos en d0.b. Esta rutina pone el dato en el buffer de salida y habilita la rutina de salida de dispositivo. si el buffer está lleno, se pone al proceso en estado de sleep hasta que se pueda escribir en el buffer. Rutinas GetStat y SetStat:

Los parámetros que se le pasan son los mismos que en el caso anterior. El código de función lo ponemos en d0.w. Estas rutinas obtienen y ponen los parámetros especificados en los requerimientos de servicio I$GetStat e I&SetStat. Rutina Term: Los parámetros que se le pasan a esta rutina son: (a1) = puntero a descriptor de dispositivo. (a2) = puntero a almacenamiento estático de dispositivo. (a4) = puntero a descriptor de proceso. (a6) = puntero a los datos globales del sistema. Esta rutina espera hasta que el buffer de salida esté vacío, deshabilita las interrupciones y borra la rutina de atención al dispositivo. Rutina Irq: Los parámetros que se le pasan a esta rutina son: (a2) = puntero al almacenamiento estático de dispositivo. (a3) = dirección del puerto. (a6) = puntero a los datos globales del sistema. Esta rutina no se incluye en la tabla de direcciones de rutinas y además no es llamada directamente desde el SCF. Las funciones que cumple son: 1) Comprobar el dispositivo, si no solicitado la interrupción, salir lo antes posible. 2) Servicio de interrupción del dispositivo (recibir o mandar un dato en los buffers). 3) Comprobar el estado del proceso. 4) Comprobar si el dispositivo está preparado para mandar mas datos. 5) Comprobar si se ha recibido un carácter de pausa. 6) Comprobar si desde el teclado se abortado el proceso.

7.3 Los Descriptores de Dispositivos. El descriptor de dispositivo es un módulo no ejecutable, contiene una tabla con valores específicos de cada dispositivo en particular. Sigue la estructura de un módulo de memoria, los campos de los cuales se componen la tabla están definidos en las librerías "sys.l" y "usr.l".

8 Comunicaciones Entre Procesos.

8.1 Señales. Las señales están preparadas para sincronizar procesos concurrentes, aunque pueden ser utilizadas para transferir pequeñas cantidades de datos. Nos podemos referir a ellas como interrupciones software, porque un proceso recibe una señal de forma semejante a como una CPU recibe una interrupción. * Si un proceso activo recibe una señal, la rutina de atención es ejecutada inmediatamente siempre que se encuentre instalada, continuando su ejecución cuando ésta termine. * Si el proceso está inactivo entonces pasará a la cola de los activos. * Si un proceso recibe una señal para la cual no posee un rutina instalada será matado. Cada señal tiene dos partes: 1) Identificador del proceso de destino 2) Código de la señal. 0 Unconditional system abort signal. 1 Wake-up signal. 2 Keyboard abort signal. 3 Keyboard interrupt signal. 4 Hang-up signal. 5-255 Reservadas. 256-65535 Definibles por el usuario. Una rutina de atención, puede ser diseñada para que pueda interpretar una palabra de código de señal como un dato. Existen cuatro funciones system calls con las que podemos controlar los procesos de comunicación a través de señales. F$Send Envía una señal a un proceso. F$Icpt Instala una rutina de atención a una señal. F$Sleep Desactiva un proceso de llamada hasta que transcurran un determinado número de ticks. F$SigMask Activa o desactiva señales. Existen funciones en C equivalentes a las anteriores para manejar las señales.

8.2 Alarmas. Existen dos tipos de alarmas, las denominadas User-state y las System-state. Alarmas User-state.

La función F$Alarm permite a un programa enviarse a sí mismo una señal. Esta puede ser enviada en una fecha determinada o de forma cíclica con un periodo de tiempo especificado. Las funciones de alarmas en user-state que se soportan son las siguientes: A$Delete Elimina una solicitud de alarma pendiente. A$Set Envía una señal después de un intervalo de tiempo. A$Cycle Envía una señal con un intervalo determinado. A$AtDate Envía una señal en un fecha y hora en formato Gregoriano. A$AtJul Envía una señal en un fecha y hora en formato Juliano. Como vemos, podemos clasificar las alarmas user-state en tres grupos. Alarmas cíclicas Alarmas en una fecha/hora determinada. Alarmas de tiempo relativo. Alarmas System-state. Las alarmas en modo system-state son equivalentes a las anteriores, con la salvedad de que son mucho más potentes, ya que cuando una alarma en user-state expira, el Kernel envía una señal al proceso que la solicitó, mientras que si expira una alarma system-state el Kernel ejecuta la rutina especificada por el proceso que la solicitó con la más alta prioridad posible.

8.3 Eventos. Los eventos en OS-9 se comportan como semáforos de valor múltiple. Son utilizados para sincronizar procesos concurrentes los cuales comparten recursos del sistema como ficheros, módulos de datos o tiempo de CPU. Por ejemplo, en el caso de que dos procesos necesiten utilizar un mismo módulo de datos en memoria, ya que es necesario sincronizarlos para que no modifiquen los datos simultáneamente. Cada evento es en realidad un variable global de 32 bytes, gestionada por el sistema y que se compone de ocho campos: Event ID Identificador del evento, es el número asignado al evento. Event name Es el nombre asignado al evento, el cual no puede exceder de 11 caracteres. Ha de ser único. Event value Es un valor entero de cuatro bytes.

Wait increment Este valor es añadido al valor del evento cuando un proceso espera por un evento. Este valor es activado cuando se crea el evento y cuando no cambia. Signal increment Este valor es añadido al valor del evento cuando el evento está señalado. Este valor es activado cuando se crea el evento y cuando no cambia. Link Count Es un contador que indica el número de usos del evento. Next event Es un puntero al próximo evento en la cola. Esta cola de evento es circular e incluye a todos los procesos que están esperando por un evento. Cada vez que un evento es señalado, esta cola es revisada. Previous event Es el puntero al proceso previo en la cola de eventos.

8.4 Pipes. Un pipe es un proceso que se comporta como una FIFO (First-In First-Out), y que permite comunicar datos entre procesos que se ejecutan concurrentemente, de forma que la salida de proceso (el proceso que escribe en el pipe) está conectada a la entrada del otro (el proceso que lee del pipe). El file manager que controla la comunicaciones entre procesos a través de pipes se denomina Pipeman y utiliza un dispositivo denominado /pipe. * Un pipe contiene por defecto 90 bytes, a no ser que se especifique un tamaño de buffer. * El proceso que lee espera al que el pipe tenga datos. * El proceso que escribe espera hasta que el pipe esté vacio. * Cualquier número de procesos pueden acceder simultáneamente a un mismo pipe. Existen dos tipos principales de pipes: pipes con nombre y sin nombre. Los pipes sin nombre son creados, típicamente, por el shell cuando se realiza un "pipeline", aunque pueden ser también utilizados por los programas de usuario. Es de destacar los siguientes puntos: * Sólo pueden ser abiertos una vez. * Procesos independientes pueden utilizarlos si el pipeline ha sido creado por un proceso padre común. Creación de Pipes Los pipes pueden ser creados utilizando /pipe para pipes sin nombre ejemplo: $ dir -u !qsort /pipe/<nombre> para pipes con nombre ejemplo: $ dir -u >/pipe/temp & qsort </pipe/temp

Los permisos que asignados a estos pipes pueden ser especificados y manejados de forma totalmente similar a la un fichero ordinario. Las funciones que podemos emplear con los pipes son las siguientes: I$Create Permite crear un nuevo pipe. I$Open Busca por un nombre especificado a través de la lista de nombre de pipes asociados con un dispositivo de pipe particular. I$Read Retorna los próximos bytes del buffer del pipe. I$ReadLn Igual que I$Read. I$Write Escribe Datos en el pipe. I$WriteLn Igual que I$Write. I$Makdir No puede ser utilizado con los pipes. I$ChgDir No puede ser utilizado con los pipes. Es interesante resaltar: * No podemos utilizar los comandos chd o makdir sobre /pipe, ya que este dispositivo no se comporta como un directorio real, pero si podremos utilizar un dir.

8.5 Módulos de Datos. Los módulos de datos permiten a diferentes procesos compartir áreas de datos y transferir datos entre ellos. Este tipo de módulos por su naturaleza deben tener un CRC válido, y una cabecera de módulo y no pueden ser de código reentrante. * El OS-9 no tiene restricciones en cuanto a contenido, organización o uso de los datos de un módulo de datos. * El OS-9 no sincroniza los proceso que utilizan estos módulos, por lo que hay que utilizar señales o eventos para permitir a varios procesos compartir estos datos. Las funciones con las cuales podremos manejar los módulos de datos son: * Especificación de un módulo de datos. _mkdata_module() o F$DatMod. * Funciones aplicables a todos los módulos. modlink(), modload(), munlink(), y munload().

Es interesante resaltar: * Al igual que el resto de los módulos OS-9, los módulos de datos, tienen un contador de link asociado. Este contador indica el número de procesos que concurrentemente acceden al módulo. Si el usuario desea que el módulo no sea eliminado de la memoria cuando el contador esté a cero, deberá activar el bit sticky del byte de atributos del módulo. * La utilidad dump puede ser usada para examinar los datos del módulo. * La utilidad save permitirá desde el sistema operativo realizar una copia en disco del módulo. * Al modificar los datos de un módulo, el valor del CRC no será correcto, por lo que habrá que calcularlo de nuevo si se desea guardalo en un fichero y cargarlo en memoria luego con un load. Para realizar ésto, podremos utilizar la función de C _setcrc(), la system call F$SetCRC, o bien utilizar la utilidad fixmod desde el sistema operativo.

9 Los Traps. Los microprocesadores de la familia 68000 de Motorola poseen 16 vectores de excepción que se denomina "traps". De éstos, el trap 0 está reservado para las llamadas al sistema OS-9, mientras que los restantes pueden ser utilizados por los manejadores de traps de usuario (user trap handlers). Un manejador de traps de usuario es un módulo OS-9 que contiene un conjunto de subrutinas. Cualquier programa puede linkarse dinámicamente a un trap de usuario y llamarlo durante el tiempo de ejecución. * Se reduce el tamaño de los programas ejecutables. * Los programas que utilizan traps son ejecutados ligeramente más lentos que los programas linkados que realizan la misma función. Microware se reserva dos trap handlers para las I/O en lenguaje C y para las funciones trigonométricas y matemáticas en punto flotantes. trap 13 El módulo CIO es llamado automáticamente por cualquier programa C. trap 15 El módulo Math es llamado para operaciones matemáticas en punto flotante, operaciones con enteros extendidos y para operaciones de conversión de tipos. Los trap handler son módulos OS-9 del tipo TrapLib que poseen tres puntos de entrada de ejecución. punto de entrada de ejecución. punto de inicialización. punto de terminación. Instalación de un Trap Hay que ejecutar F$TLink linkar el módulo Reservar e inicializar la zona de memoria estática. Ejecutar la rutina de inicialización.

10 El Editor uMACS.

10.1 Características Generales. uMACS (microMACS) es el editor de textos usado por defecto con el sistema operativo OS-9. Es utilizado para crear y modificar ficheros ASCII. Este editor se deriva del editor de texto EMACS. Sus características principales son las siguientes: * Múltiples buffers para la edición de distintos ficheros (limitados solo por el tamaño de la

memoria). * Permite editar simultáneamente varios ficheros en la misma pantalla. * Permite el movimiento del curso en cualquier dirección. * Comandos de busca y sustitución. * Permite un buffer de borrado en donde se almacena la última sección de texto borrada

pudiendo ser ésta insertada en cualquier lugar del documento editado. * Los comandos pueden ser ejecutados por sus nombres o por medio de combinaciones de

teclas. Como invocar uMACS: $ umacs {<nombre_fichero>} [<opción>] opciones: -e Todos los ficheros son abiertos para edición (defecto). -v Todos los ficheros son abiertos en modo VIEW, no pudiendo ser editados.

10.2 Los Comandos de uMACS. Antes de detallar cuales son los comandos disponibles con uMACS, hay que explicar lo siguiente: * M-A Significa usar la tecla <ESC> en primer lugar y luego la A. * ^A Significa presionar <CONTROL> simultáneamente con la tecla A. * <-- Es la tecla de borra (back space).

* Algunos comandos presentan un prompt solicitando otros comandos. uMACS intentará completar esos otros comandos tecleados. Por ejemplo si tecleamos se<espacio> completará el comando search.

* El help se solicita presionando <ESC>?, con lo que se crea una nueva ventana en la mitad

superior de la pantalla en donde podremos ver un fichero de ayuda. Podremos volver al fichero que estábamos editando con el comando ^XP o con ^X1. El primer comando deja un buffer creado con el fichero de ayuda mientras que el segundo borra el buffer.

* Cada vez que uMACS es invocado, mira y ejecuta, si existe, el fichero .umacsrc en el directorio home de cada usuario. Este fichero puede contener comandos de uMACS para personificarlo al gusto de cada usuario.

Movimientos Generales: ^V Pantalla hacia abajo ^Z Pantalla hacia arriba M-> Ir al final de fichero M-< Ir al comienzo del fichero Movimiento del Cursor: ^F Avance del cursor ^B Retroceso del cursor ^A Principio de la línea ^E Final de la línea ^N Línea próxima ^P Línea previa M-F Palabra próxima M-B Palabra previa M-P Principio del párrafo M-N Final del párrafo Búsqueda: M-S Búsqueda hacia adelante. El editor solicita el string que se ha de buscar. El string se

termina con un <ESC>. M-R Búsqueda hacia atrás. El proceso es idéntico al caso anterior. Sustituciones: ^R Sustituye todas las instancias del primer string por el segundo string que se indica.

Cada string se termina con <ESC>. M-^R Sustituye un string por otro como en el caso anterior, pero pregunta por los

siguientes comandos: ^G Cancela la operación ! Sustituye el resto de instancias ? Imprime esta lista de opciones . Salta esta sustitución y va a la siguiente Y Sustituye y continua N No sustituye y continua

Capitalización y Transposición: M-U Poner palabra en mayúsculas M-C Capitalizar palabra M-L Poner palabra en minúsculas ^T Transponer caracteres ^X^L Poner región en minúsculas ^X^U Poner región en mayúsculas M-Q Quote next entry, so that control codes may be entered into text Regiones: Una Región es definida como la zona de texto existente entre lo que se denomina una

marca y la posición actual del cursor. Para el manejo de regiones en el editor hay que definir también el Buffer de Borrado que es el último texto que ha sido borrado o guardado. Los comandos para el manejo de las regiones son los siguientes:

M-<espacio> Marca la posición actual ^X^X Intercambia marca y cursor Borrando e Insertando: <-- Borra el carácter previo M-<-- Borra la palabra previa ^D Borra el carácter siguiente M-D Borra la palabra siguiente ^K Borra hasta el final de la línea ^O Inserta una nueva línea ^W Borra la región entre la marca (que se indica con M-<espacio> ) y la posición actual

del cursor. M-W Copia la región (marca-cursor) al buffer de borrado. Copiando y Moviendo: ^W Borra la región M-W Copia la región al buffer de borrado ^Y Inserta el buffer de borrado en la posición actual del cursor. Modos de Operación: ^XM Añade modo de operación ^X^M Borra modo de operación Formateando sobre la Pantalla: ^XF Marca columna de relleno M-O Formatea párrafo ^X= Presenta información sobre el número de línea, tamaño y número de caracteres del

fichero Multiples Ventanas:

^X2 Divide la ventana actual de trabajo en dos ^X1 Restaura una única ventana de trabajo ^XO Cambia el cursor a la siguiente ventana ^XZ Aumenta de tamaño la ventana actual M-^V Realiza el scroll hacia abajo de la otra ventana M-^Z Realiza el scroll hacia arriba de la otra ventana Manejando los Múltiples Buffers: ^XB Conmuta a otro buffer ^X^B Escribe el directorio de buffer en otra ventana ^X^F Lee un fichero en un nuevo buffer ^XK Borra los buffer que no se ven en pantalla ^XX Activa el siguiente buffer de la lista Lectura de Fichero desde Disco: ^X^F Lee un fichero en un nuevo buffer ^X^R Lee un fichero en el buffer actual borrando el contenido. ^X^I Inserta un fichero en la posición actual del cursor dentro del buffer ^X^V Presenta un fichero en modo VIEW Escritura de los Ficheros en el Disco: M-Z Escribe todo los buffers cuyo contenido haya cambiado en el disco y sale del editor Acceso al Sistema Operativo: ^X! Envía un comando al sistema operativo y vuelve al programa ^XC Comienza un nuevo comando bajo uMACS ^X^C Salir de uMACS M-Z Escribe todo los buffers cuyo contenido haya sido modificado en el disco y sale del

editor Teclas especiales ^G Cancela el comando actual y retorna al nivel más alto de procesamiento ^U Permite repetir cualquier cosa. Se puede indicar a continuación el número de veces

(por defecto 4) M-<dígito> Repite en próximo comando en número de veces indicado M-X Ejecuta un comando M-K Asigna una tecla a un comando

11 La Utilidad Make.

La utilidad Make está creada para realizar el mantenimiento y re-creación de aquellos ficheros que dependen de otros ficheros. La utilidad Make en OS-9 es equivalente al Make de UNIX. Existen tres conceptos que hay que dejar claros: Makefile Se entiende que es todo aquél fichero de procedimientos, que describe las

relaciones entre el producto final y los ficheros a partir de los cuales se crea éste.

Target Es el producto final. Dependents Los ficheros a partir de los cuales se crea el target. SINTAXIS DEL FICHERO MAKEFILE: Un fichero tipo makefile contiene tres tipos de entradas 1) Entradas de dependencias: <target>:[[dependencia>],<dependencia>] 2) Entradas de comandos <target>:[[fichero>],<fichero>] <Línea de comandos OS-9> <Línea de comandos OS-9>\ <Continuación de la línea de comandos anterior> 3) Entrada de comentarios * Línea de comentarios * Línea de comentarios <Línea de comandos OS-9> # Línea de comentarios DEFINICIONES IMPLICITAS: ficheros objeto No poseen sufijos Ficheros reubicables *.r Ficheros fuente *.a, *.c, *.f, *.p Compilador cc Ensamblador r68 Linker cc Directorio default El directorio de datos actuales (.).

LOS MACROS: Make permite la utilización de macros que son reconocidos mediante el símbolo "$" delante del nombre del macro. Si el nombre del macro es de un solo carácter se puede declara por ejemplo $A o $(A). Si el nombre es de más de un carácter debe ir forzosamente entre paréntesis por ejemplo $(PFLAGS). Podemos declarar un macro dentro de cualquier lugar del fichero makefile. La sintaxis es la siguiente: < nombre_del_macro > = < lista de expansión > Existen una serie de macros especiales que son reconocidos por make: ODIR=<path> Directorio de búsqueda de los ficheros objetos y sin extensión. SDIR=<path> Directorio de búsqueda de los ficheros fuentes (*.c, *.a, *.f y

*.p ). RDIR=<path> Directorio de búsqueda de los ficheros reubicables (*.r) CFLAGS=<opciones> Opciones para el compilador. RFLAGS=<opciones> Opciones para el ensamblador. LFLAGS=<opciones> Opciones para el linker. CC=<compilador> Para indicar un compilador distinto de CC. RC=<ensamblador> Para indicar un ensamblador distinto de r68. LC=<linker> Para indicar un linker distinto de CC. Existen otra serie de macros que son expandidos: $@ Expande el nombre del fichero hecho por el comando. $* Expande el prefijo del fichero que se va a hacer. $? Expande la lista de ficheros que fueron encontrados. OPCIONES DEL PROGRAMA MAKE: Syntax: make {[<-opts>] [< target file >] [< macros >]} Function: keep track of modules for a file Options: -b don't use built-in rules -bo don't use built-in rules for object files -d debug mode, print out the file dates in makefile -dd double debug mode, very verbose -f[=]<xxx> use <xxx> as the makefile (default: makefile) -f- reads the makefile from stdin

-i ignore errors on commands and keep going -n don't execute commands, just print them out -s silent mode, execute commands without echoing them -t update the dates without executing the commands -u do the make whether it needs it or not -x use the cross compiler -z[=<path>] get list of files to make from stdin or path

12 El Compilador C.

12.1 Introducción. Las características del Compilador C de Microware son las siguientes: * Implementación de todo el lenguaje C * Eficiencia en la generación desde el punto de vista de código rápido y compacto. * Genera código independiente de la posición, reentrante y capaz de ser ubicable en ROM. * Velocidad de compilación alta. * Librerías estándar compatibles entre OS-9 y UNIX. Existe dos versiones del compilador; la que genera código para el 68000 y la que lo hace para el 68020. En ambos casos la forma de trabajar es la misma con la única diferencia que el compilador para el 68020 emplea las capacidades adicionales de la MPU del 68020 y del coprocesador matemático 68881. El lenguaje C que se utiliza se ajusta a las especificaciones de Brian W. Kernighan y Dennis M. Ritchie publicadas en su libro "The C Programming Language".

12.2 Ficheros Ejecutables. cc Programa compilador cpp Macro preprocesador c68 Realiza el paso de compilación (68000) * c68020 Realiza el paso de compilación (68020) o68 Optimizador. r68 OS-9/68000 macro assembler * r68020 OS-9/68020 macro assembler l68 OS-9/68000 linker cio Manejador Trap para la librería C de E/S del 68000 * cio68020 Manejador Trap para la librería C de E/S del 68020

Los módulos marcados con (*) son específicos para generar código para el 68020.

12.3 Ficheros de Librerías. Los ficheros de librería son indispensables durante el proceso de compilación y pueden ser encontrados en el directorio /h0/LIB del sistema. cstart.r Contiene los códigos de startup para programas compilados. clib.l Contiene la librería estándar, las funciones matemáticas y las librerías del sistema. clibn.l Contiene lo mismo que la librería clib.l pero no utiliza el gestionador de trap

matemático (math trap handler) para las operaciones en punto flotante. Las rutinas que realizan estas operaciones se extraen de la librería math.l.

clib020.l Contiene la librería estándar, funciones matemáticas y librerías del sistema

para el 68020. clib020n.l Contiene lo mismo que la librería clib020.l pero no utiliza el gestionador de

trap matemático para las operaciones en punto flotante. Las rutinas que realizan estas operaciones se extraen de la librería math.l.

clib020h.l Contiene lo mismo que la librería clib020n.l pero no utiliza el coprocesador

matemático 68881 para las operaciones en punto flotante. math.l Contiene las mismas funciones que el gestionador de trap matemático, pero en forma

autónoma. math881.l Librería equivalente a la math.l, pero se utiliza el coprocesador matemático

68881. sys.l Contiene las definiciones globales del sistema. termlib.l Contiene las funciones de manipulación de la base de datos termcap para el

manejo de terminales.

12.4 Ficheros de Definiciones. Los ficheros de definiciones contienen definiciones de macros, constantes y estructuras de datos para las funciones de librería, y pueden ser encontrados en el directorio /h0/DEFS. ctype.h Definiciones de tipos y macros. dir.h Definiciones de funciones de manejo de los directorios. direct.h Definiciones de los formatos de los directorios del OS-9. errno.h Definiciones de los números de error del OS-9.

events.h Definiciones de los subsistemas de eventos. math.h Definiciones de las funciones matemáticas. modes.h Definiciones de los valores de los permisos de ficheros. module.h Definiciones de la estructura de los módulos de memoria. procid.h Definiciones de la estructura de los descriptores de procesos. setjmp.h Definiciones de las funciones setjmp y longjmp. setsys.h Códigos de petición para la función setsys. sgstat.h Estructura para las funciones getstat, setstat y ss_opt. signal.h Definiciones para el uso de señales OS-9. stdio.h Definiciones I/O estándar. termcap.h Definiciones de la librería de manejo de terminales. time.h Definición del buffer para las funciones getime y setime. types.h Definiciones de tipos estándar.

12.5 Opciones del Compilador. La sintaxis de la línea de comandos para invocar al compilador es la siguiente: $ cc [<opciones>] <fichero> { <fichero> [opciones] } Las opciones son reconocidas antes de comenzar la compilación, por lo que pueden ser introducidas en cualquier orden. También pueden ser agrupadas excepto cuando una opción especifica un argumento. Por ejemplo es lo mismo $ cc fichero.c -i -g -f=prog que $ cc fichero.c -igf=prog Los tipos de ficheros que se pueden utilizar son, .c Fichero fuente C. .a Fichero en código ensamblador. .r Módulo reubicable. los cuales pueden ser utilizados por el compilador cc para realizar cuatro tareas:

1.- Preprocesamiento del código fuente. 2.- Compilación y generación del código ensamblador. 3.- Ensamblaje a un módulo reubicable. 4.- Unión de distintos código binarios ejecutables. Las opciones con las que podemos invocar al programa son las siguientes: ┌──────────┬──────────────────────────────────────────────────────────────┐ │Opción │Descripción │ └──────────┴──────────────────────────────────────────────────────────────┘ -a Elimina la fase de ensamblaje, por lo que a partir de un fichero .c genera un fichero

.a en código ensamblador. -bg Activa el bit sticky en la cabecera del módulo que se genere de forma que éste

permanecerá en memoria incluso si el contador de link llega a ser cero. -bp Imprime los argumentos pasados durante cada fase de compilación y los mensajes de

status de salida de cada programa. -c Generará que se imprima el código fuente como comentario en el fichero en

ensamblador de salida. Este opción es de mayor utilidad si se utiliza con la opción -a.

-d<ident> Es equivalente a utilizar un #define <ident> en el fichero fuente. Esta opción se

utiliza cuando en un fichero fuente tenemos distintas versiones de un mismo programa diferenciadas mediante la utilización de las directivas del preprocesador #ifdef o #ifndef. El identificador <ident> es usado como un macro por el preprocesador para la expansión del fichero. El valor del identificador será "1" si se define como -d<ident>, o el valor del string especificado de la forma -d=<ident>=<string>.

-e=<número> Activa el byte que guarda el número de la edición en la cabecera del módulo OS-9. -f=<pathlist> Al fichero de salida se creará en el directorio especificado en el <pathlist>. El

nombre del módulo generado será el mismo que el del fichero fuente, a menos que utilicemos la opción -n=<nombre>. Esta opción producirá un error si simultáneamente se utilizan las opciones -a o -r. Si el <pathlist> es relativo, se refiere que es relativo con respecto al directorio de actual de ejecución.

-fd=<pathlist> Esta opción es idéntica a la -f=<pathlist> con la excepción de que si el <pathlist> es

relativo, se refiere a que es relativo con respecto al directorio de datos actual. -g Causa que el linker genere un módulo simbólico que puede ser utilizado por el

depurador de alto nivel. El módulo simbólico tiene el mismo nombre que el fichero de salida con la extensión .stb añadida. Si en el directorio de trabajo existe un

subdirectorio con el nombre STB este fichero se cargará en él, en caso contrario aparecerá en el mismo directorio del fichero de salida.

-i Causa que el programa esté "linkado" con la librería cio.l. Este genera que todas las

llamadas de librería sean gestionadas por el gestionador trap denominado cio. -j Para la creación de la "jumptable". -k=<n>[w|l][cw|cl][f] <n> tipo de máquina target: 0=68000(por defecto), 2=68020. w offset de datos de 16 bit (por defecto 68000). l offset de datos de 32 bit (por defecto 68020). cw referencias de código de 16 bit (por defecto 68000). cl referencias de código de 16 bit (por defecto 68020). f causa que el 68020 genere código para el 68881. -l=<path> Especifica un fichero de librería a ser utilizado antes que las librería estándar,

matemática o la librería de interface del sistema. -m=<tamaño memoria> Indica la cantidad de memoria a utilizar por el linker para el stack de programa. El

tamaño se indica en Kbytes, por defecto se consideran 2 Kbytes. -n=<nombre> Especifica el nombre del módulo de salida. -o Inhibe la fase de optimización del código ensamblador. Su utilización se recomienda

durante las etapas de depuración ya que significa una disminución del tiempo de compilación.

-q No se indica en pantalla la ejecución de los pasos intermedios de compilación, sólo

se presentan los mensajes de error sis ocurren. -r[=<dir>] Suprime la fase del linker y genera un fichero reubicable (extensión .r). Si se

especifica un directorio, este fichero se creará en él. -s Para la generación del código de stack-checking. Esta opción debe ser utilizada con

cuidado cuando en una aplicación el tiempo de ejecución es muy crítico. -t=<dir> Causa que los ficheros temporales usados en cualquier fase de compilación se sitúen

en el directorio indicado. Esto es útil si indicamos que los ficheros se sitúen en el ramdisk (-t=/r0), ya que es este caso el tiempo de compilación será disminuido drásticamente.

-u<nombre> Cancela la definición del macro del pre-procesador <nombre>. Existen dos macros

pre-definidas en el pre-procesador, que son OSK y mc68000. Estos nombres son utilizados para identificar el compilador bajo el cual el programa está siendo compilado, y se utiliza para escribir programa independientes del hardware.

-v=<dir> Especifica un directorio adicional en el cual se van a buscar ficheros #include.

Podemos incluir esta opción varias veces para indicar distintos directorio de búsqueda. Esta búsqueda comenzará en el orden de la línea de comandos, buscándose en último lugar en el directorio DEFS en donde se encuentran los ficheros de definiciones del sistema.

-w=<dir> Especifica el directorio que contiene los ficheros de librería como cstart.r, clib.l,

etc.. -x Causa que el compilador genere instrucciones trap para acceder a las rutinas

matemáticas en punto flotante. Esto origina que el programa utilice el módulo gestionador de trap, en lugar de extraer el código desde una librería matemática. Esta opción ha de ser utilizada tanto con el compilador como con el linker.

12.6 Funciones de Librerías. Funciones ANSI. asctime() clock() ctime() difftime() gmtime() localtime() memchr() memcmp() memcpy() memset() mktime() time() Funciones de Clasificación de Caracteres. isalnum() isalpha() isascii() iscntrl() isdigit() islower() isprint() ispunct() isspace() isupper() isxdigit() Funciones de Conversión de Caracteres. _tolower() _toupper() atof() atoi() atol() toascii() tolower() toupper()

Funciones Matemáticas. abs() acos() asin() atan() ceil(x) cos() exp() fabs() floor(x) hypot() log() log10() modf() pow() sin() sqrt() tan() Funciones de Manejo de Memoria. _freemin() _srqmem() _srtmem() calloc() ebrk() free() ibrk() malloc() realloc() sbrk() Funciones Misceláneas. _errmsg() _prgname() _strass() closedir() freemem() longjmp() mktemp() opendir() qsort() readdir() rewinddir() seekdir() setjmp() stacksiz() system() telldir()

Funciones del Sistema Operativo OS-9. _cmpnam() _cpymem() _ev_creat() _ev_delete() _ev_info() _ev_link() _ev_pulse() _ev_read() _ev_set() _ev_setr() _ev_signal() _ev_unlink() _ev_wait() _ev_waitr() _get_module_dir() _get_process_desc() _get_process_table() _getsys() _gs_devn() _gs_eof() _gs_gfd() _gs_opt() _gs_pos() _gs_rdy() _gs_size() _julian() _mkdata_module() _parsepath() _setcrc() _setsys() _ss_attr() _ss_dconff() _ss_dcon() _ss_dsrts() _ss_enrts() _ss_lock() _ss_opt() _ss_pfd() _ss_rel() _ss_rest() _ss_size() _ss_ssig() _ss_tiks() _ss_wtrk() _sysdate() _sysdbg() alm_atdate() alm_atjul() alm_cycle() alm_delete() alm_set()

chain() crc() create() detach() getstat() intercept() makdir() make_module() modcload() modlink() modload() modloadp() munlink() munload() os9exec() os9fork() os9forkc() readln() setstat() sigmask() srqcmem() tsleep() unlinkx() writeln() Funciones Estándar de I/O. cleareof() clearerr() fclose() fdopen() feof() ferror() fflush() fgetc() fgets() fileno() fopen() fprintf() fputs() fread() freopen() fscanf() fseek() ftell() fwrite() getc() getchar() pffinit() pfintf() putc() putchar() puts()

putw() rewind() scanf() setbuf() sprintf() sscanf() ungetc() Funciones de Manejo de String. findnstr() findstr() index() rindex() strcat(9 strcmp() strhcpy() strlen() strncat() strncmp() strncpy() Funciones de Manejo del Terminal (Termcap). tgetent() tgetflag() tgetnum() tgetstr() tgoto() tputs() Funciones del Sistema Tipo-UNIX. _exit() access() chdir() chmod() chown() close() creat() dup() exit() getenv() getime() getpid() getuid() kill() lseek() mknod() open() pause()

prerr() read() setime() setpr() setuid() sleep() unlink() wait() write()

12.7 La Librería Termcap. El sistema operativo OS-9 utiliza para realizar el interface con el usuario la librería TERMCAP. Este método consiste en tener un fichero texto denominado termcap el cual contiene las definiciones de los códigos de control que utilizan los distintos tipos de terminales. Para el manejo de esta información se dispone de una serie de funciones que acceden a la base de datos y extraen información acerca de las características del terminal. Se ha de resaltar que estas funciones sólo extraen información de la base de datos, siendo el propio programa que las maneja el que determina que capacidades serán utilizadas. La forma que tiene el sistema de saber qué tipo de terminal se encuentra definido, es a través de la variable de entorno TERM. La forma de definir por ejemplo que trabajamos con un terminal tipo VT100 es la siguiente: $ setenv TERM vt100 Si queremos saber en un momento determinado, que tipo de terminal se encuentra definido podemos utilizar el comando "printenv" que nos indicará cuales son las variable de entorno que se encuentra definidas. $ printenv ... TERM=vt100 ... El fichero que almacena la información de los terminales es /dd/SYS/termcap este fichero no ha de ser manipulado por el usuario del sistema, a no ser que se desee realizar la descripción de un nuevo terminal que no se encuentra definido. Una descripción detallada del formato de este fichero se puede encontrar en el apartado "The Termcap File Format" del manual "OS-9 System Management". La funciones para maneja este fichero desde un programa C se encuentran definidas en la librería /dd/LIB/termlib.l. tgetenv()

tgetflag() tgetnum() tgetstr() tgoto() tputs()

13 El Ensamblador y Linker.

13.1 Introducción. Las principales características del ensamblador y linker son las siguientes: * Soporta el entorno multitarea y modular del OS-9. * Funciones de llamada al sistema operativo OS-9 y generación de traps. * Genera código reentrante y reubicable. * Permite que programas que se han escrito y ensamblados separadamente sean "linkados"

juntos, lo que posibilita la creación de librerías por parte del usuario. * Plena capacidad de manejar macros. * Puede generar código "stand alone" para los micros 68000/68020.

13.2 Formato del Fichero de Entrada. El ensamblador r68 es capaz de leer un fichero fuente líneas con una longitud máxima de 256 caracteres. En cada una de estas líneas pueden existir cuatro campos: 1 Campo de etiqueta (opcional). 2 Campo de operación. 3 Campo de los operandos. En donde puede haber cero aperandos o más operandos

dependiendo del tipo de operación. 4 Campo de comentarios (opcional). Hay que hacer constar que existen dos casos especiales a considerar: * Una línea cuyo primer carácter es un asterisco (*) es considerada como una línea de

comentario. La línea entera es impresa en el listado de salida del ensamblador, pero no afecta al proceso.

* Líneas dejadas en blanco se imprimen en el fichero de salida y también son ignoradas. Campo de Etiqueta.

El campo de etiqueta comienza en el primer carácter de la línea. Si la línea no contiene este campo el primer carácter debe ser un blanco o un tabulador. Si la etiqueta está presente, entonces el ensamblador le asignará la dirección del primer byte de código.

Cuando un nombre simbólico en el campo de etiqueta es seguido por dos puntos (:), el

nombre se dice que es global para todos los módulos que se "linken" juntos. Si los dos puntos no aparecen después de la etiqueta, ésta sólo será reconocida dentro del psect donde fue definida.

Las etiquetas pueden tener un máximo de 256 caracteres con mayúsculas o minúsculas,

digitos decimales, signo de dolar ($), punto (.), o underscore (_). El primer carácter debe ser una letra,. Los caracteres en mayúsculas y minúsculas con considerados distintos.

Campo del Operando. Este campo especifica una instrucción en lenguaje máquina o una directiva del ensamblador.

Inmediatamente después deben de haber al menos un blanco. Los nombre de los mnemotécnicos de las intrucciones pueden ser escritos en mayúsculas o minúsculas indistintamente.

Campo de Operación. Este campo no es utilizado en todas las ocasiones ya que no todas las instrucciones lo usan.

Otras instrucciones o directiva del ensamblador necesitan una dirección, un operando y/o un parámetro.

Campo de Comentarios. El último campo es el campo de comentarios. Puede ser utilizado para incluir una

descripción de la línea del ensamblador.

13.3 Los Macros. Un macro es una secuencia de instrucciones que pueden ser utilizadas en numerosos lugares de un programa. A cada macro se le asigna un nombre, el cual puede ser utilizado como cualquier otro mnemotécnico de una instrucción. A la hora de ensamblar el fichero, cada llamada a un macro será expandida con correspondiente secuencia de instrucciones. La estructura de un macro es la siguiente: <nombre> macro El estamento macro indica el comienzo del macro. . . Cuerpo del macro . . endm El estamento endm indica el final del macro. A la hora de asignar un nombre al macro podemos utilizar cualquier nombre de etiqueta válida, sólo tendremos de tener cuidado si re-definimos alguna de las directivas del ensamblador.

El cuerpo del macro puede contener cualquier número de instrucciones o directivas, incluidas referencias a macros definidos con anterioridad. Siempre debemos terminar el macro con endm. El Uso de Argumentos en un Macro. La utilización de argumentos permiten variaciones en la expansión del macro. Se permiten un máximo de 9 argumentos. Cada argumento consiste en un (\) seguido de un número (\1,\2,...\9). Cuando el macro es expandido cada argumento es sustituido por el string correspondiente en la llamada del macro. Supongamos que definimos el siguiente macro que realiza la secuencia de intrucciones para llamar a I$WritLn. writ macro moveq #\1,d0 Obtiene un path. moveq #\2,d1 Número de caracteres a escribir. lea \3(a6),a0 Obtiene la dirección del buffer. os9 I$WritLn endm Cuando referenciemos el macro, podremos hacerlo de la forma siguiente: writ 1,2,Buf con lo que el macro expandido, y por lo tanto el código que se genera será moveq #1,d0 moveq #2,d1 lea Buf(a6),a0 os9 I$WritLn Existen dos operadores especiales que pueden ser utilizados par construir macros más complejos. \Ln Devuelve la longitud del argumento n en número de bytes. \# Devuelve el número de argumentos pasados a un programa.

13.4 Las Secciones de un Programa Reubicable. Uno de los objetivo principales del ensamblador es permitir utilizar como parte de un mismo programa, segmentos ensamblados separadamente. Por segmentos entenderemos los distintos ficheros fuentes. Los procesos en OS-9 utilizan al menos dos áreas separadas de memoria. El área de código de programa y el área de datos utilizada para las variables del programa y como stack. El linker es el encargado de combinar los distintos segmentos en un único módulo OS-9. Las variables de uso global pueden ser declaradas en un segmento y referenciadas en otro.

Cada segmento debe ser dividido en dos secciones, una de variables (vsects) y la otra para instrucciones de programa (psects). Las distintas secciones de cada segmento de un programa son combinadas por el l68 de la siguiente manera. Módulo de Memoria Ejecutable ┌────────────────────────────┐ │ Cabecera del Módulo │ Generada por l68 ├────────────────────────────┤ │ Código Objeto - Segmento A │ psect del segmento A ├────────────────────────────┤ │ Código Objeto - Segmento B │ psect del segmento B ├────────────────────────────┤ │ Código Objeto - Segmento C │ psect del segmento C ├────────────────────────────┤ │ Variables Inicializadas │ ├────────────────────────────┤ │ C R C │ Generado por el l68 └────────────────────────────┘

Area de los Datos del Proceso ┌───────────────────────────────────────────┐ │ Seg. A: Variables Locales SIN-Inicializar │ ├───────────────────────────────────────────┤ │ Seg. B: Variables Locales SIN-Inicializar │ ├───────────────────────────────────────────┤ │ Seg. C: Variables Locales SIN-Inicializar │ ├───────────────────────────────────────────┤ │ Seg. A: Variables Locales Inicializadas │ ├───────────────────────────────────────────┤ │ Seg. B: Variables Locales Inicializadas │ ├───────────────────────────────────────────┤ │ Seg. C: Variables Locales Inicializadas │ ├───────────────────────────────────────────┤ │ Seg. A: Variables Remotas Inicializadas │ ├───────────────────────────────────────────┤ │ Seg. B: Variables Remotas Inicializadas │ ├───────────────────────────────────────────┤ │ Seg. C: Variables Remotas Inicializadas │ ├───────────────────────────────────────────┤ │ Seg. A: Variables Remotas SIN-Inicializar │ ├───────────────────────────────────────────┤ │ Seg. B: Variables Remotas SIN-Inicializar │ ├───────────────────────────────────────────┤ │ Seg. C: Variables Remotas SIN-Inicializar │ └───────────────────────────────────────────┘ La Directiva Psect: La directiva psect indica una sección de código de programa, por lo que sólo puede haber una por fichero fuente. El final de esta sección se indica con endsect. psect <name>,<typelang>,<attrv>,<edition>,<stacksize>,<entrypt>,<trapent> name Nombre de hasta 20 caracteres que identifica la sección psect. typelang Indica el tipo de lenguaje que se ha utilizado. Si este psect no es el principal, su valor

debe dar cero. attrev Un expresión que se utiliza como palabra de atributo/revisión del módulo ejecutable. edition Una expresión a ser utilizada como palabra de edición del módulo ejecutable. stacksize Estimación de la cantidad de memoria de stack requerida por esta psect. entrypt Es una palabra tipo long que se utiliza como offset al punto de entrada del psect. trapent Indica el offset al punto de entrada de trap sin inicializar.

Los estamentos que pueden ser utilizados dentro de la definición de una sección psect son los siguientes: Cualquier instrucción (mnemonico) del 68000. dc dz align vsect endsect os9 tcall ends La Directiva Vsect: Los estamentos que pueden ser utilizados dentro de la definición de una sección vsect son los siguientes: ds dc dz endsect align La sección vsect contiene variables inicializadas o sin inicializar, o definiciones de variables remotas inicializadas y sin inicializar.

13.5 Las Directivas del Ensamblador. Las directivas dan información que afecta los procesos de ensamblaje, pero normalmente no generan código. end equ/set fail if...else...endc nam/ttl opt pag/spc rept...endr use Existen también las denominadas Pseudo-Instrucciones, que generan código, pero que no corresponden al actual juego de instrucciones del 68000. Su objetivo principal es crear secuencias especiales de código y/o datos constantes a incluir en el programa. Las etiquetas son opcionales en las pseudo -instrucciones. Sus nombres son: align

com dc ds dz do/lo/org os9 tcall

13.6 Opciones del Ensamblador. La sintáxis de la línea de comandos para invocar al ensamblador es la siguiente: $ r68 <fichero> [<opciones>] En caso de querer generar código para el 68020 la sintáxis será totalmente equivalente, pero en lugar de utilizar r68 utilizaremos r68020. Las opciones que siguen al nombre del fichero pueden estar separadas por espacios o por comas. Una opción se activa con (-), mientras que con (--) se desactiva, permitiéndose hasta un máximo de 10 opciones en la línea de comandos. Al igual que en el compilador C, las opciones se pueden agrupar siempre que en medio de una agrupación no exista alguna que necesite argumentos adicionales. Por ejemplo, las dos líneas de comandos siguientes equivalentes. $ r68 programa.a -l -s --c >/p $ r68 programa.a -ls --c >/p Las opciones con las que podemos invocar al programa son las siguientes: ┌──────────┬──────────────────────────────────────────────────────────────┐ │Opción │Descripción │ └──────────┴──────────────────────────────────────────────────────────────┘ -a[=]<símbolo>[=<valor>] Permite definir un símbolo antes de ensamblar un fichero. El símbolo queda definido

igual que si hubiesemos utilizado la directiva set en el fichero. Si al definir el símbolo no asignamos ningún valor, por defecto será "1", en caso contrario será el valor indicado.

-c Imprime líneas de ensamblaje condicional en el listado del ensamblador. Esta opción

por defecto no está activada. -d<numero> Asigna el número de líneas por página, por defecto el valor es 66. -e Suprime los mensajes de error. Por defecto esta opción está desactivada. Esta opción

no tiene sentido a menos que la utilicemos conjuntamente con la opción -l.

-f Usa un form feed en los listados de salida para cambiar de página, en lugar de un line feed. Está desactivada por defecto.

-g Lista todo los códigos generados. No tiene sentido si no se utiliza conjuntamente con

la opción -l. Por defecto desactiva. -l Produce la escritura formateada del listado del ensamblador en la salida estándar (la

pantalla). Para tener este listado del fichero hay que redireccionar la salida con >/p hacia la impresora o con >nombre_fichero hacia un fichero. Esta opción está desactivada por defecto, por lo que normalmente solo se ven en patalla los mensajes de error.

-m=<número> Especifica el ensamblador a ser utilizado. 0=68000/68020 por defecto. -n Omite el número de líne en el listado del ensamblador. Se utiliza conjuntamente con

-l. -o=<path> Escribe la salida reubicable en el fichero indicado. -q Elimina la impresión de los warnings y errores no fatales. -s Imprime la tabla de símbolos al final del listado del ensamblador. -v Indica la versión del ensamblador y el número de edición en la salida estándar de

error. -x Imprime las expansiones de los macros en el fichero de salida. User-State System Calls. F$Alarm F$AllBit F$CCtl F$Chain F$CmpNam F$CpyMem F$CRC F$DatMod F$DelBit F$DExec F$DExit F$DFork F$Event F$Exit F$Fork F$GBlkMp F$GModDr F$GPrDBT F$GPrDsc F$Gregor F$ID

I$Read

F$Icpt F$Julian F$Link F$Load F$Mem F$PErr F$PrsNam F$RTE F$SchBit F$Send F$SetCRC F$SetSys F$SigMask F$Sleep F$SPrior F$SRqCMem F$SRqMem F$SRtMem F$SSpd F$STime F$STrap F$SUser F$SysDbg F$Time F$TLink F$Trans F$UAcct F$UnLink F$UnLoad F$Wait I/O System Calls. I$Attach I$ChgDir I$Close I$Create I$Delete I$Detach I$Dup I$GetStt I$MakDir I$Open

I$ReadLn I$Seek I$SetStt I$Write I$WritLn System-State System Calls.

F$Alarm F$AllPD F$AllPrc F$AProc F$DelPrc F$FindPD F$IOQu F$IRQ F$Move F$NProc F$Panic F$RetPD F$SSvc F$VModul

14 Paquete de Comunicaciones OS-9/ESP.

14.1 Introducción. El paquete de software OS-9/ESP permite la comunicación entre los sistemas operativos OS-9 y UNIX, con el control de protocolo de transmisión TCP/IP funcionando en red Ethernet. El OS-9/ESP suministra un interface de programación con una librería de funciones en C que facilita la creación de procesos de comunicación. Con este paquete se facilitan utilidades de transferencia de ficheros entre la red (ftp), y la conexión de terminales a sistemas remotos en red (telnet). El paquete se distribuye en un disco con todo el software necesario y un manual de instalacion. El software del paquete se suministra en diferentes partes: * Módulos de Sistema. * Ficheros de Librería. * Ficheros de Definición. * Ficheros de Datos. * Utilidades. Módulos de Sistema. Los siguientes ficheros de sistema tienen que localizarse en el directorio

CMDS/BOOTOBJS del dispositivo de almacenamiento por defecto del sistema: enp pk enp10dvr pkdvr enp10firm pks enpman socket enpsdvr Estos módulos son manejadores de ficheros, drivers y descriptores necesarios para el

OS-9/ESP. Ficheros de Librería. Los siguientes ficheros de librería tienen que estar presentes en el directorio LIB del

dispositivo de almacenamento por defecto del sistema: netdb.l socklib.l El paquete 0S-9/ESP suministra una librería en C para crear programas que accedan

directamente a las funciones de comunicación. Ficheros de Definición.

Los siguientes ficheros de definición deben estar incluidos en el directorio DEFS del

dispositivo de almacenamiento por defecto del sistema: netdb.h socket.h in.h Estos ficheros se usan con las funciones en C que facilita el paquete. Ficheros de Datos. El paquete OS-9/ESP usa un módulo de datos (inetdb) que contiene los ficheros de datos:

hosts, networks, services y protocols. Los datos de esos ficheros se guardan en un módulo para permitir un sistema basado totalmente en ROM. El módulo inetdb se crea desde los cuatro ficheros de datos con la utilidad idbgen.

Utilidades. Las siguientes utilidades son suministradas por el disco de distribución y deben localizarse

en el directorio CMDS del dispositivo de almacenamiento por defecto del sistema: enpstat ftpd ibdgen telnetd ibddump ftpdc ftp telnetdc telnet.

14.2 Inicialización del Paquete OS-9/ESP. Una vez instalado el hardware, construido el módulo inetdb y localizados los ficheros requeridos en los directorios apropiados, se debe preparar el sistema para su puesta en marcha y funcionamiento. Se debe crear el descriptor enp para el sistema siguiendo las instrucciones que se dan en el fichero "ReadMe", localizado en el directorio ENP del disco de distribución. El fichero de procedimientos load.esp puede usarse como guía para preparar los módulos ESP. Para inicializar el hardware, hay que correr la utilidad enpstat que testea los drivers de acceso al ENP-10. Una vez inicializado el ENP-10 por los drivers, se muestra el estado del sistema y el OS-9/ESP está preparado para su uso.

14.3 Usando OS-9/ESP. Hay cinco utilidades suministradas para el uso del paquete software OS-9/ESP:

enpstat Esta utilidad genera un informe del estado del sistema. ftp Esta utilidad se usa para transferir ficheros desde y hacia sistema remotos. Tiene diferentes

comandos que facilitan la manipulación entre sistemas. idbgen Esta utilidad se usa para construir el modulo de datos inetdb desde los ficheros de datos:

hosts, network, protocols y services. Se debe correr cada vez que se modifica alguno de ellos.

idbdump Esta utilidad se usa para mostrar los diferentes registros de los módulos de datos. telnet Esta utilidad da al usuario una ayuda para la comunicción entre sistemas en el sistema

Ethernet. Entre otras funciones, permite la posibilidad de "log on" en sistemas remotos.

14.4 Librerías C. El paquete OS-9/ESP es un modelo de comunicación entre tareas basado en socket. Los sockets son los puntos finales de los caminos de comunicación entre sistemas. Para usar un socjet, se tienen que seguir los siguientes pasos: 1. Crear un socket. Para hacerlo, usamos la función socket(). Esta llamada crea un socket con

una dirección específica y un protocolo para ser usado. Esta función retorna un numero del camino para usarse con la función bind().

2. Nombrar un socket, para ello se utiliza la función bind(). Una vez asociado un nombre a un

socket, puede ser abierto de dos formas usando las funciones: listen() y connect(). 3. Conectar un socket como pasivo. Para hacerlo, llamamos a la función listen() que abre un

socket en espera de conectarlo con otro socket activo. 4. O conectar un socket como pasivo. Para ello, usamos la función connect() que inicia la

conexión con un socket pasivo. Este último debe estar preparado y es especificado por su nombre que lo da la función getpeername().

Una vez que se ha realizado la conexión entre los sockets activo y pasivo, la conexión se completa por la llamada accept() dada por el socket pasivo. Posteriormente, los datos se transfieren con las funciones read(), write(), recv(), recvfrom(), send() y/o sendto(). Librería Internet de OS-9/ESP. Esta librería suministra funciones para recoger información desde varios fichero de datos, y

funciones que manejan direcciones de la red. Las funciones son: endhosttent() endnetent() endprotoent() endservent() gethostent() gethostbyaddr() gethostbyname() getnetent() getprotobynumber()

getservent() getservbyname() getservbypot() inet_addr() inet_lnaof() inet_makeaddr() inetof() inet_network() inet_ntoa() sethostent() setpeerent() setprotoent() setservent() Librería Socket de OS-9/ESP. Esta librería ofrece una ayuda para la comunicación entre los sistemas. Las funciones son: _ss_sevent() acept() bind() connect() gethostname() getpeername() getsockname() getsockopt() listen() recv() recvfrom() send() sendto() setsockopt() shutdown() socket()

ANEXO II ESTRUCTURA DEL DRIVER DE LA TARJETA SYS68K/ISIO-1 nam DUSCC ttl Interrupt-Driven DUSCC (68562) driver * Copyright 1986 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. ******************************** * Edition History * # date Comments by * __ ________ _________________________________________ ___ * 01 88/12/15 genesis srw * 02 89/05/24 fixed bug in setting a/b common registers srw * 03 89/06/12 major overhaul! too numerous to note srw Edition equ 3 Typ_Lang set (Drivr<<8)+Objct Attr_Rev set (ReEnt<<8)+0 psect sc68562_a,Typ_Lang,Attr_Rev,Edition,0,DUSCCEnt use defsfile ************************ * Interrupt-driven DUSCC Device Driver *InpSiz set 80 input buffer size *InpSiz set 256 input buffer size *OutSiz set 140 output buffer size ifdef IPBUF ifeq IPBUF-1 fail must specify a value for IPBUF endc InpSiz set IPBUF set user defined buffer size else InpSiz set 256 input buffer size endc IPBUF ifdef OPBUF ifeq OPBUF-1 fail must specify a value for OPBUF endc OutSiz set OPBUF set user defined buffer size else OutSiz set 140 output buffer size endc OPBUF Low_Cnt set 10 # of bytes to restart receive data ************************ * DUSCC register equates CMR1 equ 0 channel mode reg 1 CMR2 equ 1 channel mode reg 2 S1R equ 2 SYN reg 1 S2R equ 3 SYN reg 2 TPR equ 4 tx param reg TTR equ 5 tx timing reg RPR equ 6 rx param reg RTR equ 7 rx timing reg CTPRH equ 8 counter preload high reg CTPRL equ 9 counter preload low reg CTCR equ $a counter control reg OMR equ $b output/misc reg

Fichero Driver del sistema OS-9, este driver se encarga de definir las rutinas de control de las comunicaciones serie de la placa principal del sistema. El controlador de estas comunicaciones es el DUSCC 68562. Cabecera del módulo driver. Se definen las constantes utilizadas por el driver. Estas definiciones son referidas a los buffers de datos. Se definen los registros del controlador físico.

CTL equ $d counter low reg PCReg equ $e pin config reg RCCR equ $f channel command reg TxFIFO equ $10 tx FIFO RxFIFO equ $14 rx FIFO RSR equ $18 rx status reg TRSR equ $19 tx/rx status reg GSR equ $1b general status reg (both channels!) ICTSR equ $1a input/counter status reg IER equ $1c interrupt enable reg IVR equ $1e interrupt vector reg (both channels!) ICR equ $1f interrupt control reg (both channels!) ************************ * DUSCC register value equates TXdis equ $03 disable transmitter RXdis equ $43 disable receiver CM1val equ $07 async, no parity (default); channel mode 1 CM2val equ $38 normal op, polled or interrupt; channel mode 2 PCRval equ $44 x2, rts, rtxc input, txclk; pin config TPRval equ $73 1 stp, idl, mrks, no teom, rts cts 8 bit (default); tx param TTRval equ $30 BRG clk source; tx timing RPRval equ $03 rts off, dcd off, 8 bit; (default) rx param RTRval equ $20 BRG clk source; rx timing OMRval equ $11 save as tpr, user led off, rts on; output/misc ICRval equ $03 a high, vctred, non-stat, mstr int enab; interrupt control CTCval equ $00 reset the counter; counter control Int_enab equ $10 interrupt enable (IER reg) Even_par equ $10 even parity Odd_par equ $30 odd parity ************************ * DUSCC register bit equates TXdone_b equ 7 ************************ * DUSCC commands Rst_tx equ $00 reset transmitter Rst_rx equ $40 reset receiver Enab_tx equ $02 enable tx Enab_rx equ $42 enable rx TxRdy_a equ $01 tx ready on channel a TxRdy_b equ $05 channel b RxRdy_a equ $00 rx ready on channel a RxRdy_b equ $04 channel b ************************ * general useage equates Overun set $20 MaxBuff equ InpSiz-10 MinBuff equ 10 ******************************** * Static Storage Requirements vsect InFill ds.l 1 input buffer next-in ptr InEmpty ds.l 1 input buffer next-out ptr InEnd ds.l 1 end of input buffer

Se definen los valores a instalar en los registros del controlador Definiciones de los comandos utilizados en el controlador físico. Definiciónes de las variables estáticas utilizadas por el sistema para cada dispositivo.

OutFill ds.l 1 output buffer next-in ptr OutEmpty ds.l 1 output buffer next-out ptr OutEnd ds.l 1 output buffer end of buffer pointer OutCount ds.w 1 # of chars in output buffer IRQMask ds.w 1 interrupt mask word SigPrc ds.w 1 process to signal ds.w 1 signal code ds.w 1 associated path number DCDOff ds.w 1 process to signal on loss of DCD ds.w 1 signal process ds.w 1 associated path number P$IMASK ds.w 2 interrupt mask Shake ds.b 1 current level of DCD line. InHalt ds.b 1 input halted flag OutHalt ds.b 1 output IRQ's disabled when non-zero Parity ds.b 1 parity, word length and stop bit bits BaudRate ds.b 1 Baud rate Otpt_On ds.b 1 Value to enable DUSCC output IRQ's Otpt_Off ds.b 1 value to disable DUSCC output IRQ's InpBuf ds.b InpSiz input buffer OutBuf ds.b OutSiz output buffer ends H_XOFF equ 0 V_XOFF has been received, waiting XON H_Empty equ 1 output buffer is empty page ************************ * Module Header DUSCCEnt dc.w Init dc.w Read dc.w Write dc.w GetStat dc.w PutStat dc.w TrmNat dc.w 0 Exception handler not used ************************ * Init * Initalize DUSCC * Passed: (a1)=device descriptor address * (a2)=static storage address * Returns: cc=carry set if device can't be initalized * Destroys: (may destroy d0-d7,a0-a5) Init: movea.l V_PORT(a2),a3 I/O port address move.b #(1<<H_Empty),OutHalt(a2) output IRQs disabled clr.b OutHalt(a2) not halted for now move.b PD_PAR-PD_OPT+M$DTyp(a1),d0 move.b PD_BAU-PD_OPT+M$DTyp(a1),d1 bsr.s Configur configure the port bcs.s InitErr leave if error lea InpBuf(a2),a0 init buffer pointers move.l a0,InFill(a2) move.l a0,InEmpty(a2) lea.l InpSiz(a0),a0 compute buffer size move.l a0,InEnd(a2) mark end of input buffer lea OutBuf(a2),a0 point to start of output buffer move.l a0,OutFill(a2) init output buffer pointers move.l a0,OutEmpty(a2) lea OutSiz(a0),a0 compute out buffer size move.l a0,OutEnd(a2) mark end of output buffer move.b #$03,Otpt_Off(a2) output disabled, input enabled move.b #$02,Otpt_On(a2) output enabled, input enabled move.b M$IRQLvl(a1),d2 get priority level asl.w #8,d2 shift into priority bset #SupvrBit+8,d2 set system state bit move.w d2,IRQMask(a2) save for later

En esta tabla se almacenan diferentes variables como punteros a los buffers, buffers, variables de control, etc. Esta es la tabla de saltos a las rutinas del driver. Rutina de inicialización del dispositivo físico. Carga la dirección del puerto, la paridad y la velocidad de transmisión. Configura el puerto si es necesario. Inicializa los punteros de los buffers, los contadores de los datos, los tamaños de los buffers, etc. Obtiene el nivel de prioridad.

move.l a3,d2 copy port addr andi.b #0,d2 mask port addr move.l d2,a0 copy masked addr move.b M$Vector(a1),IVR(a0) vector number move.b M$Vector(a1),d0 get vector move.b M$Prior(a1),d1 and priority lea ACIRQ(pc),a0 address of interrupt routine os9 F$IRQ add to IRQ polling table bcs.s InitErr error - return it Init9 rts InitErr move.w #E$Unit,d1 ori #Carry,ccr rts ****************************************************** * * set Parity, Bits/Char, Number of Stop Bits * * passed: (a2) = static storage address * d0.b = Parity * d1.b = Baud Rate * * return: d0.b = error code * cc set if error * Configur: cmp.b BaudRate(a2),d1 any baud rate change? bne.s DoConfig if yes, go do configuration cmp.b Parity(a2),d0 else, any parity change? bne.s DoConfig if yes, go do configuration moveq.l #0,d1 if no changes needed, return with no error rts DoConfig: movem.l a0/a3/d0-d4,-(a7) save regs movea.l V_PORT(a2),a3 I/O port address move.b #Rst_tx,RCCR(a3) reset the transmitter move.b #TXdis,RCCR(a3) disable transmitter move.b #Rst_rx,RCCR(a3) reset the receiver move.b #RXdis,RCCR(a3) disable receiver move.b #CM1val,CMR1(a3) async, no parity move.b #CM2val,CMR2(a3) normal op, polled or interrupt move.b #PCRval,PCReg(a3) x2, rts, rtxc input, txclk move.b #TPRval,TPR(a3) 1 stp, idl, mrks, no teom, rts cts 8 bit move.b #RPRval,RPR(a3) rts off, dcd off, 8 bit move.b #OMRval,OMR(a3) save as tpr, user led off, rts on move.l a3,d2 copy port addr andi.b #0,d2 mask port addr move.l d2,a0 copy masked addr move.b #ICRval,ICR(a0) a high, vctred, non-stat, mstr int en move.b #CTCval,CTCR(a3) reset the counter timer control reg btst #0,d0 no parity ? beq.s Con_A1 jump over if no parity btst #1,d0 even? bne.s Con_A do even if set ori.b #Odd_par,CMR1(a3) set to odd parity bclr.b #3,CMR1(a3) bra.s Con_A1 Con_A ori.b #Even_par,CMR1(a3) set to even parity bclr.b #3,CMR1(a3) Con_A1 andi.b #$0c,d0 save bits/char

Pone el número del vector de interrupción en el controlador. Instala la rutina de interrupción con el vector, prioridad, dirección y dirección del puerto adecuadas. Configura el puerto con los valores de paridad y velocidad de transmisión nuevos sólo si se han cambiados. Comprueba si han habido cambios. Configura el dispositivo físico con los nuevos valores. Para hacerlo tiene que deshabilitar las comunicaciones y resetearlas. Carga los valores de los registros del controlador. Hace un salto dependiendo de la paridad si es nula, par o impar. Configura los registros según la paridad elegida.

beq.s Con_C if it is 8 bclr.b #0,TPR(a3) set to 7 bits bclr.b #0,RPR(a3) bra.s Con_C1 Con_C bset.b #0,TPR(a3) set to 8 bits bset.b #0,RPR(a3) Con_C1 move.b #Int_enab,IER(a3) enable interrupts clr.w d2 clear working reg move.b d1,d2 copy PD_BAU value andi.b #$e0,d2 legal baud value ? bne.s BadCfg no; exit lea.l BRconst(pc),a0 point at the baud rate table andi.w #$ff,d1 clear away garbage adda.w d1,a0 point at desired entry move.b (a0),d0 get the timer control value beq.s BadCfg if not legal, exit with error ori.b #TTRval,d0 make transmitter init value move.b d0,TTR(a3) set baud rate tx move.b (a0),d0 get the timer control value ori.b #RTRval,d0 make receiver init value move.b d0,RTR(a3) set baud rate rx move.b #Rst_tx,RCCR(a3) reset the transmitter move.b #Enab_tx,RCCR(a3) enable the transmitter move.b #Rst_rx,RCCR(a3) reset the receiver move.b #Enab_rx,RCCR(a3) enable the receiver movem.l (a7)+,a0/a3/d0-d4 retrieve the regs move.b d0,Parity(a2) save parity, w/length & stop bits move.b d1,BaudRate(a2) save baud rate rts BadCfg movem.l (a7)+,a0/a3/d0-d4 retrieve the regs move.w #E$BMode,d1 return "bad-mode" error ori.w #Carry,ccr set carry rts BRconst: dc.b $0 0 50.0 dc.b $1 1 75.0 dc.b $2 2 110.0 dc.b $3 3 134.5 dc.b $4 4 150.0 dc.b $6 5 300.0 dc.b $7 6 600.0 dc.b $9 7 1200.0 dc.b $0 8 1800.0 dc.b $a 9 2000.0 dc.b $b A 2400.0 dc.b $0 B 3600.0 dc.b $c C 4800.0 dc.b $0 D 7200.0 dc.b $d E 9600.0 dc.b $e F 19200.0 dc.b $f 10 38400.0 ***************************************** * Read * return one byte of input from the DUSCC * * Passed: (a1) = Path Descriptor * (a2) = Static Storage address

Configura el dispositivo a una velocidad de transmisión según una tabla. Una vez configurado el dispositivo, se resetean las comunicaciones y se reestablecen las transmisiones. Se recuperan los valores iniciales de los registros y se finaliza la rutina. En caso de error, se devuelve su código en el registro d1. Tabla de valores de velocidad de transmisión en baudios. Rutina de lectura de un caracter desde el buffer de entrada.

* (a6) = system global pointer * Return: d0.b = input character * cc = carry set, d1.w = error code if error * Destroys: a0 * Read00 move.w V_BUSY(a2),V_WAKE(a2) arrange for wakeup call move (a7)+,sr restore IRQs bsr DUSCCSlep Read: tst.b InHalt(a2) is input halted? ble.s Read_a branch if not cmpi.w #MinBuff,InCount(a2) buffer mostly emptied? bhi.s Read_a ..No, continue move.b V_XON(a2),d1 get X-ON char ori.b #Sign,d1 set sign bit move.b d1,InHalt(a2) flag input resume movea.l V_PORT(a2),a3 get port address move.b Otpt_On(a2),RCCR(a3) enable output IRQs Read_a tst.w SigPrc(a2) a process waiting for device? bne.s ErrNtRdy ..yes, return dormant term error move sr,-(a7) save current IRQ status move IRQMask(a2),sr mask irqs tst.w InCount(a2) any data? beq.s Read00 branch if not move (a7)+,sr unmask IRQs movea.l InEmpty(a2),a0 point to next char move.b (a0)+,d0 get character subq.w #1,InCount(a2) dec buffer size by one cmpa.l InEnd(a2),a0 at end of buffer blo.s Read_b branch if not lea InpBuf(a2),a0 point to start of buffer Read_b move.l a0,InEmpty(a2) update buffer pointer move.b V_ERR(a2),PD_ERR(a1) copy I/O status to PD beq.s Read90 return if no error clr.b V_ERR(a2) move.w #E$Read,d1 signal read error ori #Carry,ccr return carry set Read90 rts ErrNtRdy move.w #E$NotRdy,d1 ori #Carry,ccr rts ************************************ * DUSCC sleep * sleep until interrupt occurs * * Passed: (a2) = driver global storage * (a4) = current process descriptor pointer * Destroys: d1, possibly PC * DUSCCSlep movem.l d0/a0,-(a7) save regs moveq #0,d0 sleep indefinately os9 F$Sleep wait for input Data move.w P$Signal(a4),d1 signal present? beq.s ACSL90 no, return cmpi.w #S$Intrpt,d1 deadly signal? bls.s ACSLER y, return error ACSL90 btst #Condemn,P$State(a4) has process died? bne.s ACSLER y, return error movem.l (a7)+,d0/a0 rts ACSLER lea 12(a7),a7 exit to caller's caller ori #Carry,ccr rts

Comprueba si se puede leer. Proceso de lectura del caracter. Comprueba si existe algún dato en el buffer de entrada. Recoge el caracter del buffer y restaura los valores de los punteros y contadores. Retorna el código del error en caso de haberlo. El proceso de lectura del caracter se pone en estado de sleep hasta que detecte algún caracter.

************************************ * Write * Output one character to DUSCC * * Passed: d0.b = char to write * (a1) = Path Descriptor * (a2) = Static Storage address * (a4) = current process descriptor pointer * (a6) = system global data pointer * Returns: none * Write00 move.w V_BUSY(a2),V_WAKE(a2) arrange wake up signal move (a7)+,sr restore IRQs bsr.s DUSCCSlep sleep a bit Write: move.l V_PORT(a2),a3 move.l a3,d1 btst #5,d1 check which port beq.s Write_12 if lower andi.b #00,d1 move.l d1,a3 Write_14 btst.b #TxRdy_b,GSR(a3) for upper port beq.s Write_14 move.l V_PORT(a2),a3 move.b d0,TxFIFO(a3) clr.w d1 rts Write_12 andi.b #00,d1 move.l d1,a3 btst.b #TxRdy_a,GSR(a3) for lower port beq.s Write_12 move.l V_PORT(a2),a3 move.b d0,TxFIFO(a3) clr.w d1 rts move sr,-(a7) save current IRQ status move IRQMask(a2),sr mask IRQs cmpi.w #OutSiz,OutCount(a2) room for more data? bhs.s Write00 addq.w #1,OutCount(a2) increment count movea.l OutFill(a2),a0 point to next char location move.b d0,(a0)+ store char and inc pointer cmpa.l OutEnd(a2),a0 end of buffer? blo.s Write10 branch if not lea OutBuf(a2),a0 point to start of buffer Write10 move.l a0,OutFill(a2) update buffer pointer bclr #H_Empty,OutHalt(a2) was output buffer empty? beq.s Write80 just exit if not tst.b OutHalt(a2) still halted due to other cause bne.s Write80 don't enable IRQ if so movea.l V_PORT(a2),a3 port address move.b Otpt_On(a2),RCCR(a3) enable output interrupts Write80 move (a7)+,sr unmask IRQs moveq #0,d1 clear carry rts ***************************************** * Getsta/Putsta * Get/Put DUSCC Status * * Passed: d0.w = Status Code * (a1) = Path Descriptor * (a2) = Static Storage address

Rutina de escritura de un caracter en el buffer de salida. Pone al proceso en estado de sleep hasta que el buffer se vacíe. Chequea la dirección del puerto. Espera hasta que esté preparado para escribir, y lo hace en el puerto en el buffer de salida. Puerto B. Idem para el puerto B. Comprueba los valores de los punteros de los buffers y los contadores de los caracteres en ellos. Verifica si el buffer está lleno, y si es así, manda poner al proceso en estado de sleep hasta que se vacíe. Rutina de poner u obtener estado del dispositivo.

* Returns: depends on status code * GetStat: cmpi.w #SS_Ready,d0 ready status? bne.s GetSta10 no movea.l PD_RGS(a1),a0 get caller's register stack clr.w R$d1(a0) sweep reg move.w InCount(a2),R$d1+2(a0) return input char count beq ErrNtRdy no data, return not ready rts GetSta10 cmpi.b #SS_EOF,d0 end of file? beq.s GetSta99 yes, return * * update path descriptor for currently active baud, parity * cmpi.w #SS_Opt,d0 get options call ? bne.s Unknown move.b BaudRate(a2),PD_BAU(a1) set currently active baud rate move.b Parity(a2),PD_PAR(a1) set currently active comms mode Unknown move.w #E$UnkSvc,d1 unknown serivce code ori #Carry,ccr GetSta99 rts PutStat: cmpi.w #SS_SSig,d0 signal process when ready? bne.s PutSta_A no tst.w SigPrc(a2) somebody already waiting? bne ErrNtRdy yes, error move.w PD_CPR(a1),d0 get caller's process id movea.l PD_RGS(a1),a0 get caller's register pointer move.w R$d2+2(a0),d1 get signal code move sr,-(a7) save IRQ status move IRQMask(a2),sr disable IRQs tst.w InCount(a2) any Data available? bne.s PutSta10 yes, signal data ready move.w d0,SigPrc(a2) save process ID move.w d1,SigPrc+2(a2) save the desired signal code move.w PD_PD(a1),SigPrc+4(a2) save system path number movea.l V_PORT(a2),a3 get address move.b Otpt_On(a2),RCCR(a3) enable output interrupts move (a7)+,sr unmask IRQs moveq #0,d1 rts PutSta10 move (a7)+,sr restore IRQ status bra SendSig send the signal PutSta_A cmpi.w #SS_Relea,d0 release device? bne.s PutSta_B bra if not move.w PD_CPR(a1),d2 get current process ID lea SigPrc(a2),a3 test SigPrc bsr.s ClearSig lea DCDOff(a2),a3 ClearSig cmp.w (a3),d2 does it concern this process? bne.s ClrSig20 no, just return clr.w (a3) no more signals for him ClrSig20 moveq #0,d1 rts PutSta_B cmpi.w #SS_DCOn,d0 signal on carrier detect? beq Unknown

Dependiendo del código de estado salta a realizar los pasos oportunos. Devuelve el contador de caracteres de entrada. Si es fin de fichero, retornar. Pone los actuales valores de velocidad de transmisión y de paridad. Si el código no es reconocido, retorna un error. Rutina de poner estado. Compara el código de función. Examina reistros y variables del descriptor de path. Mira si hay algún dato en el buffer de entrada. Guarda diferentes registros. Reestablece el registro de estado. Compara el código de función. Examina diferentes registros del descriptor de path y de la tabla de variables estáticas del dispositivo. Compara el código de función. Salta si no es reconocido.

PutSta_C cmpi.w #SS_DCOff,d0 on loss of carrier? bne.s PutSta_D branch if not lea DCDOff(a2),a3 point to DCD off storage PutSta20 move.w PD_CPR(a1),(a3) save process to signal movea.l PD_RGS(a1),a0 get caller's register pointer move.w R$d2+2(a0),2(a3) get signal code move.w PD_PD(a1),4(a3) save system path number bra.s PutSta90 exit PutSta_D cmpi.w #SS_EnRTS,d0 enable RTS bne.s PutSta_E branch if not RTSDummy moveq #0,d1 fakeout rts PutSta_E cmpi.w #SS_DsRTS,d0 disable RTS beq.s RTSDummy * * If call is SS_Open or SS_Opt, * check if baud/parity/etc.. needs update * cmpi.w #SS_Open,d0 beq.s PutSta_F cmpi.w #SS_Opt,d0 bne Unknown return error for unknown service requests * * Check for dynamic configuration change * PutSta_F move.b PD_PAR(a1),d0 get parity byte move.b PD_BAU(a1),d1 get baud_rate bra Configur PutSta90 clr.b d1 rts ****************************************** * Subroutine TrmNat * terminate DUSCC processing * * Passed: (a1) = device descriptor pointer * (a2) = Static Storage * (a4) = current process descriptor pointer * Returns: none * TRMN00 move.w V_BUSY(a2),V_WAKE(a2) arrange wake up signal move (a7)+,sr restore IRQs bsr DUSCCSlep wait for I/O activity TrmNat: move.w P$ID(a4),d0 move.w d0,V_BUSY(a2) move.w d0,V_LPRC(a2) move sr,-(a7) save current IRQ status move IRQMask(a2),sr mask IRQs tst.w OutCount(a2) any data? bne.s TRMN00 sleep if there is movea.l V_PORT(a2),a3 get port address move.b #$00,IER(a3) disable receive move (a7)+,sr restore IRQ masks move.b M$Vector(a1),d0 get vector Number suba.l a0,a0 os9 F$IRQ remove DUSCC from polling table rts

Compara de nuevo el código de función. Copia y reestablece valores del descriptor de path. Compara el código de función. Compara el código de función. Si coincide, salta a configurar el dispositivo. Obtiene los valores de velocidad de transmisión y paridad. Retorno de subrutina sin errores. Subrutina de concluir con el manejo del dispositivo. Esta rutina pone fin al control del dispositivo por parte del driver. Examina si tiene caracteres en el buffer de salida, si es así, el proceso espera hasta que se vacíe. Deshabilita las interrupciones y borra el vector de rutina de interrupción.

************************************** * ACIRQ * process interrupt (input or output) from DUSCC * * Passed: (a2) = static storage address * (a3) = port address * Returns: cc = carry set if false interrupt * ACIRQ: move.b GSR(a3),d0 get status bne.s ACIRQ05 branch if irq here ACIRQ02 ori #Carry,ccr exit with carry if not rts ACIRQ05 move.l a3,d1 get port address btst #5,d1 check which port MAKE THIS "ABBIT" TYPE DEF bne.s ACIRQ07 clr.w d1 btst.b #RxRdy_a,GSR(a3) have character? bne InIRQ yes, get it btst.b #TxRdy_a,GSR(a3) can we send one? bra.s ACIRQ02 beq.s ACIRQ02 ACIRQ07 clr.w d1 btst.b #RxRdy_b,GSR(a3) have character? bne InIRQ_a yes, get it btst.b #TxRdy_b,GSR(a3) can we send one? bra.s ACIRQ02 beq.s ACIRQ02 * fall through to do output ********************************* * OutIRQ * DUSCC output interrupt service * * Passed: d0.b = DUSCC status register contents * (a2) = static storage address * (a3) = DUSCC port address * (a6) = DUSCC masked port address (for common registers) * OutIRQ move.b InHalt(a2),d0 send X-ON or X-OFF? bpl.s OutI_a branch if not bclr #SignBit,d0 clear sign bit move.b d0,TxFIFO(a3) send character move.b V_XON(a2),d1 get x-on value eor.b d1,d0 get zero if x-on move.b d0,InHalt(a2) mark it sent tst.b OutHalt(a2) is output halted bne.s OutIRQ3 branch if so rts OutI_a move.w OutCount(a2),d1 beq.s OutIRQ2 branch if not subq.w #1,d1 taking one char movea.l OutEmpty(a2),a0 get pointer to next char move.b (a0)+,TxFIFO(a3) put data in DUSCC cmpa.l OutEnd(a2),a0 end of buffer? blo.s OutI_1 branch if not lea OutBuf(a2),a0 point to start OutI_1 move.l a0,OutEmpty(a2) update pointer move.w d1,OutCount(a2) update counter cmpi.w #Low_Cnt,d1 ready for more data? bhi.s Wake90 exit if not tst.w d1 output buffer empty?

Esta es la rutina de atención a la interrupción solicitada por el controlador de dispositivo físico. Examina el registro de estado del controlador y observa si hay que atender a la interrupción. Chequea el puerto a atender. Esta rutina sólo actúa para recoger un caracter. Tanto en el puerto A como en el B. Subrutina de sacar un caracter por el puerto. Observa el estado del puerto. Examina diferentes valores de la tabla del dispositivo. Observa si el estado del contador de caracteres del buffer de salida le permiten escribir en él. Examina si el buffer se ha llenado.

bne.s WakeUp just wake up if not OutIRQ2 bset #H_Empty,OutHalt(a2) flag halted, buffer empty OutIRQ3 move.b #$02,GSR(a3) reset int pending WakeUp moveq #S$Wake,d1 wake up signal move.w V_WAKE(a2),d0 owner waiting? Wake10 beq.s Wake90 no, return clr.w V_WAKE(a2) SendSig move.l a0,-(a7) save register movea.l D_SysDis(a6),a0 get system dispatch pointer movea.l F$Send+F$Send+F$Send+F$Send(a0),a0 pointer to send routine jsr (a0) send signal movea.l (a7)+,a0 restore register Wake90 moveq #0,d1 rts ********************************** * InIRQ * DUSCC input interrupt serivce * * Passed: d0.b = DUSCC status register data * (a2) = static storage address * (a3) = DUSCC port address * InIRQ_a move.b RxFIFO(a3),d0 read input char move.b #$10,GSR(a3) clear interrupt bra.s InIRQ_b InIRQ move.b RxFIFO(a3),d0 read input char move.b #$01,GSR(a3) clear interrupt *InIRQ_b andi.b #$7f,d0 strip parity InIRQ_b tst.b d0 is a character there beq.s InIRQ1 null, impossible char cmp.b V_INTR(a2),d0 keyboard interrupt? beq InAbort yes, do it cmp.b V_QUIT(a2),d0 keyboard quit? beq InQuit yes, do it cmp.b V_PCHR(a2),d0 keyboard pause? beq InPause yes, do it cmp.b V_XON(a2),d0 x-on continue beq InXON yes, do it cmp.b V_XOFF(a2),d0 x-off immediate pause? beq InXOFF yes, do it InIRQ1 movea.l InFill(a2),a0 pointer to current char move.b d0,(a0)+ put data in buffer addq.w #1,InCount(a2) count character cmpi.w #InpSiz,InCount(a2) buffer full? bls.s InIRQ10 branch if not subq.w #1,InCount(a2) uncount character ori.b #Overun,V_ERR(a2) add in error bra WakeUp exit with error InIRQ10 cmp.l InEnd(a2),a0 end of buffer? blo.s InIRQ30 branch if not lea InpBuf(a2),a0 point to start of buffer InIRQ30 move.l a0,InFill(a2) update next in pointer move.w SigPrc(a2),d0 any process to notify? beq.s InIRQ4 no move.w SigPrc+2(a2),d1 get signal code clr.w SigPrc(a2) disable signal sending bra SendSig send signal InIRQ4 move.b V_XOFF(a2),d0 get x-off char beq WakeUp branch if not enabled

Examina las variables de control del proceso. Subrutina de obtener un caracter desde el puerto. Lee el caracter desde la pila. El dato obtenido está en el registro d0. La subrutina hace una comparación para reconocer el dato de control y saltar a la subrutina correspondiente. Recoge el caracter leido y lo guarda en el buffer, ajustando los nuevos punteros y contadores. Comprueba s el buffer está lleno. Reestablece las variables de control correspondientes.

cmpi.w #MaxBuff,InCount(a2) is buffer almost full? blo WakeUp bra if not move.b InHalt(a2),d1 have we sent XOFF? bne WakeUp yes, don't send again bclr #SignBit,d0 insure sign clear move.b d0,V_XOFF(a2) ori.b #Sign,d0 set sign bit move.b d0,InHalt(a2) flag input halt move.b Otpt_On(a2),RCCR(a3) enable in and out bra WakeUp ******************************** * Control character routines InPause tst.l V_DEV2(a2) any echo device? beq InIRQ1 buffer char and exit if not movea.l V_DEV2(a2),a0 get echo device static pointer move.b d0,V_PAUS(a0) request pause bra InIRQ1 buffer char and exit InAbort moveq #S$Intrpt,d1 keyboard Interrupt signal bra.s InQuit10 InQuit moveq #S$Abort,d1 abort signal InQuit10 move.b d0,-(a7) save input char move.w V_LPRC(a2),d0 last process ID bsr Wake10 send error signal move.b (a7)+,d0 restore input char bra InIRQ1 buffer char, exit InXON bclr #H_XOFF,OutHalt(a2) enable output tst.b OutHalt(a2) still halted(buffer empty)? bne.s InXON99 exit if so move.b Otpt_On(a2),RCCR(a3) start again InXON99 rts InXOFF tst.b OutHalt(a2) bne.s InXOFF10 already halted, continue move.b Otpt_Off(a2),RCCR(a3) disable outptu InXOFF10 bset #H_XOFF,OutHalt(a2) flag output restricted rts ends

Esta subrutina atiende según los caracteres de control recibidos desde el teclado.

ANEXO II ESTRUCTURA DEL DRIVER DE LA TARJETA SYS68K/ISIO-1 Este driver controla la placa de comunicaciones serie SYS68K/ISIO-1, cuyo controlador es el DUSCC 68562. La principal diferencia entre este driver y el anterior, es que el primero está escrito en lenguaje ensamblador y este está desarrollador casi todo en lenguaje C. Lo primero que se hace es definir todas las varibles y modulos de memoria que utiliza el sistema. Estas estan definidas en los ficheros: scisio.h scf.h sysio.h module.h types.h regs.h procid.h path.h sg_codes.h signal.h El principal fichero del driver es scglue.a escrito en lenguje ensamblador y que hace de unión entre todas las rutinas del driver escritas en lenguaje C por separado en los respectivos ficheros: main.c init.c read.c write.c stat.c term.c irq.c misc.c En el fichero misc.c están escritas otras funciones en C que son llamadas desde las rutinas del driver. Por último el fichero syscalls.a es un interface para las llamadas al sistema utilizadas como funciones en las rutinas del driver escritas en C.

Las rutinas del driver realizan las mismas funciones que en el caso del driver anterior, puesto que el controlador que manejan son las mismas. El esquema general de los ficheros utilizados para la realización de este driver es: Ficheros de definición: ┌──────────────────────────────┐ ╔═════════════<<══╡ scf.h, sysio.h, module.h, │ Fichero║específico: │ types.h, regs.h, procid.h, │ ┌───────────┐ │ path.h, sg_codes.h y signal.h│ │ scisio.h │ └──────────────────────────────┘ └────╥──────┘ ║ Rutinas║del Driver: (lenguaje C) ┌──────────────────────────┐ Fichero interface: │ main.c, init.c, read.c │ (lenguaje Ensamblador) │ write.c, stat.c, term.c, │ ┌─────────────┐ │ irq.c y misc.c ╞<<═════════╡ syscalls.a │ └──────────╥───────────────┘ └─────────────┘ ║ ║ Fichero principal: ║ (Cuerpo del Driver) ║ (Lenguaje Ensamblador) ║ ┌──────────┐ ╚═════════>> scglue.a │ └──────────┘ A continuación comentamos en detalle los principales ficheros que componen este driver. SCGLUE.A nam scglue ttl glue code for scf drivers in c * Copyright 1988 by Microware Systems Corporation * Reproduced Under License * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. ******************** * scglue: interface code for C language SCF drivers. * This code provides the register interface * between SCF and SCF-style Device Drivers * that are written in C. * This psect is the "root psect" for the final * output module, thus it must be linked first. ******************** * Edition History: *

* ed. date. reason. who. * -- -------- ------------------------------------------------ * 00 89/04/27 snarfed and hacked from rbglue.a ed.3 scr. ******************** * * scglue - glue code for scf drivers in c * use defsfile Edition set 0 driver should change this by means of @_sysedit: Typ_Lang set (Drivr<<8)+Objct let's call it a driver Attr_Rev set ((ReEnt+SupStat)<<8)+0 attributes and revision psect main,Typ_Lang,Attr_Rev,Edition,0,Entry ******************** * * The entry table * Entry dc.w Init dc.w Read dc.w Write dc.w GetStat dc.w PutStat dc.w Term dc.w 0 exception handler Este fichero es el cuerpo principal del driver de la ISIO, en él se definen las direcciones de las rutinas que componen el mismo. La importabcia de este fichero está en que con él logramos escribir la mayoría del driver en un lenguaje de alto nivel. En él estámn divididas claramente las partes de las que se compone: Declaración del programa con la directiva Psect; la tabla de saltos a las rutinas correspondientes y el tratamiento de cada una de ellas. Aqui se declara el programa de tipo Driver, en lenguaje ensamblador, bit de estado de sistema. Todas estas declaraciones son para la cabecera del módulo de memoria resultante del driver. Esta es la tabla de punteros de las rutinas del driver. En ella se situan los offsets de dichas rutinas respecto al comienzo de la tabla.

******************** * * Init - call init (dd) * * dd = device descriptor * Init: lea init(pc),a0 address of the init routine move.l a6,sys_stat(a2) initialize the systems globals ptr move.l a2,stat(a2) initialize the static storage ptr InitTerm move.l a1,d0 pass the device descriptor move.l a2,a6 set global storage ptr for C bra.s calldriver ******************** * * Read/Write - call read() * write(output) * * input: * input and output in d0.l with low order word being character * for output and cleared for input. * output: * input and output in d0.l with low order word being error * code and high order word input character for read and * cleared for write. Read: lea read(pc),a0 get the subroutine address setupcall move.l a2,a6 set global storage ptr for C move.l a1,pathdesc(a6) set path ptr move.l a4,procdesc(a6) set process ptr calldriver jsr (a0) move.l sys_stat(a6),a6 restore system global ptr move.w d0,d1 copy error code from low order word beq.s ReadEnd leave if no error ori #Carry,ccr set error flag rts ReadEnd moveq #16,d1 shift value in d1 lsr.l d1,d0 shift read character into position moveq #0,d1 clear errors and carry rts Write: lea write(pc),a0 bra.s setupcall ******************** * * GetStat/PutStat - call getstat/putstat (code) * - perform getstat routines * code = function code (d0.w) * GetStat: lea getstat(pc),a0 get address of routine bra.s GetPut PutStat: lea putstat(pc),a0 get the address of the routine GetPut ext.l d0 make the code a long bra.s setupcall

Rutina de inicializacion. Carga la dirección de la rutina escrita en lenguaje C. Inicializa los punteros a las variables del dispositivo. Salta a la rutina en alto nivel. Rutinas de lectura y escritura de caracter en los buffers correspondientes. El dato a leer o escribir lo contiene el registro d0. Se pasa la dirección de la rutina read escrita en C. y se actualizan los punteros de laas variables estáticas del dispositivo a controlar. Salto a la rutina de escrita en C. A la vuelta de la rutina llamada, se restauran los valores de los punteros a las variables estáticas que utiliza el sistema, se comprueba si hubo algún error y se devuelve el control al sistema. En caso de haber error, el código del mismo lo contiene el registro d1. Si no lo hubo, el carry está a cero. Rutina de escritura de un caracter. Se pasa la dirección de la verdadera rutina en C. Rutinas de obtener y fijar estado. Análogamente a los casos anteriores, estas rutinas lo que hacen es pasar en control a las verdaderas rutinas del driver escritas en C.

******************** * * Term - call term(dd) * * dd = device descriptor (a1) * Term: lea term(pc),a0 bra.s InitTerm ******************** * * irqsvc - call irq (port_addr) * where: port_addr (in a3) = hardware ptr * irqsvc: move.l a3,d0 put port address in d0 move.l a2,a6 set global storage ptr for C bsr irq call irq service routine move.l d0,d1 retreive error code beq.s irq_done is it us? ori.b #01,ccr not us set carry irq_done rts see ya! ends SCISIO.H /* * definitions for the scisio driver * * Copyright 1989 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. * * history: * * ed. date. reason. who. * -- -------- -------------------------------------------- --- * 00 89/04/27 and in the beginning....... srw */ #include <scf.h> #include <Machine/reg.h> #include <procid.h> #include <path.h> #include <errno.h> #include <sg_codes.h> #include <signal.h> /* * general defines */ #define CHDPROFFS 0x8800 /*offset to channel's DPR buffer*/ #define CHDPRSIZE 0x1000 /* size of DPR buffer (4k) */ #define BIMOFFSET 0x01 /* bim on odd addresses */ #define INSIZE 80 /* input buffer size */ #define OUTSIZE 140 /* output buffer size */ Rutina de conclusión de manejo del dispositivo por parte del sistema. Salto a la rutina de alto nivel. Rutina de atención a las interrupciones del dispositivo físico. A la vuelta, se comprueba si hubo algún tipo de error.

En este fichero se definen las constantes, varuiables y estructuras de datos que van a ser utilizadas por los ficheros que componen el driver de la ISIO. En este módulo se incluyen otros ficheros de definición más generales del sistema. Todos estos ficheros componen la librería de definición del driver. Inicialización de variables generales del sistema. Estas variables las utiliza el sistema para comprobar el estado actual de sus buffers.

#define MAXBUFF INSIZE - 10 /* send XOFF when buffer is this full*/ #define MINBUFF 10 /* send XON when buffer this empty */ #define LOW_CNT 10 /* resume receive count */ #define H_EMPTY 0x02 /* halted buffer empty */ #define H_XOFF 0x01 /* halted xoff received */ #define INPENDING 0x01 /* input command pending */ #define OUTPENDING 0x02 /* output command pending */ #define OVERRUN 0x04 /* receiver over run error */ #define SUPSTAT 0x2000 /* supervisory state sr mask 68xxx ONLY!*/ /* * ISIO firmware command codes */ #define ASYNINI 0x0006 /* initialize async port */ #define GETCH 0x1010 /* get a character from port */ #define PUTCH 0x0114 /* put a character to port */ #define PUTCHI 0x1114 /* put a character to port & interrupt */ #define INSTAT 0x0042 /* get input status */ #define OUTSTAT 0x0143 /* get output status */ #define CLRBUF 0x0005 /* clear input buffer */ #define RECOFF 0x0008 /* shut off DUSCC receiver */ #define BIMMASK 0x10 /* bim control mask */ typedef struct bim { u_char ctrl0; /* control register 0 */ u_char res0; /* reserved */ u_char ctrl1; /* control register 1 */ u_char res1; /* reserved */ u_char ctrl2; /* control register 2 */ u_char res2; /* reserved */ u_char ctrl3; /* control register 3 */ u_char res3; /* reserved */ u_char vect0; /* vector register 0 */ u_char res4; /* reserved */ u_char vect1; /* vector register 1 */ u_char res5; /* reserved */ u_char vect2; /* vector register 2 */ u_char res6; /* reserved */ u_char vect3; /* vector register 3 */ } *Bim; typedef struct cmdram { u_short cmdstat; /* firmware command/status word */ u_short cmdparm1; /* command parameter 1 */ u_short cmdparm2h;/* command parameter 2 */ u_short cmdparm2l; /* command parameter 2 */ u_short cmdparm3h;/* command parameter 3 */ u_short cmdparm3l; /* command parameter 3 */ u_short cmdcode; /* command dependant code */ u_short reserved; /* reserved */ } *Cmdram; /* * non-int function declarations. */ /* * scf driver static storage definitions */ #ifndef driver_static #define driver_static extern #endif /* * caring instructions: long-word alignment of pointers, etc. * results in optimum performance. Try to ensure that all

Valores de los codigos de los comandos de la ISIO que posteriromente seran utilizados para el control de la placa. Definición de la estructura de la BIM de la placa ISIO. Definición de la estructura de la Ram de comandos de la placa ISIO. Definición de las variables estáticas que utiliza el sistema para el control del dispositivo físico.

* things 'longish' are declared first. */ driver_static struct scfstatic scfstat; /* SCF required static */ driver_static short padder; /* long-word align */ driver_static void ç*sys_stat; /* system globals ptr */ driver_static Scfstatic stat; /* driver static storage ptr */ driver_static Pathdesc pathdesc; /* path descriptor ptr */ driver_static procid *procdesc; /* process descriptor ptr */ driver_static u_char *infill; /* next in pointer */ driver_static u_char *inempty; /* next out pointer */ driver_static u_char *inend; /* end of input buffer */ driver_static int incount; /* chars in input buffer*/ driver_static u_char *outfill; /* next in pointer */ driver_static u_char *outempty; /* next out pointer */ driver_static u_char *outend; /* end of output buffer*/ driver_static int outcount; /* chars in output buffer*/ driver_static u_int irqmask; /* mask for irqs */ driver_static u_short sigproc; /* process to signal */ driver_static u_short sigcode; /* signal code */ driver_static u_short sigpath; /* path number */ driver_static char inhalt; /* input halted flag */ driver_static char outhalt; /* output halted flag */ driver_static u_char curr_baud; /* current baud rate */ driver_static u_char curr_par; /* current parity */ driver_static u_char channel; /* channel # (0-3) */ driver_static u_short out_cmd; /* firmware cmd for output*/ driver_static u_char cmd_pending; /* cmd pending on channel */ driver_static Cmdram in_cmdram; /* pointer to cmdram input*/ driver_static Cmdram out_cmdram; /* pointer to cmdram output*/ driver_static u_char inbuf[INSIZE]; /* input buffer */ driver_static u_char outbuf[OUTSIZE]; /* output buffer */ /* * general definitions */ #define NULL 0 /* pointer to nowhere */ #define TRUE 1 /* for boolean use */ #define FALSE 0 #ifndef E_HDWARE #define E_HDWARE 0xaf /* E$Hardware */ #endif #ifndef CONDEMN #define CONDEMN 0x02 /* process has died SYSCALLS.A nam syscalls ttl system call interface for C language SCSI Driver System ************************************ * * System call interface for C Language SCSI Driver System * * These system call bindings always return either an error * or 0 if no error. All possible return values are returned via * pointers passed as arguments. * * Copyright 1988 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction,

Definición de las variables de estado actual de los buffers y contadores de datos en ellos. Todas estas variables tienen diferentes valores para cada uno de los dispositivos que controla el dirver. Este fichero hace de interface entre las rutinas escritas en lenguaje de alto nivel y las llamadas al sistema que utiliza los recursos del mismo.

* publication, or distribution in any form to any party other than * the licensee is strictly prohibited. * * Edition History * * ed. date. reason who * -- -------- ------------------------------------- --- * 1 88/01/18 created djl * 2 88/08/15 revised for less stack usage lac * 3 88/09/09 added _f_sleep srw * 4 88/12/20 added _f_send jal * Edition set 4 driver will set this via @_sysedit: psect syscalls,0,0,Edition,0,0 * F$DatMod - _f_datmod(size, attrev, perm, name, typlang, attrev, newname, * moddat, modhead) * int size, attrev, perm; * char *name; * int **typlang, **attrev; * char **newname; * void **moddat, **modhead; * perm set 0 name set 4 typlang set 8 attrev set 12 newname set 16 moddat set 20 modhead set 24 _f_datmod: movem.l d2/a0-a4,-(a7) save regs stacked set 7*4 six registers & return address move.l perm+stacked(a7),d2 get permissions move.l name+stacked(a7),a0 get name ptr os9 F$DatMod bcs.s _f_link_err lea typlang+stacked(a7),a4 get return ptrs ptr bra.s _f_link_ret * F$Link - _f_link(wattr, name, typlang, gattr, newname, entry, header) * int wattr; * char *name; * int **typlang, **gattr; * char **newname; * void **entry, **header; * typlang set 0 _f_link: movem.l d2/a0-a4,-(a7) save regs stacked set 7*4 six register & return address move.l d1,a0 set the name address os9 F$Link bcs.s _f_link_err skip if error lea typlang+stacked(a7),a4 get return ptrs ptr _f_link_ret move.l (a4)+,a3 move.l d0,(a3) move.l (a4)+,a3 move.l d1,(a3) move.l (a4)+,a3 move.l a0,(a3) move.l (a4)+,a3

Declaración del nombre del módulo. Esta función se implementa en leguaje ensamblador, los parámetros necesarios se le pasan a través de la pila; para los valores de retorno, también se utiliza la pila. Algunos valores necesarios para ejecutar las llamadas al sistema se inicializan. Los valores de los registros se reservan en la pila, después de la llamada al sistema, se restauran. En caso de haberse detectado algún error, se obtiene su código y se lo notifica al sistema. En este caso la función a implementar es la llamada al sistema para unir un bloque a memoria. Todas estas funciones tienen las mismas estructuras de implementación: primero se obtienen los parametros necesarios desde la rutina llamadora, se ejecuta la llamada al sistema y luego se devuelven los valores requeridos por la función.

move.l a1,(a3) move.l (a4)+,a3 move.l a2,(a3) moveq.l #0,d0 return successful _f_link_xit movem.l (a7)+,d2/a0-a4 restore regs rts _f_link_err ext.l d1 move.l d1,d0 bra.s _f_link_xit * F$SRqMem - _f_srqmem(size, gotsize, addr) * int size, *gotsize; * void **addr; * addr set 0 _f_srqmem: movem.l a0/a2,-(a7) save regs stacked set 3*4 two registers & return address os9 F$SRqMem bcs.s _f_srqmem_err move.l d1,a0 copy size ptr move.l d0,(a0) return size gotten move.l addr+stacked(a7),a0 move.l a2,(a0) return address of memory moveq.l #0,d0 return success _f_srqmem_xit movem.l (a7)+,a0/a2 rts _f_srqmem_err ext.l d1 move.l d1,d0 return error bra.s _f_srqmem_xit * F$IRQ - _f_irq(vector, prior, irqsrvc, static, port) * int vector, prior, (*irqsvc)(); * void **static, **port; * irqsvc set 0 static set 4 port set 8 _f_irq: movem.l a0/a2-a3,-(a7) save regs stacked set 4*4 three registers & return address move.l irqsvc+stacked(a7),a0 get IRQ service routine ptr move.l static+stacked(a7),a2 get static storage ptr move.l port+stacked(a7),a3 get port ptr os9 F$IRQ bsr.s HandleErr movem.l (a7)+,a0/a2-a3 rts * F$DelPrc - _f_delprc(id) * int id; * _f_delprc: move.l d1,-(a7) os9 F$DelPrc bsr.s HandleErr move.l (a7)+,d1 rts * F$Sleep - _f_sleep(ticks) * int ticks; * * ticks/seconds already in d0

Esta parte de la función llama a otra función. Esta función implementa la llamada al sistema que pide una zona de memoria libre al sistema. Con todas estas funciones conseguimos implementar las llamadas al sistema desde un lenguaje de alto nivel. Así podemos ejecutar funciones del sistema que no nos permite el compilador de C. Esta función instala o borra una rutina de servicio a la interrupción del dispositivo físico que el driver está controlando. Esta función pone al proceso en estado de sleep.

* _f_sleep: os9 F$Sleep bsr.s HandleErr rts * F$Send - _f_send(process_id, signal_code) * unsigned short process_id, * signal_code; * process ID is already in d0 * signal code is already in d1 * _f_send: os9 F$Send bsr.s HandleErr rts * F$SRtMem - _f_srtmem(size, addr) * _f_srtmem: move.l a2,-(a7) save reg move.l d1,a2 os9 F$SRtMem bsr.s HandleErr move.l (a7)+,a2 rts *********************** * Subroutine HandleErr * If carry set copy d1->d0 else put 0->d0 * * Passed: d1.l = error code if error * (cc) = carry set if error * HandleErr bcs.s HandleErr10 moveq #0,d0 return success rts HandleErr10 ext.l d1 move.l d1,d0 return error code rts * F$UnLink - _f_unlink(modhead) * _f_unlink: movem.l d1/a2,-(a7) save regs move.l d0,a2 os9 F$UnLink bsr.s HandleErr movem.l (a7)+,d1/a2 rts * Ev$Signl - _fev_signl(id, actall) * _fev_signl: move.l d1,-(a7) save reg move.w #Ev$Signl,d1 _fev_10 os9 F$Event bsr.s HandleErr move.l (a7)+,d1 restore reg rts * Ev$UnLnk - _fev_unlnk(id) * _fev_unlnk: move.l d1,-(a7)

Implementación de la función de mandar una señal a un proceso determinado. Función de devolver memoria al sistema. El código que viene a continuación trata el manejo de errores cometidos, dependiendo del códidgo del mismo. Función de descrementar el número de copias de un módulo en emmoria.

move.w #Ev$UnLnk,d1 bra.s _fev_10 * Ev$Creat - _ev_creat(initval, waitinc, siginc, name, id, newname) * int initval, waitinc, siginc; * char *name; * int **id; * char **newname; * siginc set 0 name set 4 id set 8 newname set 12 _fev_creat: movem.l d2-d3/a0-a1,-(a7) save regs stacked set 5*4 four registers & return address move.l d1,d2 move the wait increment move.l siginc+stacked(a7),d3 get signal increment move.l name+stacked(a7),a0 get name ptr move.w #Ev$Creat,d1 get the code os9 F$Event bcs.s _fev_create_err skip if error move.l id+stacked(a7),a1 get id ptr move.l d0,(a1) return id move.l newname+stacked(a7),a1 get name ptr move.l a0,(a1) return updated name ptr moveq.l #0,d0 return success _fev_create_xit movem.l (a7)+,d2-d3/a0-a1 restore regs rts _fev_create_err ext.l d1 move.l d1,d0 bra.s _fev_create_xit * Ev$Delet - _fev_delet(name, newname) * char *name, **newname; * _fev_delet: movem.l a0-a1,-(a7) save regs move.l d1,a1 save name ptr move.w #Ev$Delet,d1 get the event code move.l d0,a0 get the address of the name os9 F$Event bcs.s _fev_delet10 skip if error move.l a0,(a1) return updated name ptr moveq #0,d0 no errors _fev_delet20 movem.l (a7)+,a0-a1 rts _fev_delet10 ext.l d1 move.l d1,d0 bra.s _fev_delet20 * Ev$Wait - _fev_wait(id, min, max, val) * int id, min, max, *val; * max set 0 val set 4 _fev_wait: movem.l d2-d3/a0,-(a7) save regs stacked set 4*4 three registers & return address move.l d1,d2 the minimum activation value move.l max+stacked(a7),d3 get max activation value move.w #Ev$Wait,d1 os9 F$Event

Todas estas funciones ejecutan llamadas al sistema y comprueban si ha occurido algún error. En tal caso obtienen el código de dicho error y se lo notifican al sistema.

bcs.s _fev_wait_err move.l val+stacked(a7),a0 get value ptr move.l d1,(a0) return activation value moveq.l #0,d0 return success _fev_wait_xit movem.l (a7)+,d2-d3/a0 rts _fev_wait_err ext.l d1 move.l d1,d0 bra.s _fev_wait_xit ends MAIN.C /* * scisio - SCF driver for Force ISIO-1 * * Copyright 1989 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * the licensee is strictly prohibited. * * main - edition history and declaration of static storage * * edition history * * ed# date by changes * --- -------- --- ----------------------------------------- * 1 89/04/27 srw and in the beginning...... */ @_sysedit: equ 1 #define driver_static #include "scisio.h"

Esta rutina del driver sólamente define una variable de un tipo determinado .

INIT.C /* * init - initialization code for the force isio-1 */ #include "scisio.h" /* includes all necessary .h files */ /* * Copyright 1989 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. */ int irqsvc(); void do_getch(); /* * init(dd) - initialize the device */ int init(dd) register mod_dev *dd; /* device descriptor ptr */ { register Bim bim; /* bim device on ISIO */ register struct scf_opt *opts; /* pseudo options pointer*/ register int error; /* error holder */ register u_int isiobase; /*base address of ISIO*/ isiobase = (u_int) ((u_int) scfstat.v_sysio.v_port & 0xffff0000); bim = (Bim) ((u_int) isiobase + BIMOFFSET); /* point at bim */ channel = ((u_int) scfstat.v_sysio.v_port- (u_int)(isiobase + 0x8000))/0x40; switch (channel) { case 0: bim->ctrl0 = BIMMASK | dd->_mirqlvl; bim->vect0 = dd->_mvector; break; case 1: bim->ctrl1 = BIMMASK | dd->_mirqlvl; bim->vect1 =dd->_mvector; break; case 2: bim->ctrl2 = BIMMASK | dd->_mirqlvl; bim->vect2 = dd->_mvector; break; case 3: bim->ctrl3 = BIMMASK | dd->_mirqlvl; bim->vect3 = dd->_mvector; break; } in_cmdram = (Cmdram) scfstat.v_sysio.v_port; out_cmdram = (Cmdram) (scfstat.v_sysio.v_port + 0x10); out_cmd = PUTCH; /* output interrupts off */ /* add the device to the system irq polling routine */ if (error = _f_irq(dd->_mvector, dd->_mpriority, irqsvc, &scfstat, stat.v_sysio.v_port)) return error;

Esta rutina del driver inicializa el dispositivo a controlar con los valores adecuados para su correcto funcionamiento, es decir, dependiendo de como queremos que funcionen las comunicaciones a través del dispositivo, lo instalaremos con unos valores u otros en los registros físicos del controlador. Obtiene los valores de las direcciones del dispositivo físico, de su controlador, y de los registros del mismo. Dependiendo del dispositivo, activaremos el canal adjudicado a él, y lo inicializamos. Deshabilitamos las interrupciones. Añadimos la dirección de la rutina de atención a la interrupción del controlador.

/* build 680x0 irq mask word */ irqmask = dd->_mirqlvl << 8 | SUPSTAT; /* this gets ugly but neccessary!! calculate the pointer to * the options section of the device descriptor. this * structure occurs after _mdtype in the device descriptor. */ opts = (struct scf_opt *) ((int) &(dd->_mdtype)); /* now configure the port for baud rate, parity, etc. */ if (error = config_port(opts)) return error; /* initialize static storage */ outhalt = 0x00; /* output not halted */ infill = inempty = inbuf; /* init pointers */ inend = &inbuf[INSIZE - 1]; outfill = outempty = outbuf; outend = &outbuf[OUTSIZE - 1]; /* clear any residule data in the ISIO input buffer */ do_clrbuf(); /* now enable read interrupts by issuing a read character * command * with wait and complete with an interrupt. */ do_getch(); return 0; } READ.C /* * read - read routine for the scisio driver */ #include "scisio.h" /* includes all the defs */ /* * Copyright 1989 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. */ /* * int read (input) - read a character */ int read () { register struct scf_opt *opt; /* scf options pointer */ register u_char tmpchar; /* general register char */ register char sleeping; /* sleeping flag */ register u_int error; /* error flag */ register int oldmask; /* old status mask */

Configura el dispositivo físico con los valores adecuados de paridad y velocidad de transmisión. Inicializa los valores de las variables estáticas de cada dispositivo físico. Borra el buffer de entrada y permite las interrupciones. Esta rutina devuelve un caracter leido desde el buffer de entrada.

opt = &pathdesc->scfopt; /* set options pointer */ tmpchar = 0x00; /* clear return value */ do { sleeping = 0; /* not sleeping */ tmpchar = inhalt; /* debug post */ if (inhalt > 0) if (incount < MINBUFF) { /* is buffer mostly empty? */ tmpchar = scfstat.v_xon; /* yes get xon char */ tmpchar |= 0x80; /* flag ready to send */ inhalt = tmpchar; /* set it */ tmpchar = 0x00; out_cmd = PUTCHI; /* enable output interrupts */ } if (sigproc) return E_NOTRDY; oldmask = mask_irq(irqmask); if (incount) { mask_irq(oldmask); tmpchar = *inempty++; incount--; if (inempty >= inend) inempty = inbuf; if (opt->pd_err = scfstat.v_err) { scfstat.v_err = 0; error = E_READ; } } else { sleeping = 1; /* we be sleepin' */ mask_irq(oldmask); if (error = drv_sleep()) return error; if (procdesc->_signal) if (procdesc->_signal != SIGWAKE) { return procdesc->_signal; } if (procdesc->_state & CONDEMN) return procdesc->_signal; } } while (sleeping); return ((tmpchar << 16) | error); } WRITE.C/* * write - write routine for the scisio driver */ #include "scisio.h" /* gets all the defs */ /* * Copyright 1989 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. */

Comprueba si se puede leer. Compara el valor del contador de caracteres de entrada en el buffer. Pone el comando en el controlador. Comprueba si el buffer está vacío. Si no lo está, reestablece punteros y contadores, y lee el caracter. Si el buffer está vacío, el sistema pone al proceso en estado de sleep hasta que detecte un caracter. Esta rutina escribe un caracter en el buffer de salida.

/* * int write (output) - write a character */ int write (output) u_int output; /* the character to write */ { register u_char sleeping; /* sleeping flag */ register u_int error; /* error flag */ register int oldmask; /* irq mask */ register u_char tmpchar; /* character holder */ tmpchar = output; /* get the character */ do { sleeping = 0; oldmask = mask_irq(irqmask); if (outcount == 0) { if ((outhalt & H_XOFF) == 0) { /* are we halted due to xoff? */ if (output_ok()) { /* no, can we do output? */ do_putch(tmpchar); /* yes, go write it */ mask_irq(oldmask); /* restore irqs */ return 0; } else {/* yes, halted due to xoff */ out_cmd = PUTCHI; /* turn on output interrupts */ } } } if (outcount >= OUTSIZE) { sleeping = 1; mask_irq(oldmask); if (error = drv_sleep()) return error; if (procdesc->_signal) { if (procdesc->_signal != SIGWAKE) { return procdesc->_signal; } } if (procdesc->_state & CONDEMN) return procdesc->_signal; } else { outcount++; *outfill++ = tmpchar; /* put char in buffer */ if (outfill == outend) outfill = outbuf; outhalt &= ~H_EMPTY;/* buffer not empty */ } } while (sleeping); mask_irq(oldmask); return 0; } STAT.C /* * stat - getstat/putstat routines for the scisio driver */

Comprueba si el buffer de salida está vacío. Observa si se puede escribir en el buffer. Comprueba si el buffer de salida está lleno. Si es así, el sistema pone al proceso en estado de sleep. Si no lo está, escribe el caracter en el buffer de salida, reestablece punteros y contadores de caracteres. Rutina que pone y observa el estado del dispositivo.

#include "scisio.h" /* * Copyright 1989 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. */ /* * int getstat (code) - do necessary getstats */ int getstat (code) u_short code; { register REGISTERS *regs; /* 680x0 registers */ register struct scf_opt *opt; /* scf options pointer */ opt = &pathdesc->scfopt; /* point at scf options */ regs = pathdesc->path.pd_rgs; /* callers register stack */ switch (code) { case SS_Ready: regs->d[1] = incount; if (incount == 0) return E_NOTRDY; break; case SS_EOF: break; case SS_Opt: opt->pd_bau = curr_baud; opt->pd_par = curr_par; break; default: return E_UNKSVC; break; } return 0; } /* * int putstat (code) - perform setstat operations */ int putstat (code) u_short code; { register REGISTERS *regs; /* 680x0 registers */ register struct scf_opt *opt; /* scf options pointer */ register u_int oldmask; /* 680x0 status reg */ register u_int error; /* error holder */ opt = &pathdesc->scfopt; /* point at scf options */ regs = pathdesc->path.pd_rgs; /* callers register stack */ error = 0; switch (code) { case SS_SSig: if (sigproc) return E_NOTRDY; oldmask = mask_irq(irqmask); if (incount > 0) error =_f_send(pathdesc->path.pd_cpr,

El parámetro que se le pasa es el código de estado. Dependiendo del código se ejecutan diferentes pasos. Comprueba si el buffer de entrada está vacío, si es así, hay error. Se guardan los valores de la velocidad de transmisión y la paridad. Hay error si el código no es correcto. Subrutina de poner estado al dispositivo. Dependiendo del código pasado, se restauran diferentes variables estáticas que mantiene el sistema para el control de las transmisiones.

regs->d[2]); else { sigproc = pathdesc->path.pd_cpr; /* save process id */ sigcode = regs->d[2]; /* save signal value */ sigpath = pathdesc->path.pd_pd; /* save path */ out_cmd = PUTCHI; /* enable output interrupts */ } mask_irq(oldmask); break; case SS_Relea: if (sigproc) { if ((pathdesc->path.pd_cpr == sigproc) && (pathdesc->path.pd_pd == sigpath)) { sigproc = 0x00; sigpath = 0x00; sigcode = 0x00; } } break; case SS_Open: case SS_Opt: oldmask = mask_irq(irqmask); error = config_port(opt); mask_irq(oldmask); break; default: error = E_UNKSVC; break; } return error; } TERM.C /* * term - terminate routine for the scisio driver */ #include "scisio.h" /* * Copyright 1989 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. */ /* * int term (dd) - terminate the device */ int term (dd) mod_dev *dd; { register int error; /* error holder */ register char sleeping; /* sleeping flag */

En el caso de que el código pasado no fuese correcto, se devuelve el error correspondiente. Rutina que concluye con la utilización del dispositivo por parte del driver.

register int oldmask; /* sr mask */ do { sleeping = 0; scfstat.v_sysio.v_busy = procdesc->_pid; scfstat.v_sysio.v_lprc = procdesc->_pid; oldmask = mask_irq(irqmask); if (outcount == 0) { /* kill any pending commands on this channel */ /* do_recoff(); do_clrbuf(); */ error = abort_chnl(); mask_irq(oldmask); if (error =_f_irq(dd->_mvector, dd->_mpriority,0, &scfstat, 0)) return error; } else { sleeping = 1; mask_irq(oldmask); if (error = drv_sleep()) return error; if (procdesc->_signal) if (procdesc->_signal == SIGINT) { error = SIGINT; return error; } if (procdesc->_state && CONDEMN) return error; } } while (sleeping); } IRQ.C /* * irq - interrupt routine for scisio driver */ /* * Copyright 1989 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. */ #include "scisio.h" /* * irq(hw) - process interrupt */ int irq (hw) register u_int hw; /* port address */ { register u_short instatus; /* status of command */ register u_short outstatus; /* status of command */ register Cmdram cmdram; /* cmdram pointer */ if (cmd_pending == 0x00) /*do we have a command pending? */

Comprueba si el proceso está en estado de sleep. Comprueba si el buffer de salida está vacío. Si es así, borra los buffers y anula la rutina de atención a la interrupción. Si el buffer no está vacío, el sistema pone al proceso en estado de sleep hasta que se vacíe. Rutina de atención a la interrupción del controlador.

return 1; /* no, not our interrupt */ cmdram = in_cmdram; /* point at input cmdram */ instatus = cmdram->cmdstat; /* read status */ cmdram = out_cmdram; /* point at input cmdram */ outstatus = cmdram->cmdstat; /* read status */ if ((instatus & 0x9000) != 0x9000) /* interrupt complete ? */ if ((outstatus & 0x9000) != 0x9000) /* no, how bout here ? */ return 1; /* no, not us */ switch (cmd_pending) { case INPENDING: case INPENDING | OUTPENDING: if ((instatus & 0x9000) == 0x9000) /* command complete? */ return in_irq(); /* yes, process interrupt */ case OUTPENDING: if ((outstatus & 0x9000) == 0x9000) /* command complete? */ return out_irq(); /* yes, process interrupt */ } return 1; /* big trouble if we ever get here!! */ } /* * in_irq() - process input interrupt */ int in_irq() { register u_short status; /* command status holder */ register u_char tmpchar; /* character holder */ register int error; /* error holder */ register struct scfstatic *echodev; /* echo device static storage ptr */ error = 0x00; /* clear error */ status = in_cmdram->cmdstat; /* get the status */ in_cmdram->cmdstat = 0x8000; /* clear to allow others to complete */ if (inhalt < 0) /* xon or xoff to be sent? */ if (output_ok()) { inhalt &= 0xef; /* clear flag bit */ do_putch(inhalt); /* send character */ inhalt ^= scfstat.v_xon; /*mark character sent */ } status &= 0xff; /* mask error status */ if (status) /* any errors? */ scfstat.v_err |= status; /* accumulate error */ tmpchar = (u_char) in_cmdram->cmdparm1; /* get input character */ if (tmpchar == scfstat.v_intr) { if (scfstat.v_sysio.v_lprc) { scfstat.v_sysio.v_wake = 0x00; /* clear wake */ error = _f_send(scfstat.v_sysio.v_lprc, SIGINT); /* send signal */ } else error = 0; do_getch();

Lee los estados de los comandos de entrada y salida del controlador. Dependiendo del comando, salta a una u otra subrutina. Subrutina de interrupción de entrada. Obtiene el estado del dispositivo. Comprueba si se puede leer caracter. Se manda caracter de control. Comprueba si hay error. Obtiene el caracter.

} else if (tmpchar == scfstat.v_quit) { if (scfstat.v_sysio.v_lprc) { scfstat.v_sysio.v_wake = 0x00;/* clear wake */ error = _f_send(scfstat.v_sysio.v_lprc, SIGQUIT); /* send signal */ } else error = 0; do_getch(); } else if (tmpchar == scfstat.v_pchr) { if (scfstat.v_dev2) { echodev = (struct scfstatic *) scfstat.v_dev2; echodev->v_pause = tmpchar; } } else if (tmpchar == scfstat.v_xoff) { outhalt |= H_XOFF; do_getch(); return 0; } else if (tmpchar == scfstat.v_xon) { outhalt &= ~H_XOFF; if (outhalt == 0) { /* are we halted for some other reason */ out_cmd = PUTCHI; /* no, go do output */ if (output_ok()) { do_getch(); return out_irq(); } else { do_getch(); return 0; } } else { do_getch(); return 0; } } *infill++ = tmpchar; incount++; if (incount >= INSIZE) { incount--; scfstat.v_err |= OVERRUN; /* do wakeup with error */ if (error = scfstat.v_sysio.v_wake) { scfstat.v_sysio.v_wake = 0x00; /* clear wake */ error = _f_send(error, SIGWAKE); /* send signal */ } } else { if (infill >= inend) infill = inbuf; if (sigproc) { error = _f_send(sigproc,sigcode); /* send signal */ sigproc = 0x00; /* clear signal */ sigcode = 0x00; sigpath = 0x00; do_getch(); return 0;

Dependiendo del estado en que quedó el dispositivo, el sistema ejecuta diferentes comandos. Comprueba si se puede mandar caracter. Reestablece punteros y contadores. Comprueba la ocupación del buffer de entrada. Comprueba si el buffer de entrada está lleno.

} if (scfstat.v_xoff) { if (incount >= MAXBUFF) { if (inhalt == 0) { /* need to send xoff */ scfstat.v_xoff &= 0xef; /* clear sign bit */ inhalt = scfstat.v_xoff & 0x80; /* flag input halted */ out_cmd = PUTCHI; /* enable out irqs */ /* do wakeup */ if (error =scfstat.v_sysio.v_wake){ stat.v_sysio.v_wake=0x00; /* clear wake */ error = _f_send(error,SIGWAKE); /* send signal */ } } else { if (error =scfstat.v_sysio.v_wake){ scfstat.v_sysio.v_wake=0x00; /* clear wake */ error=_f_send(error,SIGWAKE); /* send signal */ } } } else { if (error = scfstat.v_sysio.v_wake) { scfstat.v_sysio.v_wake= 0x00; /* clear wake */ error = _f_send(error, SIGWAKE); /* send signal */ } } } else { if (error = scfstat.v_sysio.v_wake) { scfstat.v_sysio.v_wake = 0x00; /* clear wake */ error = _f_send(error, SIGWAKE); /* send signal */ } } } do_getch(); /* enable input interrupts */ return error; } /* * out_irq() - process output interrupt */ int out_irq() { register u_short status; /* command status holder */ register u_char tmpchar; /* character holder */ register int error; /* error holder */

Comprueba el valor del contador de caracteres de entrada. Verifica si admite lectura de caracteres. Dependiendo del estado del dispositivo, el driver manda el error correspondiente en caso de haberlo. Subrutina de enviar caracter.

error = 0x00; status = out_cmdram->cmdstat; out_cmdram->cmdstat = 0x8000; if (inhalt & 0x80) { /* xon or xoff to send? */ tmpchar = inhalt & 0xef; /* clear flag bit */ do_putch(tmpchar); /* send character */ inhalt = scfstat.v_xon ^ tmpchar; /* mark character sent */ if (outhalt == 0x00) return 0; } else { if (outcount = 0x00) outhalt |= H_EMPTY; else { if (outhalt = 0x00) {/*are we halted ? */ outcount--; /* no, get one char from buffer */ do_putch(*outempty++); /* go write it */ if (outempty == outend) outempty = outbuf; if (outcount >= LOW_CNT) { if (outcount == 0) { /* any more data in buffer ? */ outhalt |= H_EMPTY; /* no, mark buffer empty */ } } else return 0; } } } out_cmd = PUTCH; /* disable output irq */ if (error = scfstat.v_sysio.v_wake) { scfstat.v_sysio.v_wake = 0x00; /* clear wake */ error = _f_send(error, SIGWAKE); /* send signal */ } return 0; } MISC.C /* * misc - miscellaneous functions for the scisio driver */ #include "scisio.h" /* gets all the defs */ /* * Copyright 1989 by Microware Systems Corporation * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited. */ /* * config_port(opts) */ int config_port(opt)

Comprueba si se puede enviar caracter de control. Observa si el buffer está vacío. Escribe el caracter si el sistema lo permite. Además, actualiza los punteros y contadores oportunos. Este módulo de código fuente desarrolla funciones llamadas desde las rutinas anteriores. Todas estas funciones se basan en la estructura de comandos que permite la placa ISIO. Esta función configura el controlador de disositivo.

struct scf_opt *opt; /* scf options pointer */ { register u_short cmdstatus; /*firmware error return code */ register u_char tmpchar; /* register char */ register u_int isiobase; /* base address of ISIO */ register u_char *ptr; /* pointer to parameter block */ register Cmdram cmdram; /* local pointer to cmdram */ isiobase = (u_int) ((u_int) scfstat.v_sysio.v_port & 0xffff0000); cmdram = out_cmdram; /* get local pointer in reg */ /* issue the ASYINI firmware command */ cmdram->cmdparm1 = 0x00; /* reserved */ cmdram->cmdparm3h = 0x00; /* reserved */ cmdram->cmdparm3l = 0x00; /* reserved */ cmdram->cmdcode = 0x00; /* reserved */ cmdram->reserved = 0x00; /* reserved */ /* build parameter block */ ptr = (u_char *) (isiobase + CHDPROFFS + channel * CHDPRSIZE); *ptr++ = 0x02; /* driver does software handshake */ tmpchar = (opt->pd_par >> 2) & 0x03; switch (tmpchar) { /* character length */ case 0: *ptr++ = 0x03; break; case 1: *ptr++ = 0x02; break; case 2: *ptr++ = 0x01; break; case 3: *ptr++ = 0x00; } tmpchar = (opt->pd_par >> 4) & 0x03; switch (tmpchar) { /* stop bits */ case 0: *ptr++ = 0x07; break; case 1: *ptr++ = 0x08; break; case 2: *ptr++ = 0x0f; } tmpchar = opt->pd_par & 0x03; switch (tmpchar) { /* parity */ case 0: *ptr++ = 0x00; break; case 1: *ptr++ = 0x06; break; case 3: *ptr++ = 0x02; } tmpchar = opt->pd_bau; switch (tmpchar) { /* baud rate */ case 0: case 1: case 2: case 3: case 4: case 0x0c: *ptr++ = opt->pd_bau; *ptr++ = opt->pd_bau;

Inicializa las variables que utiliza el sistema para controlar al dispositivo. Inicializa variables internas. Comprueba la longitud del caracter en transmisión. Comprueba los bits de stop. Comprueba la paridad. La velocidad de transmisión.

break; case 5: case 6: case 9: case 0x0a: *ptr++ = opt->pd_bau + 0x01; *ptr++ = opt->pd_bau + 0x01; break; case 7: *ptr++ = opt->pd_bau + 0x02; *ptr++ = opt->pd_bau + 0x02; break; case 0x0e: case 0x0f: *ptr++ = opt->pd_bau - 0x01; *ptr++ = opt->pd_bau - 0x01; break; case 8: case 0x0b: case 0x0d: return E_PARAM; } ptr = (u_char *) (isiobase + CHDPROFFS + channel * CHDPRSIZE); cmdram->cmdparm2l = (u_short) ((u_int) ptr - (u_int) isiobase); cmdram->cmdparm2h = 0x00; cmdram->cmdstat = ASYNINI; /* BONZAI!! */ do { cmdstatus = cmdram->cmdstat; } while ((cmdstatus & 0x8000) == 0) ;/* poll until done */ cmdstatus = cmdram->cmdstat & 0x000f; /* mask error */ if (cmdstatus) return E_PARAM; else { curr_baud = opt->pd_bau; curr_par = opt->pd_par; } return 0; } /* * void do_getch() - issue the firmware getch command * this acts like enabling input interrupts. The character is * read by the interrupt service routine. */ void do_getch() { register Cmdram cmdram; /* local pointer to cmdram */ cmdram = in_cmdram; /* get local pointer in reg */ cmdram->cmdparm1 = 0x00; /* reserved */ cmd_pending |= INPENDING;/* flag input command pending */ cmdram->cmdstat = GETCH; } /* * void do_putch() - issue the firmware putch command * The character is written to the serial port */ void do_putch(output) u_char output; /* character to write */ { register Cmdram cmdram; /* local pointer to cmdram */ register u_short cmd; /* local command */ register u_short status; /* status register */

Esta función manda un comando de obtener caracter. Esta función manda un comando para poner un caracter.

cmdram = out_cmdram; /* get local pointer in reg */ cmd = out_cmd; /* get local command */ cmd_pending |= (cmd == (PUTCHI ? OUTPENDING : 0x00)); cmdram->cmdparm1 = output;/* write this character */ cmdram->cmdstat = cmd; if (cmd == PUTCH) { do { status = cmdram->cmdstat;/* are we done? */ } while ((status & 0x8000) == 0x00); } return; } /* * int output_ok() - issues the firmware outstat command * and checks if output is possible. returns 1 if possible, * 0 if impossible. */ int output_ok() { register u_short status; register Cmdram cmdram; cmdram = out_cmdram; cmdram->cmdstat = OUTSTAT; do { status = cmdram->cmdstat; /* are we done? */ } while ((status & 0x8000) == 0); return ((cmdram->cmdparm1 & 0x8000) == 0x00); } /* * void do_clrbuf() - issue the firmware clrbuf command * The input buffer is emptied */ void do_clrbuf() { register Cmdram cmdram; /* local pointer to cmdram */ register u_short status; /* status register */ cmdram = in_cmdram; /* get address of input cmdram */ cmdram->cmdparm1 = 0x00; cmdram->cmdparm2h = 0x00; cmdram->cmdparm2l = 0x00; cmdram->cmdparm3h = 0x00; cmdram->cmdparm3l = 0x00; cmdram->cmdcode = 0x00; cmdram->reserved = 0x00; cmdram->cmdstat = CLRBUF; do {

Chequea si es posible enviar un caracter. Borra y vacía el buffer de entrada.

status = cmdram->cmdstat; /* are we done? */ } while ((status & 0x8000) == 0); } /* * void do_recoff() - issue the firmware recoff command * The DUSCC reciever is turned off */ void do_recoff() { register Cmdram cmdram; /* local pointer to cmdram */ register u_short status; /* status register */ cmdram = in_cmdram; /* get address of input cmdram */ cmdram->cmdparm1 = 0x00; cmdram->cmdparm2h = 0x00; cmdram->cmdparm2l = 0x00; cmdram->cmdparm3h = 0x00; cmdram->cmdparm3l = 0x00; cmdram->cmdcode = 0x00; cmdram->reserved = 0x00; cmdram->cmdstat = RECOFF; do { status = cmdram->cmdstat; /* are we done? */ } while ((status & 0x8000) == 0); } /*************************** * drv_sleep() - sleep after command issued */ int drv_sleep() { register int error; /* error code */ scfstat.v_sysio.v_wake = scfstat.v_sysio.v_busy; do { if (error = _f_sleep(0)) return error; } while (scfstat.v_sysio.v_wake != 0); return(0); } /* * int abort_chnl() - abort pending operations on the current channel */ int abort_chnl() { register u_short *abrtflag; /* pointer to abort flags */ register u_char *trigger; /* pointer to trigger address */ register u_int ab_chnl; /* channel to abort */ register u_char c; /* read trigger abort */ register u_int isiobase; /* base address of ISIO */ register int count; /* counter */ isiobase = (u_int) ((u_int) scfstat.v_sysio.v_port & 0xffff0000); abrtflag = (u_short *) (isiobase + 0x8100); /* point at flag */ trigger = (u_char *) (isiobase + 0x1001); /* point at trigger */ ab_chnl = ((u_int) in_cmdram & 0xff) / 0x10 + 1; /* calculate channel # */ do { for (count = 0; count <= 10000; count++) ; *abrtflag = (u_short) ab_chnl;

Envia comando para deshabilitar al controlador como dispositivo de entrada. Esta función pone al proceso en estado de sleep. ESta función corta todas las operaciones en el canal de transmisión.

/* set channel to abort */ c = *trigger; /* BONZAI !! */ while (*abrtflag > 0); /* twiddle twiddle */ } while ((in_cmdram->cmdstat & 0x8000) == 0); ab_chnl++; do { for (count = 0; count <= 10000; count++) ; *abrtflag = (u_short) ab_chnl; /* set channel to abort */ c = *trigger; /* BONZAI !! */ while (*abrtflag > 0); /* twiddle twiddle */ } while ((out_cmdram->cmdstat & 0x8000) == 0); return 0; } /* * int mask_irq(mask) - mask interrupts to level of device */ #ifdef OSK /* * WARNING - THIS IS 68xxx SPECIFIC CODE * Note also that stack is kept long-aligned. */ #asm mask_irq: clr.l -(sp) keep stack long-aligned move.w sr,2(sp) save current status word move.w d0,sr mask interrupts move.l (sp)+,d0 return original mask rts #endasm #endif MAKE.ISIO # makefile for scisio driver # # This driver should always be made non-cpu specific, so that # it will always be a "portable" driver (i.e. no -k options, # no cpu specific conditionals). OBJ = scisio # the high-level driver name SDIR = . RDIR = RELS ODIR = ../../CMDS/BOOTOBJS LIB = ../../LIB SCFDEF = ../../DEFS SCOM = . # Note: xxglue.r MUST be linked first in final output GLUENAM = scglue CALLNAM = syscalls SGLUE = $(SCOM)/RELS/$(GLUENAM).r SCALL = $(SCOM)/RELS/$(CALLNAM).r SLIB = $(LIB)/sys.l FILES = main.r init.r read.r write.r stat.r term.r misc.r irq.r COMDEFS = DEFS = $(OBJ).h # $(COMDEFS) MAKER = ./make.isio

Enmascara las interrupciones. Este fichero especifica los pasos para obtener el driver final. En este módulo se observan las interdependencias de los módulos anteriores.

CFLAGS = -qt=/dd -v=$(SCFDEF) -s RFLAGS = -q $(OBJ) : $(FILES) $(SLIB) $(SGLUE) $(SCALL) chd $(RDIR); l68 ../$(SGLUE) $(FILES) ../$(SCALL) -l=../$(SLIB) \ -l=../$(LIB)/math.l -O=../$(ODIR)/$(OBJ) -g -msw >-map.$(OBJ) touch make.isio $(FILES) : $(DEFS) $(MAKER) $(SGLUE) : $(SCOM)/$(GLUENAM).a chd $(SCOM); make $(GLUENAM).r $(SCALL) : $(SCOM)/$(CALLNAM).a chd $(SCOM); make $(CALLNAM).r