Vuelo del Colibrí. De lo que es capaz un sistema operativo, escrito completamente en ensamblador. Escuela de ensamblaje: ensamblajes de desarrollo de sistemas operativos para DOS

Recientemente decidí aprender ensamblador, pero no me interesaba desperdiciar líneas de código. Pensé que mientras estudiaba ensamblador dominaría alguna materia. Así que mi elección recayó en escribir un gestor de arranque. El resultado de mis hallazgos está aquí en este blog.

Quiero decir de inmediato que me encanta la teoría combinada con la práctica, así que comencemos.

Primero te mostraré cómo crear un simple MBR para que podamos disfrutar del resultado lo antes posible. A medida que nos volvamos más complejos con ejemplos prácticos, proporcionaré información teórica.

¡Primero hagamos un gestor de arranque de unidad flash USB!

¡¡¡Atención!!! Nuestro primer programa ensamblador funcionará tanto para una unidad flash como para otros dispositivos, como un disquete o un disco duro. Posteriormente, para que todos los ejemplos funcionen correctamente, daré una serie de aclaraciones respecto al funcionamiento del código en diferentes dispositivos.

escribiremos a fasm, ya que se considera el mejor compilador para escribir cargadores, lo cual es MBR. La segunda razón para elegir Fasm es que simplifica enormemente el proceso de compilación de archivos. Sin directivas de línea de comandos, etc. tonterías que pueden desalentar por completo el aprendizaje del ensamblador y lograr sus objetivos Entonces, en la etapa inicial, necesitamos dos programas y algunos innecesario pequeña unidad flash. Desenterré 1 Gb (formateado rápidamente, y no es una pena, en todo caso). Después del trabajo de nuestro cargador de arranque, la unidad flash dejará de funcionar normalmente. mi Windows 7 se niega a formatear la unidad flash. Te aconsejo que devuelvas la vida a la unidad flash con una utilidad. Herramienta de formato de almacenamiento en disco USB de HP ( HPUSBFW.EXE) u otras utilidades para formatear unidades flash.

Instálalos y lanza los accesos directos apropiados en el escritorio o donde quieras.

La preparación ha terminado, pasemos a la acción.

Abra Fasmw.exe y escriba lo siguiente allí. Esbozaremos el mínimo de código para ver el resultado. Más adelante analizaremos qué es nakalyakano aquí. Comentaré brevemente.

Código FASM: ============= boot.asm ===============

organización 7C00h; las direcciones de nuestro programa se calculan de acuerdo con esta directiva

uso16; se genera código hexadecimal

cli ; deshabilitar interrupciones para cambiar direcciones en registros de segmento

hacha de movimiento, 0

mov sp, 7C00h

sti ; habilitar interrupciones (después de cambiar direcciones)

mov ax, 0003h; establece el modo de video para mostrar la cadena en la pantalla

en 10h

mov ax, 1301h; función de salida de cadena real 13h int 10h (más sobre eso más adelante)

mov bp, stroka; dirección de la cadena de salida

mov dx, 0000h ;línea y columna en la que se muestra el texto

mov cx, 15 ;número de caracteres en la cadena de salida

mov bx, 000eh ;00-número de página de video (mejor no tocar) 0e-atributos de carácter (color, fondo)

en 10h

jmp $ ;stalk en su lugar (recorre el programa en este punto)

line db "¡Ok, MBR cargado!"

veces 510 - ($ - $$) db 0 ;rellenando con ceros el espacio entre el byte anterior y el último

db 0x55 ,0xAA ;los dos últimos bytes

Compile este código (Ctrl + F9) en fasm "e y guarde el archivo binario resultante como boot.bin en algún lugar conveniente. Antes de escribir nuestro binario en una unidad flash USB, un poco de teoría.

Cuando conectó la unidad flash USB a la computadora, no es absolutamente obvio para el sistema BIOS que desea iniciar desde la unidad flash USB, por lo que en la configuración del BIOS debe seleccionar el dispositivo desde el que desea iniciar. elegimos arrancar desde USB (tendrá que descubrir cómo hacerlo usted mismo, ya que la interfaz del BIOS tiene varias variaciones... puede buscar en Google la configuración del BIOS para su placa base, no hay nada complicado, por regla general).

Ahora que el BIOS sabe que desea iniciar desde la unidad flash, debe asegurarse de que el sector cero en la unidad flash sea arrancable. Para hacer esto, el BIOS busca últimos dos bytes del sector cero y, si son iguales a 0x55 0xAA, solo entonces se cargará en la RAM. De lo contrario, el BIOS simplemente pasará por su unidad flash. Habiendo encontrado estos dos bytes mágicos, carga el sector cero en la RAM en la dirección 0000: 7C00h, y luego se olvida de la unidad flash y transfiere el control a esta dirección. Ahora todo el poder sobre la computadora pertenece a su cargador de arranque y, actuando ya desde la RAM, puede cargar código adicional desde la unidad flash USB. Ahora veremos cómo se ve este mismo sector en el programa DMDE.

1. Inserte su unidad flash en la computadora y asegúrese de que no contenga la información que necesita.

2.Abra el programa DMDE. Lea todas las acciones adicionales en las imágenes:

Después de ver este cómic, tendrá la habilidad de descargar su MBR a una unidad flash. Y así luce el esperado resultado de nuestro bootloader:


Por cierto, si hablamos del código de cargador mínimo, entonces puede verse así:

Organización 7C00h
jmp$
db 508 duplicado (0)
base de datos 0x55.0xAA

Dicho cargador, después de haber recibido el control, simplemente cuelga la computadora y ejecuta un comando sin sentido jmp $ en un ciclo. Yo la llamo estancamiento.

Publiqué un video en YouTube que podría ayudarte:

Finalmente, algunos breves datos sobre el trabajo del gestor de arranque:

1. El cargador de arranque, también conocido como cargador de arranque, también conocido como MBR tiene un tamaño de 512 bytes. Históricamente,
que esta condición debe cumplirse para admitir medios y dispositivos más antiguos.
2. El cargador de arranque siempre se encuentra en el sector cero de una unidad flash, disquete, disco duro, desde el punto de vista del programa DMDE u otros editores hexadecimales que le permiten trabajar con dispositivos. Para cargar un binario (nuestro boot.bin) en uno de los dispositivos enumerados, no necesitamos pensar en su estructura física interna. El programa DMDE solo sabe cómo leer sectores en estos dispositivos y los muestra en modo LBA (simplemente los numera desde 0 hasta el último sector). Puedes leer sobre LBA
3. El cargador de arranque siempre debe terminar con dos bytes 0x55 0xAA.
4. El cargador siempre se carga en la memoria a las 0000:7C00h.
5. El gestor de arranque inicia el sistema operativo.


