Kamis, 29 Desember 2016

Masih Ragu Pakai Linux? Kurang Apa? Aplikasi Ini Buat Kamu Mantap Pakai Linux

Saya tidak heran, kenapa banyak orang masih ragu pakai Linux. Apalagi mereka yang setiap hari dibebani tugas kantor; mengetik laporan, desain iklan, dan sebagainya. Ya, saya akui, aplikasi Linux memang belum begitu lengkap dan bagus jika dibandingkan dengan empunya Wid*ws dan M*c. But, If you know these, you'll love it. :D

Meski dalam aplikasi, linux masih kalah; setidaknya Linux unggul dalam banyak hal:
- Free. udah gitu open source lagi. Insya Allah, jauh dari software bajakan. Ingat dosa, dong.
- Customizable. Jangan kawatir, jika kamu tidak suka tampilan linux, baik dari segi ikon, tema ataupun sembarangnya. Linux selalu menjawab kekurangan ini untuk kamu. Iya, kamu. Ada banyak icon pack dan tema lingkungan desktop yang bisa kamu pilih dan install. Bukan sampai disitu, kamu juga bisa mengganti windows manager sampai dengan desktop environment.



Aman. Tidak heran lagi, di linux semua virus gak bakalan mempan. Seumur-umur pakai linux, saya belum pernah lho sekalipun terserang virus. Bahkan, saya berani membuka virus di Windows dengan tangan dan mouse saya sendiri. -- Sambil melet, dan bilang 'week.. gak mempan'.
- Mudah di atur dan gak suka main di belakang. Saya jamin, Linux tidak akan pernah mencuri data pribadi anda, memaksa update dan menjalankan program yang tidak anda butuhkan. Jika memang ada, kita bisa mengaturnya dengan mudah, dan linux tak akan melakukannya kembali.

Jika masih belum yakin, ini aplikasi yang bakal merubah jalan pikiran agan.
1. Wine
Jika sulit move on, jalankan aplikasi Windows kesayanganmu dengan Wine. Aplikasinya tidak akan terlihat seperti jalan di emulator. Bahkan tampilannya mirip seperti berjalan di Windows. Winde menggunakan teknologi virtualisasi, jadi jangan takut aplikasinya lambat. Wine bukan cuma sekedar emulator gan.

2. Shashlik
Jika susah mengejanya cukup ingat ingat shampoo Sunsilk gan. hehe. Hampir seperti Wine. Shashlik adalah program untuk mengemulasikan program Android. Program android yang anda jalankan akan terlihat seperti program biasa bagi Linux.

3. Emulator untuk berbagai macam device dan aplikasi.
Jika aplikasi dari 2 raja aplikasi (Windows dan Android), masih belum cukup, aplikasi emulator di Linux bisa anda gunakan. Misalnya QEMU, untuk emulasi sistem operasi yang biasanya berjalan pada prosesor x86, ARM, MIPS, SPARC, ...; FCEUX untuk menjalankan game nintendo; DESMUME, untuk menjalankan game nintendo DS; Dan masih banyak lagi, hampir semua jenis game dari platform lain bisa dijalankan di Linux. Apa di Windows tidak ada? Ada, tapi coba survei di situsnya. Sebagian besar, awalnya dikembangkan untuk Linux saja, lho.

Ada banyaaaak lagi aplikasi yang masih bisa kamu jalankan di Linux.  Penasaran kan seperti apa kerennya? Yuk, migrasi ke Linux.
NB :
- Jika masih ragu, dual boot Windows dan Linux adalah pilihan yang tepat.
- Saya rekomendasikan pengguna baru untuk install Linux Ubuntu atau OpenSuSE.

Read more

Rabu, 28 Desember 2016

Memahami Istilah Abstraction Layer dengan Analogi Sederhana

Abstraction layer?  Saya mengartikan abstraction layer sebagai lapisan-lapisan antar muka yang berguna menyembunyikan kerumitan dalam beragamnya perbedaan dan mengambil beberapa persamaan dalam berbagai macam perbedaan.

Misalnya: Jalan-jalan.  Kata jalan-jalan terdengar implisit. Kemanapun arahnya, itulah yang namanya jalan-jalan. Setelah yakin memutuskan untuk pergi, ada beberap opsi yang bisa dipilih, jalan-jalan ke jakarta, jalan jalan ke surabaya, jalan-jalan ke semarang, ataupun ke kota lainnya. Jika kita sudah memilih jalan-jalan ke Surabaya, misalnya; kita selanjutnya memilih opsi transportasi. Misalnya dengan sepeda atau dengan kereta.

Ungkapan di atas adalah sebuah analogi sederhana untuk abstraction layer. Contoh abstraction layer yang sering kita temui adalah dalam manajemen file. Di antara beragam jenis file, filesystem dan media penyimpanan yang digunakan; kita dapat menyalin data melalui file manager dengan cara yang sama; meskipun sumber dan tujuan data memiliki properti yang berbeda. Ini berkat abstraction layer.
file abstraction layer

Ilustrasi di atas menunjukkan bagaimana proses akses file bekerja dengan alur kerja yang berbeda. Pertaama, Proses baca file melalui layer filesystem. Bisa diibaratkan FAT dan NTFS adalah  objek yang sama-sama merupakan turunan class filesystem. Semua filesystem memiliki method bacaFile(), namun tiap filesystem memiliki implementasinya sendiri-sendiri.

Dibawahnya lagi, layer filesystem harus berkomunikasi dengan layer disk I/O. Baik floppy ataupun CD adalah turunan class disk yang memiliki method bacaData() dengan implementasinya sendiri-sendiri pula.
Read more

Minggu, 25 Desember 2016

Belajar Assembly MIPS / PIC32 Dengan MARS Simulator

Prosesor MIPS adalah pioner dari arsitektur prosesor RISC. Ia pernah berjaya di era 90-an di mana industri prosesor sedang gencar-gencarnya melakukan riset. Akan tetapi sekarang ini seperti mulai turun pamornya. Meski demikian MIPS memiliki kelebihan tersendiri, terutama dalam hal kesederhanaannya. Beberapa referensi juga mengatakan bahwa harga jual MIPS di pasaran relatif terjangkau. Tidak hern, di luar sana, MIPS banyak digunakan sebagai bahan riset dan penelitian akademisi dan peneliti. Untuk itu saya mulai tertarik dengan arsitektur prosesor ini.

Kenampakan prosesor MIPS
Grafik market share prosesor

Arsitektur MIPS juga diproduksi oleh industri semikonduktor lain, misalnya Microchip dengan PIC32 nya. Jadi, jika kalian mencoba development board PIC32, misalnya; kalian akan merasakan sensasi yang sama dengan menulis program untuk MIPS. Hal ini sama halnya dengan AMD yang membeli lisensi Intel untuk memproduksi varian prosesor dengan arsitektur serupa Intel. Cukup di sini basa-basinya. Langsung saja kita mulai bahasannya.

Untuk belajar assembly MIPS, saya sarankan menggunakan simulator MARS. Ini lebih baik dari pada praktik langsung dengan komputer asli berinti MIPS. Dengan simulator, kita bisa lebih mudah melacak dan melihat bagaimana nilai tiap register berubah seiring dengan berjalannya instruksi.

mips mars simulator
Download : http://courses.missouristate.edu/KenVollmar/mars/download.htm

Register
Arsitektur RISC umumnya lebih banyak beroperasi dengan register. Oleh karena itu, arsitektur MIPS dibilang arsitektur register-to-register. Jumlah registernya lebih banyak dari arsitektur CISC, namun memiliki jumlah instruksi yang terbatas. Jika dibandingkan dengan Intel, maka akan terlihat perbandingan yang jauh.


Conventional NameUsage
$0$zeroHard-wired to 0. Apapun yang kita baca dari sini akan selalu 0.
$1$atReserved for pseudo-instructions
$2 - $3$v0, $v1Return values from functions. Digunakan sebagai alamat return dalam pemanggilan fungsi/prosedur.
$4 - $7$a0 - $a3Arguments to functions - not preserved by subprograms. Menyimpan argumen fungsi.
$8 - $15$t0 - $t7Temporary data, not preserved by subprograms. Bisa digunakan dengan bebas, untuk keperluan apapun.
$16 - $23$s0 - $s7Saved registers, preserved by subprograms. Bisa digunakan bebas juga, namun setelah digunakan oleh sebuah fungsi, fungsi tersebut harus mengembalikan nilai register ke nilai semula. Kenapa demikian? anda akan tahu nanti.
$24 - $25$t8 - $t9More temporary registers, not preserved by subprograms. Bebas digunakan juga.
$26 - $27$k0 - $k1Reserved for kernel. Do not use. Hanya sistem operasi yang boleh menangani dan menggunakan nilai ini. Sementara, kita abaikan register ini.
$28$gpGlobal Area Pointer (base of global data segment). Untuk menunjuk alamat data area.
$29$spStack Pointer. Untuk menunjuk memori stack.
$30$fpFrame Pointer. Biasanya dimanfaatkan untuk menyimpan nilai $sp saat penanganan fungsi.
Sumber: http://www.cs.uwm.edu/classes/cs315/Bacon/Lecture/HTML/ch05s03.html
Selain register di atas, ada pula register hi dan lo yang berperan dalam operasi perkalian dan pembagian. Semuanya itu adalah register dasar yang harus diketahui. Setelah mengetahui ini, nanti kita akan membahas register coprocessor.






Instruksi
Syntax
INSTRUKSI [operand1], [operand2], [operand3]
Sebuah instruksi dapat ditulis tanpa operand, atau dengan operand hingga maksimal 3 operand. Operand dapat berupa register, nilai konstan (immediate), atau label yang merepresentasikan alamat suatu data.

label:
#komentar
Label diindikasikan dengan titik dua yang mengikuti nama label. Dan, komentar ditulis dengan prefix #.

.word
.set ...
Direktif adalah kode yang menginstruksikan assembler untuk melakukan sesuatu, diawali dengan simbol titik sebelum kode direktif. Untuk melihat dftar direktif, lihat menu Help di MARS.

Format
Sama seperti arsitektur RISC lain, MIPS menyederhanakan eksekusi dengan membatasi ukuran tiap instruksi. Seluruh instruksi di MIPS akan selalui berukuran 32 bit (4 byte). Setiap instruksi akan dijalankan dalan waktu yang sama, yaitu satu siklus waktu CPU. Berbeda dengan arsitektur CISC yang memiliki panjang instruksi dan waktu eksekusi berbeda-beda tiap instruksinya.





Gambar di atas menunjukkan beberapa macam varian format instruksi MIPS. Varian pertama (R) digunakan pada instruksi untuk memproses data dari 3 parameter register. Misalnya instruksi ADDU, SUBU, OR, AND.

addu $t0, $t1, $t2

# ADDU rd,rs, rt
# $t0 = $t1 + $t2)

Opcode (op) ADDU adalah 100001b. Sesuai tabel register di atas, register $t0 bernomor 8 (01000b) berperan sebagai rd, register $t1 bernomor 9(01001b) berperan sebagai rs, dan register $t2 bernomor 9 (01010b) berperan sebagai rt. Nilai shamt 0, nilai ini hanya digunakan untuk instruksi bit shift. Terakhir, instruksi ADDU memiliki nilai variant funct 100001. Dari penjabaran ini, maka diperoleh hasil decode instruksi:
100001 01000 10111 01010 00000 100001

Varian berikutnya adalah varian untuk mengolah data dari register dan nilai immediate (I). Immediate adalah sebutan untuk nilai konstan yang diberikan secara langsung untuk diproses oleh instruksi. Contoh instruksi immediate adalah LUI, ADDI, SUBI, SUBIU, ORI, ANDI.

subiu $t0,$t1,100
# SUBIU rd, rs, immediate
# $t0 = $t1 + 100

Meski MIPS memiliki varian prosesor  berarsitektur 32-bit dan 64-bit, instruksinya terbatas untuk meload instruksi immediate. Dalam instruksi yang mengolah nilai immediate, nilai maksimum yang diperbolehkan hanyalah sebesar 16-bit (0 - 65535). Oleh karena itu, saat ingin meload nilai immediate 32-bit, kita perlu menggunakain instruksi LUI (Load Upper Immediate).

#load nilai 0x00A12B78
lui $t1, 0x00A1
addi $t1, $t1, 0x2B78
# $t1 = 0x00A10000 + 0x00002B78

Terakhir, varian J digunakan untuk instruksi jump dan branching. Target address yang digunakan bersifat relatif terhadap posisi instruksi tersebut. Karena bernilai 26 bit, maka instruksi ini dapat melompat ke instruksi yang jauhnya 33.554.430 byte ke kiri atau ke kanan. Contoh instruksi dalam kelompok ini adalah J, B dan JAL.
label:
...
j label
# J label

Referensi :
- https://en.wikibooks.org/wiki/MIPS_Assembly/Instruction_Formats#I_Format
- http://alumni.cs.ucr.edu/~vladimir/cs161/mips.html

Pseudo instruction
Karena keterbatasan instruksi MIPS, beberapa instruksi harus ditulis untuk melakukan satu tahap pekerjaan yang terbilang sederhana, sehingga cenderung terlihat kompleks. Oleh karena itu, MIPS dan prosesor RISC lainnya menyediakan dukungan pseudo instruction pada assemblernya. Beberapa contoh pseudo-instruction antara lain:

Branch if less than (blt)
The blt instruction compares 2 registers, treating them as signed integers, and takes a branch if one register is less than another.
blt $8, $9, label

diterjemahkan menjadi:
slt $1, $8, $9
bne $1, $0, label


Load Immediate (li)
The li pseudo instruction loads an immediate value into a register.
li $8, 0x3BF20

diterjemahkan menjadi:
lui $8, 0x0003
ori $8, $8, 0xBF20


Move (move)
The move pseudo instruction moves the contents of one register into another register.
move $1, $2

diterjemahkan menjadi:
add $1, $2, $0

Load Address (la)
la $a0,address

diterjemahkan menjadi:
lui $at, %hi(address)
ori $a0,$at,%lo(address)