ensamblador

ensamblador(del inglés ensamblar - ensamblar) - un compilador de lenguaje ensamblador a comandos de lenguaje de máquina.
Para cada arquitectura de procesador y para cada sistema operativo o familia de sistemas operativos, hay un ensamblador. También existen los llamados "ensambladores cruzados", que permiten en máquinas con una arquitectura (o en el entorno de un sistema operativo) ensamblar programas para otra arquitectura de destino u otro sistema operativo, y obtener código ejecutable en un formato adecuado para su ejecución en la arquitectura de destino o en el entorno de destino.

arquitectura x86

Ensambladores para DOS

Los ensambladores más conocidos para el sistema operativo DOS fueron Borland Turbo Assembler (TASM) y Microsoft Macro Assembler (MASM). También en un momento, el ensamblador simple A86 fue popular.
Inicialmente, solo admitían instrucciones de 16 bits (antes de la llegada del procesador Intel 80386). Las versiones posteriores de TASM y MASM admiten instrucciones de 32 bits, así como todas las instrucciones introducidas en procesadores más modernos y sistemas de instrucciones específicos de la arquitectura (como, por ejemplo, MMX, SSE, 3DNow!, etc.) .

Microsoft Windows

Con la llegada del sistema operativo Microsoft Windows, apareció una extensión de TASM llamada TASM32, que hizo posible crear programas para ejecutar en el entorno de Windows. La última versión conocida de Tasm es la 5.3, que admite instrucciones MMX y actualmente se incluye en Turbo C++ Explorer. Pero oficialmente el desarrollo del programa está completamente detenido.
Microsoft mantiene un producto llamado Microsoft Macro Assembler. Continúa evolucionando hasta el día de hoy, con las últimas versiones incluidas en los DDK. Pero la versión del programa destinada a crear programas para DOS no se está desarrollando. Además, Stephen Hutchesson creó un paquete de programación MASM llamado "MASM32".

GNU y GNU/Linux

El sistema operativo GNU incluye el compilador gcc, que incluye el ensamblador de gas (GNU Assembler) que usa la sintaxis de AT&T, a diferencia de la mayoría de los otros ensambladores populares que usan la sintaxis de Intel.

Ensambladores portátiles

También hay un proyecto de ensamblador abierto, cuyas versiones están disponibles para varios sistemas operativos, y que le permite obtener archivos de objetos para estos sistemas. Este ensamblador se llama NASM (Netwide Assembler).
YASM es una versión reescrita de NASM con licencia desde cero (con algunas excepciones).
FASM (Flat Assembler) es un ensamblador joven bajo una licencia BSD modificada para prohibir la renovación de licencias (incluso bajo la GPL de GNU). Hay versiones para KolibriOS, GNU/Linux, MS-DOS y Microsoft Windows, usa sintaxis Intel y soporta instrucciones AMD64.

arquitecturas RISC


MCS-51
AVR
Actualmente hay 2 compiladores Atmel (AVRStudio 3 y AVRStudio4). La segunda versión es un intento de corregir la no muy acertada de la primera. También hay un ensamblador en WinAVR.
BRAZO
AVR32
MSP430
PowerPC

Montaje y compilación

El proceso de traducir un programa en lenguaje ensamblador a código objeto se llama ensamblador. A diferencia de la compilación, el ensamblaje es un proceso más o menos inequívoco y reversible. En lenguaje ensamblador, cada mnemónico corresponde a una instrucción de máquina, mientras que en lenguajes de programación de alto nivel, una gran cantidad de instrucciones diferentes pueden esconderse detrás de cada expresión. En principio, esta división es bastante arbitraria, por lo que a veces la traducción de programas ensambladores también se denomina compilación.

lenguaje ensamblador

lenguaje ensamblador- un tipo de lenguaje de programación de bajo nivel, que es un formato para registrar instrucciones de máquina que es conveniente para la percepción humana. A menudo, por brevedad, se le llama simplemente ensamblador, lo cual no es cierto.

Los comandos del lenguaje ensamblador se corresponden uno a uno con los comandos del procesador y, de hecho, representan una forma simbólica conveniente de notación (código mnemotécnico) de los comandos y sus argumentos. El lenguaje ensamblador también proporciona abstracciones básicas de software: vincular partes del programa y datos a través de etiquetas con nombres simbólicos (durante el ensamblado, se calcula una dirección para cada etiqueta, después de lo cual cada aparición de la etiqueta se reemplaza por esta dirección) y directivas.
Las directivas de ensamblaje le permiten incluir bloques de datos (descritos explícitamente o leídos de un archivo) en el programa; repetir un cierto fragmento un número específico de veces; compilar el fragmento según la condición; establezca la dirección de ejecución del fragmento para que sea diferente de la dirección de ubicación de la memoria [¡especifique!]; cambiar los valores de las etiquetas durante la compilación; utilizar definiciones de macro con parámetros, etc.
Cada modelo de procesador, en principio, tiene su propio conjunto de instrucciones y el lenguaje ensamblador (o dialecto) correspondiente.

Ventajas y desventajas

Ventajas del lenguaje ensamblador

La cantidad mínima de código redundante, es decir, el uso de menos instrucciones y accesos a la memoria, permite aumentar la velocidad y reducir el tamaño del programa.
Garantizar la compatibilidad total y el uso máximo de las capacidades de la plataforma deseada: el uso de instrucciones especiales y características técnicas de esta plataforma.
Al programar en ensamblador, se vuelven disponibles funciones especiales: acceso directo al hardware, puertos de E/S y registros especiales del procesador, así como la capacidad de escribir código automodificable (es decir, metaprogramación, y sin necesidad de un intérprete de software) .
Las últimas tecnologías de seguridad implementadas en los sistemas operativos no permiten realizar código automodificable, ya que excluyen la ejecución simultánea de instrucciones y la escritura en la misma área de memoria (tecnología W^X en sistemas BSD, DEP en Windows).

Desventajas del lenguaje ensamblador

Grandes cantidades de código y una gran cantidad de pequeñas tareas adicionales, lo que lleva a que el código se vuelva muy difícil de leer y comprender y, por lo tanto, se vuelve más difícil de depurar y refinar el programa, así como la dificultad de implementar la programación. paradigmas y cualquier otra convención. lo que conduce a la complejidad del desarrollo colaborativo.
Menos bibliotecas disponibles, su baja compatibilidad entre sí.
No es portátil para otras plataformas (que no sean compatibles con binarios).

Solicitud