Ayo Belajar
Tips : aktifkan pseudo instruction melalui settings simulator MARS. Untuk melihat daftar instruksi lihat menu Help.

Operasi matematika dasar (pi-po-lon-do) --IYKWIM
Misalnya kita inin menambahkan nilai 100 + 100 instruksinya seperti ini
li $t0, 100
addiu $t0, $t0, 100


Selain ADDIU, ada juga ADDU, ADDI dan ADD. Apa bedanya?
Pada dasarnya semuanya berguna untuk menambah nilai hnya saja terdapat perbedaan behavior pada implementasinya. instruksi yang memiliki mnemonic tambahan U, seperti ADDIU (Add immediate without overflow), akan mengabaikan adanya overflow. Saya belum tahu pada prakteknya seperti apa. Menurut dokumentasi, ketika terjadi overflow akan memicu prosesor untuk menghasilkan exception. Nah, pertanyaannya, apakah sistem operasi akan menangani exception ini, ataukan mengakhiri program yang menghasilkan exception?

Perkalian dan pembagian sedikit berbeda dengan instruksi matematika biasa. Jika menggunakan instruksi pseudo, perkalian cukup sederhana:

mul $t0, $t1, $t2
# $t0 = $t1 x $t2

Sebenarnya, jika diterjemahkan, instruksi perkalian dan pembagian akan melibatkan register hi dan lo. Instruksi non-pseudo berikut akan mengalikan $t0 dan $t1. Lalu, dimanakah hasilnya?
mult $t0,$t1

Hasilnya disimpan pada register lo. Apabila hasil perkalian menghasilkan lebih dari batasan nilai 32 bit, sejumlah 32 bit tertinggi akan disimpan pada register hi. Untuk mengakses kedua register ini kita bisa menggunakan instruksi mfhi, mflo, mthi, mtlo (move from hi, move from lo, move to hi, move to lo).

Untuk instruksi pembagian, perlakukan register hi dan lo sedikit berbeda. Hasil pembagian akan disimpan pada register lo, dan apabila pembagian bersisa, sisa tersebut berada pada register hi.
li $t0,1000
li $t0,10
div $t0,$t1
#simpan hasil ke $t3
mflo $t3
#simpan sisa ke $t4
mfhi $t4



Macam Data dan Cara Mengaksesnya
MIPS mengenal 3 macam data: byte (8 bit), halfword(16 bit) dan word (32 bit). Ingat, MIPS berarsitektur register-to-register, jadi kita tidak bisa langsung mengoperasikan data tersebut, ya. Nilai data tersebut pertama-tama harus diload ke register. Ada beberapa instruksi yang berguna untuk meload dan menyimpan (store) data:
LB (Load Byte)
LH (Load Halw-word)
LW (Load Word)
SB (Store Byte)
SH (Store Half-word)
SW (Store Word)

Untuk mendeklarasikan data, gunakan direktif .byte, .half, atau .word; dengan diawali label sebagai nama data tersebut. Perlu diketahui juga, penempatan instruksi dan data harus terpisah. Dari MARS, tersedia direktif .text sebagai indikasi awal instruksi dan .data sebagai indikasi awal bagian menampung data.

.text
    #load nilai dataA ke $t0, tambah dengan 100
    #hasilnya simpan ke dataB
    lw $t0,dataA
    addiu $t0,$t0,100
    sw $t0,dataB

.data
    dataA:
    .word 100

    dataB:
    .word 0


Jump dan Branch
Instruksi dasar lainnya yang akan dibahas adalah mengenai jump dan branch. Tujuan instruksi ini adalah untuk melompat ke segmen instruksi tertentu. Ada 2 macam instruksi yang perlu diketahui.

Uncoditional jump/branch
Unconditional jump/branch dilakukan secara langsung untuk melompat ke suatu instruksi. Instruksi semacam ini misalnya J, B, JAL, JALR.
main:
    j exit:
    ...

exit:
    ...
 
Conditional branch
Conditional jump adalah instruksi yang bekerja ketika suatu kondisi ditemukan benar. Misalnya BEQ (Branch if Equal), BGEZ (Branch if Greater or Equal to Zero), dll. Selengkapnya lihat menu Help,ya.
main:
    li $t0,1
    li $t1,2
    #lompat ke label 'sama', jika $t0 == $t1
    beq $t0,$t1,sama
beda:
    ...
sama:
    ...


Ternyata instruksi MIPS tidak kalah kerennya dengan instruksi Intel, ya. Yang membuat lebih keren, MIPS tergolong arsitektur RISC, jadi jumlah instruksinya sedikit. Meski jumlah registernya lebih banyak dari CISC, semua registernya mudah diingat, tak masalah.

Mungkin sampai disini dulu belajarnya, nanti disambung lain waktu. Terima kasih sudah membaca. See youu later...

Read more

Episode Membuat Sistem Operasi: Mengistall Bootloader Hingga Mencetak Hello World (C dan Assembly + Video)

 

Tulisan ini tidak akan membahas banyak hal, dan tidak pula menjelaskan setiap poinnya dengan panjang lebar. Namun, agar terlihat menarik, saya sengaja menggunakan judul sepanjang itu. hehehe

Tutorial ini dapat diikuti dengan 2 cara; lihat video berikut dahulu, atau baca penjelasan yang diberikan di bawah, sebelum melihat video. #gak_penting


Persiapan
Pertama-tama, kita siapkan virtual disk dan memformatnya dengan filesystem FAT.

#dd if=/dev/zero of=disk.img bs=512 count=20000
#mkdosfs disk.img

Device /dev/zero adalah device yang akan selalu mengembalikan data 0 ketika dibaca. Kita menggunakan argumen input file (if) berupa device ini agar, virtual disk yang baru berisi data yang benar-benar kosong. Lalu output file (of) akan saya namakan sebagai disk.img. Besar virtual disk yang saya inginkan adalah 20000 sektor, yang tiap sektornya terdapat 512 byte. Kedua parameter ini di atur dengan block size (bs) dan count.

Perintah mkdosfs selanjutnya berguna untuk memformat virtual disk dengan filesystem FAT.

Instalasi GRUB 2
Alasan saya memilih GRUB, karena menurut saya GRUB adalah yang terbaik di antara bootloader lain. Bootloader lain umumnya hanya fokus pada dukungan sistem operasi linux, tidak untuk hobyist OS developer seperti kita. Meski begitu, GRUB 2 belum didukung platform Windows, jadi tutorial ini dikhususkan bagi anda yang memahami Linux. Jangan patah semangat, kalau memang tertarik dengan pengembangan OS, coba dual boot Windows + Ubuntu. [RECOMENDED]

losetup /dev/loopX disk.img
(Sekarang, mount  /dev/loopX di suatu tempat)
grub-install --force --root-directory=<lokasi_mount> /dev/nama_device

Pertama, kita harus memasang virtual disk yang baru dibuat ke loop device, yaitu dengan losetup. Gunakan format seperti diatas dengan mengubah X menjadi 0, 1, atau 2. Setelah dipasang, virtual disk akan bekerja sepeti block device nyata yang dapat diakses sebagai /dev/loopX.

Sekarang, mount loop device ke suatu tempat. Biar mudah, kita juga bisa mount lewat file manager langsung.

GRUB menyediakan grub-install sebagai program pembantu proses instalasi. Instalasi dapat dilakukan di block device manapun yang berproperti read write. Hampir semua filesystem didukung oleh GRUB, namun ada kalanya suatu hal membuat GRUB sulit bekerja pada filesystem tersebut. Oleh karena itu, tidak ada salahnya kita sedikit menyulitkan GRUB dengan --force. Hasilnya memang terlihat beberapa warning, tapi jangan kawatir, aman, kok. Tentukan lokasi mount dengan lokasi mount loop device. Lalu, apa nama device? tentu saja /dev/loopX..

Buat konfigurasi GRUB
 Metode loading kernel yang akan dilakukan adalah berdasarkan spesifikasi multiboot 2. Jadi kita perlu meload modul multiboot2, dari konfigurasi berikut.

set timeout=30
set default=0
menuentry 'Hello world' {
insmod multiboot2
multiboot2 /System/hello
}


Simpan pada device yang telah di mount sebagai /boot/grub/grub.cfg.

Buat project
Ada 3 macam file yang harus kita buat.
ldscript.txt
File ini berisi linker script, berguna untuk mengatur ulang section dari object files, sehingga sesuaii dengan keinginan kita.

ENTRY(multiboot_entry)
SECTIONS
{
  .text 0x1000000 :
  {
    text = .;
    /*header multiboot harus berada di awal section*/
    ./Release/multiboot2.s.o(*)
    *(.text)
  }
  .data :
  {
     data = .;
     *(.data)
     *(.rodata*)
  }
  .bss :
  {
    bss = .;
    *(.bss)
  }
  /DISCARD/ :
  {
    *(*)
  }
  end = .;
}  



Setiap mengompile file, dihasilkan sebuah object file. Dalam object file terbagi beberapa macam bagian (section), section umum yang akan selalu dihasilkan adalah .text (berisi instruksi komputer), .data (berisi data program) dan .bss (berisi data program yang memiliki nilai awal 0). Data yang berupa teks yang tidak pernah diubah selma program berjalan biasanya disimpan pada .rodata(read-only data).

int myvar = 0; --> .data

int myvar; sama seperti
int myvar = 0; --> .bss

Untuk melihat section pada objek, gunakan perintah berikut:

objdump -x namafileobjek.o

Program yang dihasilkan dengan linker script ini akan dieksekusi pada alamat memori 0x1000000. Prosedur yang dieksekusi pertama adalah multiboot_entry().

multiboot.s
.intel_syntax noprefix
.extern KMain
.global multiboot_entry

.text
    .align 8
    multiboot_header_start:
        .long 0xE85250D6
        .long 0
        .long multiboot_header_end - multiboot_header_start
        .long -(0xE85250D6+0+(multiboot_header_end - multiboot_header_start))
        .align 8
        address_tag:
            .short    2
            .short    0
            .long    24
            .long    multiboot_header_start
            .long    text
            .long    bss
            .long    end
        .align 8
        entry_tag:
            .short    3
            .short    0
            .long    12
            .long    multiboot_entry
            .align 8

/*    framebuffer_tag:
            .short    5
            .short    0
            .long    20
            .long    640
            .long    480
            .long    32
        .align 8
*/       
        end_tag:
            .short    0
            .short    0
            .long    8
        .align 8
    multiboot_header_end:
   
    multiboot_entry:
        push ebx
        call KMain
        jmp $


Header multiboot harus berada di bagian paling awal dari file yang diload bootloader. Lokasinya juga harus dalam alignment 8 byte. Menurut spesifikasi, bootloader akan mencari header di beberapa byte pertama dari file. Jika ditemukan nilai indikator magic yang tepat, bootloader harus melanjutkan loading file tersebut. Selengkapnya mengenai konfigurasi Multiboot, kunjungi grup Programmer OS Indonesia, atau baca dokumentasi Multiboot v 2.

Saat multiboot_entry() terpanggil, ia akan memnggi fungsi KMain(), di fungsi tersebutlah kita memulai pekerjaan kita. Saat bootloader selesai, ia mengisi EBX dengan alamat multiboot tag. Kita dapat menemukan banyak informasi dari multiboot tag ini. Tapi, sekarang bukan saat yang tepat untuk mempelajarinya.

kmain.c
Untuk menghasilkan output, kita dapat menulis karakter di memori 0xB8000. Setiap 2 byte, dimulai dari alamat tersebut merepresentasikan sebuah karakter yang akan dicetak mulai dari pojok kiri atas. 1 byte pertama adalah karakter dan 1 byte lagi adalah atribut warna karakter. Saya juga sudah menulis penjelasan lebih lengkap di Programmer OS Indonesia.

//Biar tambah keren
static char *vidmem = 0xB8000;
void print(char *str){
    while(*str != 0){
        *vidmem = *str;
        vidmem++;
        *vidmem = 0x0F; //attribute
        vidmem++;
        str++;
    }
}

int KMain(void *arg)
{
    print("Hello world!");
}


Build
Untuk source code C, kompilasi dilakukan dengan perintah:
gcc -c -masm=intel -m32 -nostdinc -fnostack-protector -ffreestanding

-masm=intel digunakan agar kita dapat menggunakan syntax assembly intel saat menggunakan inline assembly di C.
-m32 untuk mnghasilkan kode instuksi 32-bit.
-nostdinc untuk melarang kompiler menginclude standard header otomatis.
-fnostack-protector agar compiler tidak melakukan optimisasi saat akses stack.
-ffreestanding untuk memastikan agar compiler tidak menginput kode tambahan lain, terutama kode yang berkaitan dengan host OS.

Untuk kode assembly:
as --32 -msyntax=intel

Maksudnya, argumen tersebut mengatakan bahwa kita ingin mengompile source yang ditulis dalam syntax intel ke dalam objek yang berformat instruksi 32-bit.

Untuk building file object:
gcc -nostdlib -T ldscript.txt

-nostdlib mencegah linker memadukan program dengan library system operasi host. Jangan lupa, kita haru membuat output agar seuai linker script dengan -T.

Run
Build seluruh source code, taruh hasilnya pada virtual disk sebagai /System/hello.
Unmount virtual disk, lalu jalankan dengan qemu-system-i386 disk,img atau qemu-system-i386 /dev/loop0.

http://www.facebook.com/groups/programmer.os.indonesia

Read more

Jumat, 23 Desember 2016

Pengertian Interrupt, Exception, Trap, Fault, IRQ dan Abort

interrupt, traps, fault, exception

Interrupt adalah suatu mekanisme prosesor dimana saat hal tersebut terjadi, prosesor akan menunda proses eksekusi. Setiap interrupt akan memiliki kode instruksi handler yang harus disediakan oleh sistem operasi. Kode instruksi ini bekerja layaknya fungsi subrutin biasa. Ia akan dipanggil sesuai dengan jenis sumber interrupt yang telah dikonfigurasikan oleh sistem operasi.