Se sigue directamente de las ventajas y desventajas.
Dado que es extremadamente inconveniente escribir programas grandes en lenguaje ensamblador, se escriben en lenguajes de alto nivel. En ensamblador, escriben pequeños fragmentos o módulos para los que son críticos:
rendimiento (controladores);
tamaño del código (sectores de arranque, software para microcontroladores y procesadores con recursos limitados, virus, protección de software);
características especiales: trabajar directamente con hardware o código de máquina, es decir, cargadores de sistemas operativos, controladores, virus, sistemas de protección.

Vincular código ensamblador a otros lenguajes

Dado que la mayoría de las veces solo se escriben fragmentos del programa en ensamblador, deben vincularse con el resto de las partes en otros idiomas. Esto se logra de 2 maneras principales:
En tiempo de compilación- insertar fragmentos de ensamblador en el programa (eng. ensamblador en línea) con directivas de lenguaje especiales, incluidos los procedimientos de escritura en lenguaje ensamblador. El método es conveniente para transformaciones de datos simples, pero el código ensamblador completo, con datos y subrutinas, incluidas las subrutinas con muchas entradas y salidas que no son compatibles con los lenguajes de alto nivel, no se puede usar.
En la etapa de construcción, o compilación separada. Para que los módulos de enlace interactúen, es suficiente que las funciones de enlace admitan las convenciones de llamada y los tipos de datos requeridos. Los módulos separados se pueden escribir en cualquier idioma, incluido el lenguaje ensamblador.

Sintaxis

No existe un estándar generalmente aceptado para la sintaxis de los lenguajes ensambladores. Sin embargo, existen estándares a los que se adhieren la mayoría de los desarrolladores de lenguaje ensamblador. Los principales estándares de este tipo son la sintaxis de Intel y la sintaxis de AT&T.

Instrucciones

El formato general para escribir instrucciones es el mismo para ambos estándares:

[etiqueta:] código de operación [operandos] [;comentario]

donde el código de operación es directamente el mnemotécnico de la instrucción al procesador. Se le pueden añadir prefijos (repeticiones, cambios de tipo de direccionamiento, etc.).
Los operandos pueden ser constantes, nombres de registros, direcciones de RAM, etc. Las diferencias entre los estándares de Intel y AT&T se relacionan principalmente con el orden en que se enumeran los operandos y su sintaxis para diferentes métodos de direccionamiento.
Los mnemotécnicos utilizados suelen ser los mismos para todos los procesadores de la misma arquitectura o familia de arquitecturas (entre los mnemotécnicos más conocidos se encuentran los procesadores y controladores Motorola, ARM, x86). Se describen en la especificación del procesador. Posibles excepciones:
Si el ensamblador usa sintaxis de AT&T multiplataforma (los mnemotécnicos originales se convierten en sintaxis de AT&T)
Si inicialmente había dos estándares para escribir mnemotécnicos (el sistema de instrucciones se heredó del procesador de otro fabricante).
Por ejemplo, el procesador Zilog Z80 heredó el conjunto de instrucciones Intel i8080, lo amplió y cambió los mnemotécnicos (y las designaciones de registro) a su manera. Por ejemplo, cambié el mov de Intel a ld. Los procesadores Motorola Fireball heredaron el conjunto de instrucciones Z80, reduciéndolo un poco. Sin embargo, Motorola ha vuelto oficialmente a los mnemónicos de Intel. Y por el momento, la mitad de los ensambladores de Fireball trabajan con mnemónicos de Intel y la otra mitad con mnemónicos de Zilog.

directivas

Además de las instrucciones, el programa puede contener directivas: comandos que no se traducen directamente en instrucciones de máquina, sino que controlan el funcionamiento del compilador. Su conjunto y sintaxis varían significativamente y no dependen de la plataforma de hardware, sino del compilador utilizado (dando lugar a dialectos de lenguajes dentro de una misma familia de arquitecturas). Como un "conjunto de caballeros" de directivas, podemos distinguir:
definición de datos (constantes y variables)
gestionar la organización del programa en memoria y los parámetros del archivo de salida
configurar el modo compilador
todo tipo de abstracciones (es decir, elementos de lenguajes de alto nivel), desde el diseño de procedimientos y funciones (para simplificar la implementación del paradigma de programación procedimental) hasta estructuras y bucles condicionales (para el paradigma de programación estructurada)
macros

Ejemplo de programa

Un ejemplo de un programa Hello world para MS-DOS para la arquitectura x86 en el dialecto TASM:

.MODELO PEQUEÑO SEGMENTO DE CÓDIGO ASUME CS:CÓDIGO, DS:CÓDIGO ORG 100h INICIO: mov ah,9 mov dx,OFFSET Msg int 21h int 20h Msg DB "Hello World",13,10,"$" CÓDIGO TERMINA FIN INICIO

Origen y crítica del término "lenguaje ensamblador"

Este tipo de lenguaje obtuvo su nombre del nombre del traductor (compilador) de estos lenguajes: ensamblador (ensamblador en inglés - ensamblador). El nombre de este último se debe a que en las primeras computadoras no existían lenguajes de nivel superior, y la única alternativa a la creación de programas usando ensamblador era programar directamente en códigos.
El lenguaje ensamblador en ruso a menudo se llama "ensamblador" (y algo relacionado con él, "ensamblador"), lo que, según la traducción al inglés de la palabra, es incorrecto, pero se ajusta a las reglas del idioma ruso. Sin embargo, el ensamblador (programa) en sí mismo también se denomina simplemente "ensamblador" y no "compilador de lenguaje ensamblador", etc.
El uso del término "lenguaje ensamblador" también puede dar lugar a la idea errónea de que existe un único lenguaje de bajo nivel, o al menos un estándar para dichos lenguajes. Al nombrar el lenguaje en el que está escrito un programa en particular, es deseable especificar para qué arquitectura está destinado y en qué dialecto del lenguaje está escrito.

Digo de inmediato, no cierre el artículo con los pensamientos "Maldita sea, otro Popov". El solo tiene un Ubuntu lamido, y yo tengo todo desde cero, incluido el kernel y las aplicaciones. Entonces, continuación bajo el corte.

grupo de SO: aquí.
Primero, te daré una captura de pantalla.

No hay más de ellos, y ahora con más detalle sobre por qué lo estoy escribiendo.