Pada dasarnya, interrupt sama saja seperti peristiwa pemanggilan fungsi biasa, layaknya saat melompat ke suatu prosedur dari fungsi main().

int main(){
function_to_call()
}

Bedanya, interrupt terjadi secara tak terduga dan tidak dapat dikontrol oleh program. Meskipun demikian, sistem operasi masih dapat mengontrol laju kerja interrupt jika dikehendaki demikian.

Seluruh pekerjaan program pada dasarnya merupakan proses matematis yang diatur jalannya oleh instruksi. Hasil pekerjaan yang diproses oleh program tersimpan dalam register. Oleh karena itu, kita tidak boleh membiarkan isi dari register ini termodifikasi oleh pihak lain, salah satunya adalah interrupt. Interrupt menyebabkan register instruction pointer (IP) atau program counter (PC) berpindah ke lokasi dimana interrupt handler berada. Yang bertugas menyediakan fungsi handler untuk seluruh interrupt adalah sistem operasi.

Seperti program lain, untuk bekerja, interrupt handler tentu membutuhkan register. Kita ingat bahwa konten register ini adalah bagian kerja dari program yang terinterupsi sebelumnya. Apabila termodifikasi sedikit saja, dapat dipastikan hasil kerja program menjadi tidak valid lagi. Jadi, sebuah interrupt handler perlu menyimpan konten seluruh register sebelum melakukan sesuatu, misalnya ke dalam stack.

Sebuah prosedur yang ditulis dengan bahasa pemrograman manapun, memiliki pola kerja yang sama. Jika direpresentasikan dalam bahasa assembly, semua prosedur dipanggil dengan cara yang sama, yaitu dengan instruksi CALL. Saat instruksi ini terjadi, sebenarnya prosesor menaruh nilai alamat Instruction Pointer(IP) ke stack dan melakukan jump(JMP) ke lokasi fungsi. Anda akan tahu tujuannya setelah membaca penjelasan selanjutnya.

Setiap prosedur, bagaimanapun bentuknya juga akan memiliki akhiran instruksi yang sama, yaitu RET. Instruksi RET berguna mengembalikan nilai IP yang baru saja ditaruh oleh pemanggil fungsi melalui instruksi CALL. Dengan cara seperti inilah prosesor bisa tahu dimana ia harus kembali setelah eksekusi sebuah fungsi telah selesai.

C:
MyProc(){
...
return;
}
Caller(){
MyProc();
}

ASM:
MyProc:
...
ret



Caller:
call MyProc

Bagaimana dengan interrupt? Mekanismenya masih sama, kok. Tapi, konten yang berada di dalam stack sedikit lebih banyak. Saat interrupt terjadi, prosesor melompat ke interrupt handler, sambil menaruh 3 buah data konten register yang berbeda ke dalam stack:
EFLAGS
CS
EIP

Lalu, bentuk fungsi handler interrupt tidak lagi menggunakan instruksi RET, ya. Untuk menyelesaikan eksekusi, handler menggunakan instruksi IRET. Instruksi ini akan mengembalikan konten ketiga register di atas ke posisi semula, bersamaan dengan kembali ke lokasi dimana program mulai terinterupsi.
Umumnya, interrupt handler akan menaruh konten general purpose register sebelum mulai bekerja dan mengembalikannya saat telah selesai. Dengan demikian, state kondisi kerja program yang terinterupsi tetap valid.

MyInterruptHandler:
pusha
...
popa
iret


Macam Interrupt
Ada beberapa kelompok besar interrupt yang biasa dikenal. Setiap jenisnya memiliki tingkah laku dan sumber pemicu yang berbeda.

1. Exception, yaitu interrupt yang dihasilkan oleh prosesor ketika terjadi kesalahan pada prosesor, karena eksekusi instruksi yang tidak dibenarkan kegunaannya, atau juga bisa karena prosesor menjalankan instruksi yang memang disediakan untuk menghasilkan exception secara disengaja. Exception itu sendiri dapat dibagi menjadi 3 macam:

  • Trap: Interupsi yang disengaja dengan menjalankan instruksi trap. Biasanya kondisi ini dimanfaatkan oleh sistem operasi untuk tujuan debugging.
  • Fault: Dipicu oleh kesalahan operasi yang dilakukan oleh prosesor. Seringkali interrupt dalam golongan ini muncul akibat eksekusi instruksi yang tidak valid. Dalam kondisi fault, sistem operasi biasanya masih dapat melakukan perbaikan dan melanjutkan eksekusi instruksi selanjutnya. Jika tidak memungkinkan, program yang menimbulkan fault harus diakhiri segera.
  • Abort: Timbul akibat kesalahan fatal prosesor yang sudah tidak dapat ditangani. Bisa disebabkan karena kerusakan, atau karena beberapa kesalahan fault yang seharusnya tidak dibiarkan.


2. Interrupt Request(IRQ), seringkali disebut sebagai hardware interrupt. Munculnya dipicu oleh peripheral device yang terhubung dengan jalur interupsi prosesor. Biasanya IRQ muncul saat hardware membutuhkan penanganan dari prosesor. Misalnya, ketika mouse digerakkan, ia akan mengirimkan interupsi untuk memberitahukan bahwa ada event yang sedang terjadi pada mouse. Dalam handler IRQ, terdapat deretan instruksi untuk melakukan transaksi data dengan hardware penghasil interrupt, melalui port. Setiap hardware yang dapat meghasilkan interupsi akan memiliki jalur interrupt yang berbeda dengan tujuan interupsi beragam. Jika ingin mengetahuinya secara detail, kita perlu membaca dokumen spesifikasi yang terkait dengan hardware tersebut.

3. Software Interrupt, yaitu interrupt yang dihasilkan oleh software. Biasanya digunakan untuk tujuan komunikasi antara user space program dan kernel. Di Intel, software interrupt dapat dihasilkan dengan instruksi INT x, dimana x adalah nomor interrupt handler yang akan dipanggil.
Read more

Perbedaan Port-Mapped I/O dan Memory-Mapped I/O

cpu board

Komunikasi data antara prosesor dan peripheral device dapat dilakukan dengan 2 cara, yaitu MMIO dan PMIO. Intel adalah salah satu proseesor yang lebih banyak menggunakan metode PMIO. Sedangkan MIPS dan ARM hanya mendukung satu macam metode transaksi data, yaitu menggunakan metode MMIO saja.

Dalam MMIO, jalur komunikasi bus terhubung bersama dengan jalur komunikasi bus untuk transaksi data dengan memori RAM. Sehingga, untuk dapat bekerja dengan adil, tidak boleh ada device yang memiliki alamat yang serupa dengan salah satu alamat yang diduduki oleh RAM. Untuk mengakses data dari device, prosesor tidak menyediakan satupun instruksi khusus. Ini karena, baik RAM ataupun device akan memiliki address space yang sama. Dengan kata lain, device bisa diakses seperti mengakses memori biasa.

Metode PMIO masih menggunakan sistem komunikasi bus yang sama, seperti MMIO, hanya saja prosesor yang menerapkan PMIO wajib menyediakan jalur bus tambahan yang terpisah dengan jalur bus untuk transaksi data dengan RAM. Kalau dilihat, Intel memiliki jumlah pin lebih banyak dari MIPS, ini karena ia butuh sambungan untuk melakukan transaksi PMIO.

Ekspansi jalur bus ini ditujukan khusus untuk transaksi data dengan peripheral device. Untuk itu, prosesor yang menerapkan PMIO perlu menyediakan instruksi khusus untuk melakukan transaksi data dengan device. Misalnya Intel. Ia menyediakan instruksi IN untuk mengambil data dari device dan OUT untuk mengirim data ke device.
memory mapped io vs port mapped io

Kiri: MMIO, Kanan : PMIO
Read more

Bagaimana Cara Prosesor dan Hardware Berkomunikasi?

Prosesor adalah pusat dari aktivitas komputer, dimana semua data diproses sedemikian rupa. Data yang perlu diproses oleh prosesor berasal dari salah satu peripheral device yang berperan sebagai input, misalnya keyboard, mouse dan camera. Hasil dari proses kemudian diteruskan ke salah satu peripheral deice yang berperan sebagai output. Ada banyak peripheral device yang terhubung oleh komputer, alur berjalannya data diatur oleh komputer namun, alamat tujuan/sumber device tetap diatur oleh program.

Karena ada banyak device yang terhubung dengan satu buah prosesor, diperlukan sebuah metode untuk mengatur ke alamat device manakah data harus di transfer. Oleh karena itu, komunikai data yang terjadi pada komputer secara abstrak dilakukan melalui system bus. System bus terdiri atas 3 macam sirkuit:
1. Address bus
2. Data bus
3. Control bus
system bus

Saat terjadi transaksi data dari komputer, prosesor mengirimkan data tersebut melalui data bus. Alamat tujuan data tersebut ditentukan oleh address bus. Dan, control bus akan menunjukkan sinyal dari prosesor bahwa ia perlu mengirim data. Saat ketiga jenis data ini terkirim, setiap device akan memeriksa apakah alamat yang dimaksud oleh prosesor tersebut adalah alamat yang tergolong dalam wilayah areanya atau bukan. Jika ia, maka ia akan mengambil data dari data bus dan menyimpannya pada memori internal yang sudah ditugaskan untuk menyimpan data pada alamatnya masing-massing.

Sementara itu, pembacaan data dari device tidak jauh berbeda. Transaksi dimulai dengan mengirim alamat sumber dan sinyal control bus untuk memulai tranaksi pembacaan data. Setelah alamat diketahui oleh salah satu device yang sesuai, ia akan mengirim data yang diminta ke data bus.

Ilustrasinya bisa dilihat pada gambar berikut.
Address bus ditujukkan oleh pin berlabel Addr x, Data bus terlihat berlabel Data x. Sedangkan Control bus terdiri atas IOR(I/O Read), IOW(I/O Write), MEMR dan MEMW. Contoh ini adalah contoh bus 8-bit, komputer sekarang kebanyakan memiliki lebar bus 32 bit atau 64-bit, jadi jelas lebih banyak dari ini.

Read more

Kamis, 22 Desember 2016

Episode Membuat Sistem Operasi: Membuat dan Menyiapkan Virtual Disk


Daripada menggunakan disk asli, membuat OS jauh lebih aman dilakukan dengan disk virtual(virtual disk). Virtual disk biasanya dibuat dalam bentuk file. Isi dari file tersebut akan dijadiakn representasi dari seluruh konten disk. Berikut alternatif cara yang bisa anda lakukan untuk membuat dan meyiapkan virtual disk untuk keperluan pengembanagn sistem operasi.

Dengan OSFMount
Lewat menu File dan carilah sendiri. Cukup mudah, kok, untuk dipelajari sendiri.

Dengan bximage (Bochs) (Recommended for Windows User)
Buka program bximage.exe di Windows, lalu ikuti langkahnya.

Dengan dd (Recommended for Linux User)
Membuat disk.img berukuran 512 x 1000 byte. Ukuran lainnya, tinggal ubah parameter count.
dd if=/dev/zero of=/home/irvan/disk.img bs=512 count=1000

Tersedia juga dd untuk Windows yang bisa anda download sendiri dari Google.

Real disk?
Khusus linuxer, anda bisa menggunakan disk device anda langsung jika menggunakan QEMU. Misal flashdisk saya adalah /dev/sdc.
qemu-system-i386 /dev/sdc

Dengan /dev/ram0
Linuxer bisa menggunakan ramdisk device: /dev/ram0, /dev/ram1, /dev/ram2, …
Tiap device berukuraan 60 MB.


Format, Mount dan akses virtual disk
OSFMount (Recommended for Windows User)
Cukup mudah untuk dipelajari sendiri
Anda bisa format dari Explorer setelah virtual disk dipasang.

ImDisk
Cukup mudah untuk dipelajari sendiri
Anda bisa format dari Explorer setelah virtual disk dipasang.

Loopback device (linux) (Recommended for Linux User)
Setup loopback device dengan command:
losetup /dev/loop0 disk.img

Lalu format ke filesystem FAT:
mkdosfs /dev/loop0

Virtual disk akan muncul dan bisa di akses seperti disk biasa. Lakukan mount seperti mounting disk biasa, bahkan bisa juga langsung dari file manager; nautilus/konqueror.

Jika sudah tidak digunakan, lepas virtual disk:
losetup -d /dev/loop0

Hint: Ada lebih dari sattu loop device; /dev/loop0 - /dev/loop7

mount command (linux)
format ke filesystem FAT dulu:
mkdosfs disk.img

Format command : mount <device> <mount point>
misal: mount disk.img /lokasi/mount

Hint: Gunakan mkfs untuk pilihan filesystem lain

OK, sekarang virtual disk siap digunakan. Anda bisa menaruh semua file komponen sistem operasi anda di dalamnya. Meski demikian, file virtual disk belum bisa dijalankan sebelum menginstall bootloader. Jadi, tunggu tulisan berikutnya mengenai instalasi bootloader, ya.
See you later...
Read more

Ubuntu Software Center Tertutup Sendiri (Closed Unexpectedly), Ini Solusinya

Meskipun menginstall software baru dapat dilakukan secara manual melalui terminal, dengan apt. Rasanya tetap nyaman menggunakan software center. Selain karena tampilannya berbasis GUI dan praktis digunakan, melalui ini kita bisa melihat menu software secara lebih detail. Apa jadinya kalau software center tiba--tiba mengalami masalah?

ubuntu software center

Inilah yang baru saja saya alami. Ubuntu software center dapat dibuka normal, sih. Selang beberapa waktu, saya sepertinya harus menunggu data software yang masih keadaan diload. Tiba-tiba, cling. Seperti sihir, ia menghilang begitu saja. Berkali-kali saya coba buka kembali menghasilkan kondisi serupa. Sayapun mencoba eksekusi apt-get update, sambil berharap agar software center kembali seperti sedia kala. Ya, akhirnya berhasil.

Hanya sehari ia bekerja normal. Keesokannya, saya menemui masalah kemarin hari, seperti kisah lama yang terulang kembali. Sayapun tak berkutik, karena tak tahu sebab dan asal muasalnya. Muncul sebuah ide untuk menjalankan software center dari terminal. Sebelum menghilang tiba-tiba, di terminal saya menemukan pesan log aneh.