Era una cálida tarde de abril, jueves. Desde niño, soñaba con escribir un sistema operativo, cuando de repente pensé: "Ahora que conozco los pros y los asm, ¿por qué no hacer realidad mi sueño?". Busqué en Google sitios sobre este tema y encontré un artículo de Habr: "Cómo comenzar y no dejar de escribir SO". Gracias a su autor por el enlace OSDev Wiki a continuación. Fui allí y comencé a trabajar. Había en un artículo todos los datos sobre el sistema operativo mínimo. Comencé a construir cross-gcc y binutils y luego reescribí todo desde allí. Deberías haber visto mi alegría cuando vi la inscripción "¡Hola, kernel World!" Salté de la silla y me di cuenta: no me rendiré. Escribí "consola" (entre comillas, no tenía acceso a un teclado), pero luego decidí escribir un sistema de ventanas. Como resultado, funcionó, pero no tenía acceso al teclado. Y luego decidí pensar en un nombre basado en el sistema X Window. Sistema de ventana Y buscado en Google: lo es. Como resultado, llamó a Z Window System 0.1, que se incluye en OS365 pre-alpha 0.1. Y sí, nadie lo vio excepto yo. Luego descubrí cómo implementar la compatibilidad con el teclado. Captura de pantalla de la primera versión, cuando no había nada, ni siquiera un sistema de ventanas:

Ni siquiera movió el cursor de texto, como puede ver. Luego escribí un par de aplicaciones sencillas basadas en Z. Y aquí está la versión alfa 1.0.0. Había muchas cosas, incluso el menú del sistema. Y el administrador de archivos y la calculadora simplemente no funcionaron.

Fui aterrorizado directamente por una amiga que solo se preocupa por la belleza (Mitrofan, lo siento). Dijo: “¡Lavado el modo VBE 1024 * 768 * 32, lavado, lavado! ¡Pues se emborracharon! Bueno, ya estaba cansada de escucharlo y aún así lo lavé. Más sobre la implementación a continuación.

Hice todo con mi cargador de arranque, a saber, GRUB "ohm. Con él, puede configurar el modo de gráficos sin complicaciones agregando algunas líneas mágicas al encabezado Multiboot.

Establecer ALINEAR, 1<<0 .set MEMINFO, 1<<1 .set GRAPH, 1<<2 .set FLAGS, ALIGN | MEMINFO | GRAPH .set MAGIC, 0x1BADB002 .set CHECKSUM, -(MAGIC + FLAGS) .align 4 .long MAGIC .long FLAGS .long CHECKSUM .long 0, 0, 0, 0, 0 .long 0 # 0 = set graphics mode .long 1024, 768, 32 # Width, height, depth
Y luego tomo la dirección del búfer de fotogramas y la resolución de pantalla de la estructura de información Multiboot y escribo píxeles allí. VESA hizo todo muy confuso: los colores RGB deben ingresarse en orden inverso (no R G B, sino B G R). No entendí durante varios días: ¿por qué no se muestran los píxeles? Al final, me di cuenta que olvidé cambiar los valores de 16 constantes de color de 0...15 a sus equivalentes RGB. Como resultado, lo liberé, al mismo tiempo que lavé el fondo degradado. Luego hice una consola, 2 aplicaciones y lancé 1.2. Ah, sí, casi lo olvido: puedes descargar el sistema operativo en

Original: AsmSchool: Hacer un sistema operativo
Autor: Mike Saunders
Fecha de publicación: 15 de abril de 2016
Traducción: A. Panin
Fecha de transferencia: 16 de abril de 2016

Parte 4: Con las habilidades que ha aprendido de los artículos anteriores de la serie, ¡puede comenzar a desarrollar su propio sistema operativo!

¿Para qué sirve?

  • Entender cómo funcionan los compiladores.
  • Comprender las instrucciones de la unidad central de procesamiento.
  • Para optimizar su código en términos de rendimiento.

En el transcurso de unos pocos meses, hemos recorrido un largo camino, que comenzó con el desarrollo de programas sencillos en lenguaje ensamblador para Linux y terminó en el último artículo de la serie con el desarrollo de código autónomo que se ejecuta en una computadora personal. sin un sistema operativo. Bueno, ahora intentaremos recopilar toda la información y crear un sistema operativo real. Sí, seguiremos los pasos de Linus Torvalds, pero antes conviene responder a las siguientes preguntas: "¿Qué es un sistema operativo? ¿Cuáles de sus funciones tendremos que recrear?".

En este artículo, nos centraremos solo en las funciones principales del sistema operativo: cargar y ejecutar programas. Los sistemas operativos complejos realizan muchas más funciones, como administrar la memoria virtual y procesar paquetes de red, pero requieren años de trabajo continuo para implementarse correctamente, por lo que en este artículo solo consideraremos las funciones principales que están presentes en cualquier sistema operativo. El mes pasado desarrollamos un pequeño programa que cabe en un sector de 512 bytes de un disquete (su primer sector), y ahora lo modificaremos un poco para agregar la función de cargar datos adicionales desde el disco.

Desarrollo del cargador de arranque

Podríamos intentar mantener el binario de nuestro sistema operativo lo más pequeño posible para colocarlo en el primer sector de 512 bytes del disquete, el que carga la BIOS, pero en este caso no podremos implementar cualquier función interesante. Por lo tanto, usaremos estos 512 bytes para colocar el código binario de un cargador de sistema simple que cargará el código binario del kernel del sistema operativo en la RAM y lo ejecutará. (Después de eso, desarrollaremos el propio kernel del sistema operativo, que cargará el código binario de otros programas desde el disco y también lo ejecutará, pero hablaremos de esto un poco más adelante).

Puede descargar el código fuente de los ejemplos discutidos en este artículo en www.linuxvoice.com/code/lv015/asmschool.zip. Y este es el código de nuestro gestor de arranque de un archivo llamado boot.asm:

BITS 16 jmp inicio corto; Saltar a la etiqueta omitiendo la descripción del disco nop; Adición antes de la descripción del disco %incluye "bpb.asm" start: mov ax, 07C0h ; Cargar dirección mov ds, ax ; Eje de movimiento del segmento de datos, 9000h; Preparar stack mov ss, ax mov sp, 0FFFFh ; ¡La pila está creciendo hacia abajo! cld; Establecer indicador de dirección mov si, kern_filename call load_file jmp 2000h:0000h ; Saltar al binario del núcleo del SO cargado desde el archivo kern_filename db "MYKERNELBIN" %include "disk.asm" veces 510-($-$$) db 0 ; Relleno con ceros de código binario hasta 510 bytes dw 0AA55h ; Búfer de marca final del código binario del cargador de arranque: ; Búfer de inicio para el contenido del disco

En este código, la primera instrucción de la CPU es la instrucción jmp, que se encuentra después de la directiva BITS, que le dice al ensamblador NASM que se está utilizando el modo de 16 bits. Como probablemente recuerde del artículo anterior de la serie, la ejecución del código binario de 512 bytes cargado por el BIOS desde el disco comienza desde el principio, pero tenemos que saltar a la etiqueta para omitir el conjunto de datos especial. Obviamente, el mes pasado simplemente escribimos el código al principio del disco (usando la utilidad dd) y dejamos el resto del espacio del disco vacío.

Ahora tendremos que usar un disquete con un sistema de archivos MS-DOS (FAT12) adecuado, y para que funcione correctamente con este sistema de archivos, debemos agregar un conjunto de datos especiales cerca del comienzo del sector. Este conjunto se denomina "Bloque de parámetros del BIOS" (BPB) y contiene datos como la etiqueta del disco, el número de sectores, etc. No debería interesarnos en esta etapa, ya que dichos temas pueden estar dedicados a más de una serie de artículos, por lo que colocamos todas las instrucciones y datos relacionados en un archivo de código fuente separado llamado bpb.asm.

Basado en lo anterior, esta directiva de nuestro código es extremadamente importante:

%incluye "bpb.asm"

Esta es una directiva NASM que permite que el contenido del archivo fuente especificado se incluya en el archivo fuente actual durante el ensamblaje. Por lo tanto, podremos hacer que el código de nuestro cargador del sistema sea lo más breve y comprensible posible moviendo todos los detalles de la implementación del bloque de parámetros del BIOS en un archivo separado. El bloque de parámetros del BIOS debe ubicarse tres bytes después del inicio del sector, y dado que la instrucción jmp solo ocupa dos bytes, debemos usar la instrucción nop (su nombre significa "sin operación"; esta es una instrucción que no hace nada pero desperdicia ciclos de CPU) para llenar el byte restante.

Trabajando con la pila

A continuación, tendremos que usar instrucciones similares a las discutidas en el artículo anterior para preparar los registros y la pila, así como la instrucción cld (significa "dirección clara"), que le permite establecer la bandera de dirección para ciertas instrucciones, como la instrucción lodsb, que, cuando se ejecuta, incrementará el valor en el registro SI en lugar de disminuirlo.

Después de eso, colocamos la dirección de la cadena en el registro SI y llamamos a nuestra función load_file. Pero piense por un momento: ¡aún no hemos desarrollado esta función! Sí, eso es cierto, pero su implementación se puede encontrar en otro archivo de código fuente que incluimos llamado disk.asm.