(ubuntu-software:2114): GLib-ERROR **: Creating pipes for GWakeup: Too many open files

Yang benar saja? Too many open files?
Jika memang terlalu banyak open files, mana mungkin saya bisa menjalankan program lain dengan normal. Ah sudahlah. Penyebabnya sudah diketahui, jadi saya bisa bertanya ke Google soal ini.

Dan, strike. Inilah jawabannya (https://ubuntuforums.org/showthread.php?t=2343602)

sudo apt-get install ubuntu-software -f

Alhamdulillah, masalah tersebut fixed. Entah apa gunanya argumen "-f" pada perintah tersebut. Yang jelas, saya berterima kasih pada Google dan Ubuntu Foums. :)
Read more

Rabu, 21 Desember 2016

Analisa Naik Turun Trafik Website Niche Pendidikan

naik turun suka duka blog niche pendidikan

Beberapa hari ini saya sering mengamati fenomena aneh dalam tampilan trafik jumlah visitor. Ternyata, naik-turunnya trafik selalu memiliki pola yang cenderung tetap. Jika kalian berencana membuat situs share niche yang menganut tema pendidikan, mungkin hasil analisa saya kali ini dapat membantu.

Hari Jumat, Trafik Cenderung Turun
Kemungkinan hal ini dipengaruhi oleh kondisi Indonesia yang sebagian besar penduduknya tergolong penganut agama islam. Aktivitas siang hari telah terganti oleh kegiatan shalat Jumat. Faktor lain juga karena sabtu dan minggu adalah hari libur bagi mahaiswa. Jumat adalah hari terakhir yang banyak dijadikan alasan untuk bermalas-malasan.

trafik turun jumat

Hari Minggu, Trafik Cenderung Naik dari 2 Hari Sebelumnya
Ini karena banyak pelajar mulai sibuk menyiapkan tugas PR mereka. Hari minggu adalah hari dimana ketegangan mulai kembali. Juga hari dimana semangat belajar tumbuh kembali.

trafik naik minggu

Meski kedua poin di atas cenderung berubah-ubah, sebagian besar trafik menunjukkan bahwa kedua pernyataan tersebut benar. Ada banyak faktor tidak bisa diduga yang dapat mengakibatkan perbedaan antara pola umum dengan kenyataan.

Juni-Agustus, Masa Terpuruknya Trafik
Hari libur panjang, tidak banyak orang yang memikirkan tugas. Semakin lama masa libur berlangsung, trafik akan semakin terpuruk. Demikianlah yang terjadi pada bulan-bulan tersebut. Tapi, utungnya ada beberapa pelajar rajin yang browsing untuk keperluan diluar sekolah, ya. :)

trafik terpuruk juni juli agustus

Demikianlah simpulan analisa trafik yang telah saya teliti. Mudah-mudahan bermanfaat dan bisa dijadikan pertimbangan untuk memikirkan strategi jitu mengupayakan jumlah pengunjung tetap mendekati konstan, khusunya di waktu terpuruk mulai datang.
Read more

Contoh Doubly-Linked List Dengan C Beserta Penjelasannya

doubly linked list illustration

Deretan data dapat disimpan dalam bentuk array. Hal ini mustahil dilakukan jika data tersebar acak (noncontiguous) dalam memori. Array dapat menyimpan data berderet dalam ukuran dan jumlah yang tetap. Jika ingin menyimpan data dalam jumlah yang bervariasi, sebuah array harus disiapkan dengan menyediakn ruang kosong untuk menampung hingga beberapa jumlah elemen.

Apabila jumlah elemen yang akan disimpan dalam deretan tersebut tidak bisa diramalkan, tentu ini akan menjadi masalah. Misalnya array kosong yang disediakan sebanyak 10, namun ternyata sistem harus menyimpan 20 elemen. Saat ini terjadi, sistem bisa mengalokasikan deretan array kosong lagi. Kebalikannya, jika array kosong ada 10, namun sistem hanya perlu menambahkan 2 elemen, ini tak akan menjadi masalah besar. Namun, bagaimanapun manajemen memori harus dilakukan sebaik-baiknya.

Daripada menyimpan elemen dalam linked list, sistem lebih baik mengalokasikan memori cukup sebesar ukuran elemen yang perlu disimpan. Lokasi memori hasil alokasi tentu akan acak (noncontiguous), sehingga setiap elemen perlu dilengkapi dengan pointer untuk menunjukkan dimana alamat memori lokasi elemen sebelumnya dan sesuadahnya disimpan.

doubly linked list vs array


Setiap elemen/node dalam list akan selalu memiliki 2 pointer untuk menunjukkan lokasi elemen sebelum dan sesudahnya; belakang dan depannya; atau sebelah kiri dan kanannya. Oleh karena itu, setiap elemen akan diwakili oleh sebuah DLIST_NODE yang memiliki field pointer untuk menunjukkan lokasi elemen lainnya.

typedef struct _DLIST_NODE{
struct _DLIST_NODE *next;
struct _DLIST_NODE *prev;
int data;
} DLIST_NODE;

Untuk memudahkan pencarian, sebuah data struktur diperlukan sebagai parameter  pengelompok deretan elemen. Kita akan menyebutnya sebagai DLIST.

typedef struct _DLIST {
DLIST_NODE *first;
DLIST_NODE *last;
} DLIST;

Field first akan selalu menujuk pada elemen pertama dalam sebuah list, dan field last menunjuk pada elemen paling terakhir. Saat tidak ada satupun data tersimpan dalam list, kedua field ini harus bernilai 0. Ketika satu buah elemen pertama dimasukkan, kedua field ini akan menunjuk ke satu elemen yang sama, yaitu elemen baru itu sendiri –elemen pertama dan terakhir–.


Menambahkan data ke list
Elemen dapat dimasukkan dalam beberapa metode, antara lain adalah sebagai berikut.
- tambahkan di posisi paling awal (prepend)
- tambahkan di posisi paling akhir (append)
- sisipkan sebelum salah satu elemen (insert before)
- sisipkan sesudah salah satu elemen (insert after)

Prepend
Proses prepend harus diawali dengan memeriksa apakah ada elemen dalam kelompok DLIST. Apabila kita menemukan DLIST→first bernilai 0, elemen baru harus diperlakukan sebagai node pertama sekaligus terakhir. Sehingga first dan last pada DLIST akan menunjuk ke elemen baru. Lalu field prev dan next dari elemen baru harus diset 0 untuk menunjukkan bahwa tidak ada element lain.

elemen pertama = elemen terakhir = elemen baru
elemen baru→sebelumnya = 0
elemen baru→sesudahnya = 0

Namun, jika ditemukan satu atau lebih elemen dalam grup DLIST, yaitu ketika terindikasi DLIST→first ≠ 0; elemen baru harus dikaitkan dengan benar. Elemen pertama diubah menjadi elemen sesudahnya (elemen kedua), lalu elemen baru diubah peranannya sebagai elemen pertama dalam grup DLIST.