El sistema de archivos FAT12, utilizado en disquetes formateados en MS-DOS, es uno de los sistemas de archivos más simples que existen, pero también requiere una buena cantidad de código para trabajar con su contenido. La subrutina load_file tiene unas 200 líneas y no se mostrará en este artículo, ya que estamos considerando el desarrollo de un sistema operativo, no un controlador para un sistema de archivos específico, por lo tanto, no es muy inteligente desperdiciar espacio en las páginas de registro. De este modo. En general, incluimos el archivo de código fuente disk.asm casi antes del final del archivo fuente actual y podemos olvidarnos de él. (Si todavía está interesado en la estructura del sistema de archivos FAT12, puede leer la excelente descripción general en http://tinyurl.com/fat12spec y luego buscar en el archivo de código fuente disk.asm; el código que contiene es bien comentado)

En cualquier caso, la subrutina cargar_archivo carga el código binario del archivo con el nombre especificado en el registro SI en el segmento 2000 con desplazamiento 0, después de lo cual saltamos a su inicio para la ejecución. Y eso es todo: ¡el kernel del sistema operativo está cargado y el cargador del sistema ha completado su tarea!

Es posible que haya notado que nuestro código usa MYKERNELBIN en lugar de MYKERNEL.BIN como el nombre de archivo del núcleo del sistema operativo, lo que encaja bien con el esquema de nombres 8+3 que se usa en los disquetes en DOS. De hecho, el sistema de archivos FAT12 usa la representación interna de los nombres de archivo, y ahorramos espacio al usar un nombre de archivo que garantiza que no requerirá que nuestra subrutina load_file implemente un mecanismo para buscar el carácter de punto y convertir el nombre de archivo a la representación interna del sistema de archivos

Después de la línea con la directiva para conectar el archivo de código fuente disk.asm, hay dos líneas diseñadas para rellenar el código binario del cargador del sistema con ceros hasta 512 bytes e incluir la marca final de su código binario (esto se discutió en el último artículo). Finalmente, al final del código está la etiqueta "búfer", que es utilizada por la subrutina load_file. En general, la subrutina load_file necesita espacio libre en la RAM para realizar algunas acciones intermedias en el proceso de encontrar un archivo en el disco, y tenemos suficiente espacio libre después de cargar el gestor de arranque, por lo que colocamos el búfer aquí.

Para ensamblar el cargador de arranque, use el siguiente comando:

nasm -f bin -o arranque.bin arranque.asm

Ahora necesitamos crear una imagen de disquete virtual de MS-DOS y agregar nuestro binario de cargador de arranque a sus primeros 512 bytes usando los siguientes comandos:

Mkdosfs -C disquete.img 1440 dd conv=notrunc if=boot.bin of=disquete.img

¡Esto completa el proceso de desarrollo del gestor de arranque! Ahora tenemos una imagen de disquete de arranque que nos permite cargar el binario del kernel del sistema operativo desde un archivo llamado mykernel.bin y ejecutarlo. A continuación, estamos esperando una parte más interesante del trabajo: el desarrollo del kernel del sistema operativo en sí.

núcleo del sistema operativo

Queremos que el núcleo de nuestro sistema operativo realice muchas tareas importantes: mostrar un saludo, aceptar la entrada del usuario, determinar si la entrada es un comando compatible y ejecutar programas desde el disco después de que el usuario especifique sus nombres. Este es el código del núcleo del sistema operativo del archivo mykernel.asm:

Mov ax, 2000h mov ds, ax mov es, ax loop: mov si, prompt call lib_print_string mov si, user_input call lib_input_string cmp byte, 0 je loop cmp word, "ls" je list_files mov ax, si mov cx, 32768 call lib_load_file jc load_fail call 32768 jmp loop load_fail: mov si, load_fail_msg call lib_print_string jmp loop list_files: mov si, file_list call lib_get_file_list call lib_print_string jmp loop prompt db 13, 10, "MyOS > ", 0 load_fail_msg db 13, 10, "¡No encontrado! ", 0 entrada de usuario por 256 db 0 lista de archivos por 1024 db 0 % incluye "lib.asm"

Antes de mirar el código, preste atención a la última línea con la directiva para incluir el archivo de código fuente lib.asm, que también se encuentra en el archivo asmschool.zip de nuestro sitio web. Esta es una biblioteca de subrutinas útiles para trabajar con la pantalla, el teclado, las líneas y los discos que también puede usar; en este caso, incluimos este archivo de código fuente al final del archivo de código fuente principal del kernel del sistema operativo para poder para que este último sea lo más compacto y bonito posible. Consulte la sección "Rutinas de la biblioteca lib.asm" para obtener más información sobre todas las rutinas disponibles.

En las tres primeras líneas del código del kernel del sistema operativo, llenamos los registros de segmento con datos para señalar el segmento 2000 en el que se cargó el código binario. Esto es importante para garantizar que instrucciones como lodsb , que deben leer datos del segmento actual y no de ningún otro, funcionen correctamente. Después de eso, no realizaremos ninguna operación adicional en los segmentos; ¡Nuestro sistema operativo funcionará con 64 KB de RAM!

Más adelante en el código hay una etiqueta que corresponde al comienzo del bucle. En primer lugar, usamos una de las rutinas de la biblioteca lib.asm, a saber, lib_print_string, para imprimir el saludo. Los bytes 13 y 10 antes de la línea de saludo son caracteres de nueva línea, por lo que el saludo no se mostrará inmediatamente después de la salida de ningún programa, sino siempre en una nueva línea.

Después de eso, usamos otra rutina de la biblioteca lib.asm llamada lib_input_string , que toma los caracteres ingresados ​​por el usuario usando el teclado y los almacena en un búfer, cuyo puntero está en el registro SI. En nuestro caso, el búfer se declara hacia el final del código del kernel del sistema operativo de la siguiente manera:

Entrada de usuario veces 256 db 0

¡Esta declaración permite un búfer de 256 caracteres lleno de ceros, que debería ser lo suficientemente largo para contener comandos para un sistema operativo simple como el nuestro!

A continuación, realizamos la validación de entrada del usuario. Si el primer byte del búfer de entrada de usuario es nulo, entonces el usuario simplemente presionó la tecla Intro sin ingresar ningún comando; no olvide que todas las cadenas terminan con caracteres nulos. Entonces, en este caso, deberíamos saltar al comienzo del ciclo e imprimir el saludo nuevamente. Sin embargo, si el usuario ingresa algún comando, primero tendremos que verificar si ingresó el comando ls. Hasta ahora, solo ha visto comparaciones de bytes individuales en nuestros programas de lenguaje ensamblador, pero no olvide que también es posible comparar valores de dos bytes o palabras de máquina. En este código, comparamos la primera palabra de máquina del búfer de entrada de usuario con la palabra de máquina correspondiente a la línea ls, y si son idénticas, pasamos al bloque de código a continuación. Dentro de este bloque de código, usamos otra rutina de la biblioteca lib.asm para obtener una lista de archivos separados por comas en el disco (que debe almacenarse en el búfer file_list), imprimir esa lista en la pantalla y volver al proceso entrada del usuario.

Ejecución de programas de terceros

Si el usuario no ingresa el comando ls, asumimos que ingresó el nombre del programa desde el disco, por lo que tiene sentido intentar cargarlo. Nuestra biblioteca lib.asm contiene una implementación de una subrutina útil lib_load_file , que analiza las tablas del sistema de archivos FAT12 de un disco: toma un puntero al comienzo de una línea con un nombre de archivo usando el registro AX, así como un valor de compensación para cargar un código binario desde un archivo de programa utilizando el registro CX. Ya estamos usando el registro SI para almacenar un puntero a la cadena de entrada del usuario, así que copiamos ese puntero al registro AX y luego ponemos el valor 32768, que se usa como compensación para cargar el código binario desde el archivo del programa, en el registro CX.

Pero, ¿por qué usamos este valor como compensación para cargar código binario desde un archivo de programa? Pues es solo una de las opciones de mapa de memoria de nuestro sistema operativo. Debido a que estamos trabajando en un solo segmento de 64 KB y nuestro kernel binario se carga en el desplazamiento 0, tenemos que usar los primeros 32 KB de memoria para los datos del kernel y los 32 KB restantes para los datos del programa cargable. Por lo tanto, el desplazamiento 32768 es el medio de nuestro segmento y nos permite proporcionar una cantidad suficiente de RAM tanto para el kernel del sistema operativo como para los programas cargados.

Después de eso, la rutina lib_load_file realiza una operación muy importante: si no puede encontrar un archivo con el nombre dado en el disco, o por alguna razón no puede leerlo desde el disco, simplemente sale y establece una bandera de acarreo especial. Este es un indicador de estado de la CPU que se establece durante algunas operaciones matemáticas y no debería ser de nuestro interés en este momento, pero podemos determinar la presencia de este indicador para tomar decisiones rápidas. Si la subrutina lib_load_asm establece la bandera de acarreo, usamos la instrucción jc (saltar si acarrea) para saltar al bloque de código que imprime el mensaje de error y regresa al inicio del ciclo de entrada del usuario.

En el mismo caso, si el indicador de transferencia no está configurado, podemos concluir que la subrutina lib_load_asm cargó con éxito el código binario del archivo de programa en la RAM en la dirección 32768. Todo lo que necesitamos en este caso es iniciar la ejecución del código binario. cargado en esta dirección, es decir, ¡comienza a ejecutar el programa especificado por el usuario! Y después de usar la instrucción ret en este programa (para volver al código de llamada), solo tendremos que volver al ciclo de entrada del usuario. Por lo tanto, hemos creado un sistema operativo: consta de los mecanismos más simples para analizar comandos y cargar programas, implementado dentro de unas 40 líneas de código ensamblador, aunque con mucha ayuda de las subrutinas de la biblioteca lib.asm.

Para ensamblar el código del kernel del sistema operativo, use el siguiente comando:

Nasm -f bin -o mikernel.bin mikernel.asm

Después de eso, tendremos que agregar de alguna manera el archivo mykernel.bin al archivo de imagen del disquete. Si está familiarizado con el truco de montar imágenes de disco con dispositivos de bucle invertido, puede acceder al contenido de la imagen de disco floppy.img utilizándola, pero hay una forma más sencilla utilizando GNU Mtools (www.gnu.org/software/mtools ). Este es un conjunto de programas de disquetes que usan sistemas de archivos MS-DOS/FAT12, disponibles en los repositorios de paquetes de software de todas las distribuciones populares de Linux, por lo que solo necesita usar apt-get , yum , pacman o cualquier otra utilidad que solía instalar paquetes de software en su distribución.

Después de instalar el paquete de software adecuado, para agregar el archivo mykernel.bin al archivo de imagen de disco floppy.img, deberá ejecutar el siguiente comando:

Mcopy -i disquete.img mikernel.bin::/

Observe los caracteres divertidos al final del comando: dos puntos, dos puntos y barra oblicua. Ahora estamos casi listos para lanzar nuestro sistema operativo, pero ¿de qué sirve hasta que haya aplicaciones para él? Corrijamos este malentendido desarrollando una aplicación extremadamente simple. Sí, ahora desarrollará una aplicación para su propio sistema operativo; imagínese cuánto aumentará su autoridad en las filas de los geeks. Guarde el siguiente código en un archivo llamado test.asm:

Org 32768 mov ah, 0Eh mov al, "X" int 10h ret

Este código simplemente usa la función BIOS para mostrar el carácter "X" en la pantalla, luego de lo cual devuelve el control al código que lo llamó; en nuestro caso, este código es el código del sistema operativo. La línea de organización que inicia el código fuente de la aplicación no es una instrucción de la CPU, sino una directiva del ensamblador NASM que le indica que el código binario se cargará en la RAM en el desplazamiento 32768, por lo tanto, es necesario volver a calcular todos los desplazamientos teniendo en cuenta esta circunstancia. .

Este código también debe ensamblarse y el archivo binario resultante debe agregarse al archivo de imagen del disquete:

Nasm -f bin -o prueba.bin prueba.asm mcopy -i floppy.img prueba.bin::/

Ahora, respire hondo, prepárese para presenciar los resultados insuperables de su propio trabajo y arranque la imagen del disquete con un emulador de PC como Qemu o VirtualBox. Por ejemplo, el siguiente comando se puede utilizar para este propósito:

Qemu-system-i386 -fda disquete.img

Listo: el cargador de arranque boot.img que integramos en el primer sector de la imagen del disco carga el kernel del sistema operativo mykernel.bin, que muestra un saludo. Escriba el comando ls para obtener los nombres de los dos archivos en el disco (mykernel.bin y test.bin), luego escriba el nombre del último archivo para ejecutar y mostrar el carácter X en la pantalla.

Es genial, ¿no? Ahora puede comenzar a personalizar el shell de su sistema operativo, agregar implementaciones de nuevos comandos y agregar archivos de programa adicionales al disco. Si desea ejecutar este sistema operativo en una PC real, debe consultar la sección "Ejecutar el cargador de arranque en una plataforma de hardware real" del artículo anterior de la serie; necesitará exactamente los mismos comandos. El próximo mes haremos que nuestro sistema operativo sea más poderoso al permitir que los programas descargables usen las funciones del sistema, implementando así el concepto de separación de código para reducir la duplicación de código. Gran parte del trabajo aún está por delante.

rutinas de la biblioteca lib.asm

Como se mencionó anteriormente, la biblioteca lib.asm proporciona un gran conjunto de subrutinas útiles para usar dentro de los núcleos de su sistema operativo y programas individuales. Algunos de ellos utilizan instrucciones y conceptos que aún no se han tratado en los artículos de esta serie, otros (como las rutinas para trabajar con discos) están estrechamente relacionados con la estructura de los sistemas de archivos, pero si te consideras competente en estos temas, puede familiarizarse con sus implementaciones y comprender el principio de trabajo. Sin embargo, es más importante entender cómo llamarlos desde su propio código:

  • lib_print_string: lleva un puntero a una cadena terminada en nulo a través del registro SI e imprime esa cadena en la pantalla.
  • lib_input_string: lleva un puntero a un búfer a través del registro SI y llena este búfer con caracteres ingresados ​​por el usuario usando el teclado. Después de que el usuario presiona la tecla Intro, la cadena en el búfer termina en nulo y el control vuelve al código del programa de llamada.
  • lib_move_cursor: mueve el cursor en la pantalla a la posición con las coordenadas pasadas a través de los registros DH (número de fila) y DL (número de columna).
  • lib_get_cursor_pos: llame a esta subrutina para obtener los números de fila y columna actuales utilizando los registros DH y DL, respectivamente.
  • lib_string_uppercase: lleva un puntero al comienzo de una cadena terminada en nulo mediante el registro AX y convierte los caracteres de la cadena a mayúsculas.
  • lib_string_length: toma un puntero al comienzo de una cadena terminada en nulo usando el registro AX y devuelve su longitud usando el registro AX.
  • lib_string_compare: toma punteros al comienzo de dos cadenas terminadas en nulo a través de los registros SI y DI y compara esas cadenas. Establece la bandera de acarreo si las cadenas son idénticas (para usar una instrucción de salto dependiendo de la bandera de acarreo jc) o borra esta bandera si las cadenas son diferentes (para usar la instrucción jnc).
  • lib_get_file_list: lleva un puntero al inicio de un búfer a través del registro SI y coloca una cadena terminada en nulo que contiene una lista de nombres de archivos del disco separados por comas en ese búfer.
  • lib_load_file: toma un puntero al comienzo de una cadena que contiene un nombre de archivo mediante el registro AX y carga el contenido del archivo en el desplazamiento proporcionado por el registro CX. Devuelve el número de bytes copiados en la memoria (es decir, el tamaño del archivo) usando el registro BX, o establece la bandera de acarreo si no se encuentra ningún archivo con el nombre dado.

Hoy, en nuestra Kunstkamera, un ejemplo curioso es un sistema operativo escrito en puro ensamblador. Junto con los controladores, un shell gráfico, docenas de programas y juegos preinstalados, ocupa menos de un megabyte y medio. Conozca el excepcionalmente rápido y predominantemente ruso OS Hummingbird.

El desarrollo de Hummingbird fue bastante rápido hasta 2009. El pájaro aprendió a volar en hardware diferente, requiriendo el mínimo del primer Pentium y ocho megabytes de RAM. Los requisitos mínimos del sistema para Hummingbird son:

  • CPU: Pentium, AMD 5x86 o Cyrix 5x86 sin MMX a 100 MHz;
  • RAM: 8 MB;
  • Tarjeta gráfica: compatible con VESA con soporte para modo VGA (640 × 480 × 16).

El Hummingbird moderno es una "construcción nocturna" actualizada periódicamente de la última versión oficial, lanzada a finales de 2009. Probamos la compilación 0.7.7.0+ con fecha del 20 de agosto de 2017.

ADVERTENCIA

En la configuración predeterminada, KolibriOS no tiene acceso a los discos visibles a través del BIOS. Piense con cuidado y haga una copia de seguridad antes de cambiar esta configuración.

Aunque los cambios en las compilaciones nocturnas son pequeños, se han acumulado lo suficiente a lo largo de los años. El Hummingbird actualizado puede escribir en particiones FAT16-32 / ext2 - ext4 y es compatible con otros sistemas de archivos populares (NTFS, XFS, ISO-9660) en modo de lectura. Agregó soporte para USB y tarjetas de red, se agregó una pila TCP/IP y códecs de sonido. En general, ya puede hacer algo en él, y no solo mirar una vez un sistema operativo ultraligero con una GUI y quedar impresionado por la velocidad de inicio.



Al igual que las versiones anteriores, la última versión de Hummingbird está escrita en ensamblador plano (FASM) y ocupa un disquete de 1,44 MB. Gracias a esto, se puede colocar completamente en alguna memoria especializada. Por ejemplo, los artesanos escribieron KolibriOS directamente en Flash BIOS. Durante el funcionamiento, puede ubicarse por completo en la memoria caché de algunos procesadores. Imagínese: ¡todo el sistema operativo, junto con los programas y controladores, se almacena en caché!

INFORMACIÓN

Al visitar el sitio kolibrios.org, el navegador puede advertir de peligro. La razón, aparentemente, son los programas ensambladores en la distribución. Ahora VirusTotal define el sitio como completamente seguro.

"Hummingbird" se carga fácilmente desde un disquete, disco duro, unidad flash, Live CD o en una máquina virtual. Para la emulación, es suficiente especificar el tipo de sistema operativo "otro", asignarle un núcleo de procesador y algo de RAM. No es necesario conectar un disco, y si hay un enrutador con DHCP, Hummingbird se conectará instantáneamente a Internet y la red local. Inmediatamente después de la descarga, verá una notificación.


Un problema: el navegador integrado Hummingbird no admite el protocolo HTTPS. Por lo tanto, no fue posible mirar el sitio en él, así como abrir las páginas de Google, Yandex, Wikipedia, Sberbank ... de hecho, no hay una dirección habitual. Todos cambiaron a un protocolo seguro hace mucho tiempo. El único sitio con HTTP puro de la vieja escuela que encontré fue el "portal del Gobierno de Rusia", pero no se veía mejor en un navegador de texto.



La configuración de apariencia en Hummingbird ha mejorado a lo largo de los años, pero todavía está lejos de ser ideal. Se muestra una lista de los modos de video admitidos en la pantalla de inicio de Hummingbird cuando presiona la tecla de la letra a.



La lista de opciones disponibles es pequeña y es posible que la resolución deseada no se encuentre en ella. Si tiene una tarjeta gráfica con una GPU AMD (ATI), puede agregar configuraciones personalizadas de inmediato. Para hacer esto, debe pasar el parámetro -m al cargador de arranque ATIKMS X X , por ejemplo:

/RD/1/CONDUCTORES/ATIKMS -m1280x800x60 -1

Aquí /RD/1/DRIVERS/ATIKMS es la ruta al gestor de arranque (RD - Disco RAM).

Cuando el sistema está funcionando, el modo de video seleccionado se puede ver con el comando vmode y (teóricamente) cambiarse manualmente. Si Hummingbird se está ejecutando en una máquina virtual, esta ventana permanecerá vacía, pero con un inicio limpio, los controladores de video Intel se pueden agregar desde i915 a Skylake inclusive.

Sorprendentemente, un montón de juegos caben en KolibriOS. Entre ellos hay juegos lógicos y arcade, etiquetas, una serpiente, tanques (no, no WoT), ¡todo un "Game Center"! Incluso Doom y Quake fueron portados a Hummingbird.



Otra cosa importante fue el lector FB2READ. Funciona correctamente con cirílico y tiene configuraciones de visualización de texto.



Recomiendo almacenar todos los archivos de usuario en una unidad flash USB, pero debe conectarse a través de un puerto USB 2.0. Nuestra unidad flash USB 3.0 (en un puerto USB 2.0) con una capacidad de 16 GB con el sistema de archivos NTFS se determinó de inmediato. Si necesita escribir archivos, debe conectar una unidad flash USB con una partición FAT32.



La distribución de Hummingbird incluye tres administradores de archivos, utilidades para ver imágenes y documentos, reproductores de audio y video y otras aplicaciones de usuario. Sin embargo, la atención se centra en el desarrollo del lenguaje ensamblador.



El editor de texto incorporado tiene resaltado de sintaxis ASM e incluso le permite ejecutar inmediatamente programas escritos.



Entre las herramientas de desarrollo se encuentra el compilador Oberon-07/11 para i386 Windows, Linux y KolibriOS, así como emuladores de bajo nivel: E80 - emulador ZX Spectrum, FCE Ultra - uno de los mejores emuladores de NES, DOSBox v.0.74 y otros. Todos ellos fueron adaptados especialmente al Hummingbird.

Si deja KolibriOS durante unos minutos, se iniciará el protector de pantalla. Se ejecutarán líneas de código en la pantalla, en las que puede ver una referencia a MenuetOS.

Continúa disponible solo para miembros

Opción 1. Únase a la comunidad del "sitio" para leer todos los materiales en el sitio

¡La membresía en la comunidad durante el período especificado le dará acceso a TODOS los materiales de Hacker, aumentará su descuento acumulativo personal y le permitirá acumular una calificación profesional de Xakep Score!

 
Artículos en tema:
Crear imágenes vectoriales ”en el editor de gráficos vectoriales Libre Office Draw Hacemos una flecha a partir de una línea
HERRAMIENTAS DE LOS SISTEMAS DE INFORMACIÓN TECNOLOGÍAS BÁSICAS DE LA INFORMACIÓN. PRESENTACIONES Directrices para el trabajo de laboratorio Bryansk 2018 PROPÓSITO DEL TRABAJO Aprender a construir diagramas utilizando bibliotecas de elementos para el diseño.
Los mejores editores de PDF para Linux
El formato PDF se ha vuelto muy popular con el desarrollo de Internet y la difusión de la documentación electrónica, y quienes se ocupan de textos tienen que seleccionar las herramientas para abrir archivos en este formato y trabajar con ellos. Los seguidores de *nix tienen algo que ofrecer
Kali Linux: una descripción detallada de la distribución
Hackear con Kali Linux ¿Por qué Kali Linux? Con Kali Linux, la piratería se vuelve mucho más fácil ya que tiene todas las herramientas (más de 300 utilidades preinstaladas) que pueda necesitar. Además, puede descargar fácilmente más
Uso de KVM para crear máquinas virtuales en un servidor Kvm Descripción
En Cloud4Y, consideramos que los productos VmWare son la solución de virtualización líder. Sin embargo, también estamos interesados ​​en otras soluciones, incluidas Xen y KVM. Y esto es lo que notamos: no hay mucha información para comparar estos hipervisores: después