elemen baru→sebelumnya = 0
elemen baru→sesudahnya = elemen pertama
elemen pertama→sebelumnya = elemen baru
elemen pertama = elemen baru

HINT : Gambarlah elemen-elemen yang mengalami perubahan dalam secarik kertas untuk memudahkan visualisasi.


Kode:
void DListPrepend(DLIST *list,DLIST_NODE *newNode){
if(!list->first){
list->first = list->last = newNode;
newNode->prev = newNode->next = 0;
}
else{
newNode->prev = 0;
newNode->next = list->first;
list->first->prev = newNode;
list->first = newNode;
}
}

Append
Tidak berbeda jauh dengan prepend, append juga harus memeriksa apakah grup DLIST sudah memiliki elemen. Hal ini dilakukan untuk menentukan apakah elemen baru harus diperlakukan sebagai elemen pertama dan terakhir. Jika bukan:

elemen baru→sesudahnya = 0
elemen baru→sebelumnya = elemen terakhir
elemen terakhir→sesudahnya = elemen baru
elemen terakhir = elemen baru

Kode:
void DListAppend(DLIST *list,DLIST_NODE *newNode){
if(!list->last){
list->last = newNode;
list->first = newNode;
newNode->prev = 0;
newNode->next = 0;
}
else {
newNode->next = 0;
newNode->prev = list->last;
list->last->next = newNode;
list->last = newNode;
}
}

Insert before
Sebelum menyisipkan elemen ke posisi sebelum elemen target, perlu dipastikan apakah elemen target itu ada. Jika tidak, mungkin lebih baik kita menempatkan elemen baru ke posisi awal (prepend).

Jika tidak, lakukan prosedur berikut.

elemen baru→sesudahnya = elemen target
Jika elemen target = elemen pertama:
elemen pertama = elemen baru
Jika bukan:
elemen baru→sebelumnya = elemen target→sebelumnya
elemen target→sebelumnya→sesudahnya = elemen baru
elemen target→sebelumnya = elemen baru

Kode:
void DListInsertBefore(DLIST *list,DLIST_NODE *node,DLIST_NODE *newNode){
if(!node) //nothing? prepend!
{
if(!list->first){
list->first = newNode;
list->last = newNode;
newNode->prev = 0;
newNode->next = 0;
}
else{
newNode->prev = 0;
newNode->next = list->first;
list->first->prev = newNode;
list->first = newNode;
}
return;
}
newNode->next = node;
if(!node->prev){
list->first = newNode;
}
else {
newNode->prev = node->prev;
node->prev->next = newNode;
node->prev = newNode;
}
}

Insert after
Tidak perlu dijelaskan detail. Prosedur ini murni kebalikan dari prosedur insert before. Jika anda sudah paham prosedur tersebut, tentu sangat mudah membaca kode implementasi di bawah ini.

Kode:
void DListInsertAfter(DLIST *list,DLIST_NODE *node,DLIST_NODE *newNode){
if(!node){ //nothing? append!
if(!list->last){
list->last = newNode;
list->first = newNode;
newNode->prev = 0;
newNode->next = 0;
}
else {
newNode->next = 0;
newNode->prev = list->last;
list->last->next = newNode;
list->last = newNode;
}
return;
}
newNode->prev = node;
if(!node->next){
list->last = newNode;
}
else {
newNode->next = node->next;
node->next->prev = newNode;
node->next = newNode;
}
}


Menghapus elemen dari list
Dalam kasus ini, elemen perlu diperiksa apakah ia berperan sebagai elemen pertama. Jika demikian, elemen pertama akan digantikan perannya oleh elemen sesudahnya. Apabila kondisi ini tidak ditemukan, field next dari “elemen sebelum elemen target” harus diarahkan ke “elemen sesudah elemen target”.

Kemudian, elemen target juga dipastikan peranannya sebagai elemen terakhir atau bukan. Jika elemen terakhir, peranan elemen terakhir dgantikan dengan elemen sebelum elemen target. Atau, jika tidak, field prev dari “elemen sesudah elemen target” harus diarahkan pada “elemen sebelum elemen target”.

Untuk menghindari human error saat penggunaan linked list; terakhir, elemen yang baru dilepas sebaiknya dihapus referensi prev dan next nya.

Jika elemen target = elemen pertama:
   elemen pertama = elemen target→sesudahnya
Bukan:
   elemen target→sebelumnya→sesudahnya = elemen target→sesudahnya

Jika elemen target = elemen terakhir:
   elemen terakhir = elemen target→sebelumnya
Bukan:
   elemen target→sesudahnya→sebelumnya = elemen target→sebelumnya

elemen target→sebelumnya = elemen target→sesudahnya = 0

Kode:
void DListUnlink(DLIST *list,DLIST_NODE *node){
if(!node->prev)
list->first = node->next;
else
node->prev->next = node->next;
if(!node->next){
list->last = node->prev;
}
else
node->next->prev = node->prev;
}


Contoh Penggunaan
Dari beberapa fungsi yang telah ditampilkan di atas, kita belum dapat melihat bagaimana keseluruhan fungsi tersebut dengan baik, sebelum mempraktekkannya sendiri. Oleh karena itu, berikut saya sertakan code snippet sederhana :

void DListDump(DLIST *list){
DLIST_NODE *node = list->first;
while(node){
printf("node at %x data: %i prev: %x next: %x\n",node,node->data,node->prev,node->next);
node = node->next;
}
}

DLIST dlist = {0,0};
int main(){
char action;
DLIST_NODE *node;
DLIST_NODE *node_addr;
int node_data;

first:
printf("[a]ppend [p]repend Insert a[f]ter Insert [b]efore [d]ump [r]emove [q]uit:");
scanf("\n%c",&action);
switch (action){
case 'd':
DListDump(&dlist);
break;
case 'a':
node = malloc(sizeof(DLIST_NODE));
printf("Node data:");
scanf("\n%i",&node_data);
node->data = node_data;
DListAppend(&dlist,node);
break;
case 'p':
node = malloc(sizeof(DLIST_NODE));
printf("Node data:");
scanf("\n%i",&node_data);
node->data = node_data;
DListPrepend(&dlist,node);
break;
case 'f':
node = malloc(sizeof(DLIST_NODE));
printf("Node addr (hex):");
scanf("\n%x",&node_addr);
printf("Node data:");
scanf("\n%i",&node_data);
node->data = node_data;
DListInsertAfter(&dlist,node_addr,node);
break;
case 'b':
node = malloc(sizeof(DLIST_NODE));
printf("Node addr (hex):");
scanf("\n%x",&node_addr);
printf("Node data:");
scanf("\n%i",&node_data);
node->data = node_data;
DListInsertBefore(&dlist,node_addr,node);
break;
case 'r':
node = malloc(sizeof(DLIST_NODE));
printf("Node addr (hex):");
scanf("\n%x",&node_addr);
DListUnlink(&dlist,node_addr);
free(node_addr);
break;
case 'q':
goto last;
break;
default:
printf("Invalid option\n");
goto first;
break;
}
goto first;

last:
return 0;
}


Bagaimana hasilnya?
Wow, cool...

linked list


Read more